乐趣区

关于react-native:使用-Agora-SDK-开发-React-Native-视频通话App

在 React Native 的利用中,从头开始增加视频通话性能是很简单的。要保障低提早、负载平衡,还要留神治理用户事件状态,十分繁琐。除此之外,还必须保障跨平台的兼容性。

当然有个简略的办法能够做到这一点。在本次的教程中,咱们将应用 Agora Video SDK 来构建一个 React Native 视频通话 App。在深入探讨程序工作之前,咱们将介绍利用的构造、设置和执行。你能够在几分钟内,通过几个简略的步骤,让一个跨平台的视频通话利用运行起来。

咱们将应用 Agora RTC SDK for React Native 来做例子。在这篇文章中,我应用的版本是 v3.1.6。

创立一个 Agora 账户

  • 在声网官网注册并登录后盾。

  • 找到 “ 项目管理 “ 下的 “ 我的项目列表 “ 选项卡,点击蓝色的 “ 创立 “ 按钮,创立一个我的项目。(当提醒应用 App ID+ 证书时,抉择只应用 App ID。)记住你的 App ID,它将在开发 App 时用于受权你的申请。

留神:本文没有采纳 Token 鉴权,倡议在生产环境中运行的所有 RTE App 都采纳 Token 鉴权。无关 Agora 平台中基于 Token 的身份验证的更多信息,请在声网文档核心搜寻关键词「Token」,参考相干文档。

示例我的项目构造

这就是咱们正在构建的应用程序的构造:

.

├── android

├── components

│ └── Permission.ts

│ └── Style.ts

├── ios

├── App.tsx

.

让咱们来运行这个利用

  • 须要装置 LTS 版本的 Node.js 和 NPM。
  • 确保你有一个 Agora 账户,设置一个我的项目,并生成 App ID。
  • 从主分支下载并解压 ZIP 文件。
  • 运行 npm install 来装置解压目录中的 App 依赖项。
  • 导航到 ./App.tsx,将咱们之前生成的 App ID 填入 appId: "<YourAppId>"
  • 如果你是为 iOS 构建,关上终端,执行 cd ios && pod install
  • 连贯你的设施,并运行 npx react-native run-android / npx react-native run-ios 来启动应用程序。期待几分钟来构建和启动应用程序。
  • 一旦你看到手机(或模拟器)上的主屏幕,点击设备上的开始通话按钮。(iOS 模拟器不反对摄像头,所以要用实体设施代替)。

通过以上操作,你应该能够在两个设施之间进行视频聊天通话。该利用默认应用 channel-x 作为频道名称。

利用工作原理

App.tsx

这个文件蕴含了 React Native 视频通话 App 中视频通话的所有外围逻辑。

import React, {Component} from 'react'
import {Platform, ScrollView, Text, TouchableOpacity, View} from 'react-native'
import RtcEngine, {RtcLocalView, RtcRemoteView, VideoRenderMode} from 'react-native-agora'

import requestCameraAndAudioPermission from './components/Permission'
import styles from './components/Style'

/**
 * @property peerIds Array for storing connected peers
 * @property appId
 * @property channelName Channel Name for the current session
 * @property joinSucceed State variable for storing success
 */
interface State {
    appId: string,
    token: string,
    channelName: string,
    joinSucceed: boolean,
    peerIds: number[],}

...

咱们开始先写 import 申明。接下来,为利用状态定义一个接口,蕴含:

  • appId:Agora App ID
  • token:为退出频道而生成的 Token。
  • channelName:频道名称(同一频道的用户能够通话)。
  • joinSucceed:存储是否连贯胜利的布尔值。
  • peerIds:一个数组,用于存储通道中其余用户的 UID。
...

export default class App extends Component<Props, State> {
    _engine?: RtcEngine

    constructor(props) {super(props)
        this.state = {
            appId: YourAppId,
            token: YourToken,
            channelName: 'channel-x',
            joinSucceed: false,
            peerIds: [],}
        if (Platform.OS === 'android') {
            // Request required permissions from Android
            requestCameraAndAudioPermission().then(() => {console.log('requested!')
            })
        }
    }

    componentDidMount() {this.init()
    }

    /**
     * @name init
     * @description Function to initialize the Rtc Engine, attach event listeners and actions
     */
    init = async () => {const {appId} = this.state
        this._engine = await RtcEngine.create(appId)
        await this._engine.enableVideo()

        this._engine.addListener('Warning', (warn) => {console.log('Warning', warn)
        })

        this._engine.addListener('Error', (err) => {console.log('Error', err)
        })

        this._engine.addListener('UserJoined', (uid, elapsed) => {console.log('UserJoined', uid, elapsed)
            // Get current peer IDs
            const {peerIds} = this.state
            // If new user
            if (peerIds.indexOf(uid) === -1) {
                this.setState({
                    // Add peer ID to state array
                    peerIds: [...peerIds, uid]
                })
            }
        })

        this._engine.addListener('UserOffline', (uid, reason) => {console.log('UserOffline', uid, reason)
            const {peerIds} = this.state
            this.setState({
                // Remove peer ID from state array
                peerIds: peerIds.filter(id => id !== uid)
            })
        })

        // If Local user joins RTC channel
        this._engine.addListener('JoinChannelSuccess', (channel, uid, elapsed) => {console.log('JoinChannelSuccess', channel, uid, elapsed)
            // Set state variable to true
            this.setState({joinSucceed: true})
        })
    }

...

咱们定义了一个基于类的组件:变量 _engine 将存储从 Agora SDK 导入的 RtcEngine 类实例。这个实例提供了次要的办法,咱们的应用程序能够调用这些办法来应用 SDK 的性能。

在构造函数中,设置状态变量,并为 Android 上的摄像头和麦克风获取权限。(咱们应用了下文所述的 permission.ts 的帮忙函数 ) 当组件被挂载时,咱们调用 init 函数,应用 App ID 初始化 RTC 引擎。它还能够通过调用 engine 实例上的 enableVideo 办法来启用视频。(如果省略这一步,SDK 能够在纯音频模式下工作。)

init 函数还为视频调用中的各种事件增加了事件监听器。例如,UserJoined 事件为咱们提供了用户退出频道时的 UID。咱们将这个 UID 存储在咱们的状态中,以便在当前渲染他们的视频时应用。

留神:如果在咱们退出之前有用户连贯到频道,那么在他们退出频道之后,每个用户都会被触发一个 UserJoined 事件。

...
    /**
     * @name startCall
     * @description Function to start the call
     */
    startCall = async () => {
        // Join Channel using null token and channel name
        await this._engine?.joinChannel(this.state.token, this.state.channelName, null, 0)
    }

    /**
     * @name endCall
     * @description Function to end the call
     */
    endCall = async () => {await this._engine?.leaveChannel()
        this.setState({peerIds: [], joinSucceed: false})
    }

    render() {
        return (<View style={styles.max}>
                <View style={styles.max}>
                    <View style={styles.buttonHolder}>
                        <TouchableOpacity
                            onPress={this.startCall}
                            style={styles.button}>
                            <Text style={styles.buttonText}> Start Call </Text>
                        </TouchableOpacity>
                        <TouchableOpacity
                            onPress={this.endCall}
                            style={styles.button}>
                            <Text style={styles.buttonText}> End Call </Text>
                        </TouchableOpacity>
                    </View>
                    {this._renderVideos()}
                </View>
            </View>
        )
    }

    _renderVideos = () => {const {joinSucceed} = this.state
        return joinSucceed ? (<View style={styles.fullView}>
                <RtcLocalView.SurfaceView
                    style={styles.max}
                    channelId={this.state.channelName}
                    renderMode={VideoRenderMode.Hidden}/>
                {this._renderRemoteVideos()}
            </View>
        ) : null
    }

    _renderRemoteVideos = () => {const {peerIds} = this.state
        return (
            <ScrollView
                style={styles.remoteContainer}
                contentContainerStyle={{paddingHorizontal: 2.5}}
                horizontal={true}>
                {peerIds.map((value, index, array) => {
                    return (
                        <RtcRemoteView.SurfaceView
                            style={styles.remote}
                            uid={value}
                            channelId={this.state.channelName}
                            renderMode={VideoRenderMode.Hidden}
                            zOrderMediaOverlay={true}/>
                    )
                })}
            </ScrollView>
        )
    }
}

接下来,还有开始和完结视频聊天通话的办法。joinChannel 办法接管 Token、频道名、其余可选信息和一个可选的 UID(如果你将 UID 设置为 0,零碎会主动为本地用户调配 UID)。

咱们还定义了渲染办法,用于显示开始和完结通话的按钮,以及显示本地视频源和近程用户的视频源。咱们定义了 _renderVideos 办法 来渲染咱们的视频源,应用 peerIds 数组在滚动视图中渲染。

为了显示本地用户的视频源,咱们应用 <RtcLocalView.SurfaceView> 组件,须要提供 channelIdrenderMode。连贯到同一 个 channelId 的用户能够互相通信,而 renderMode 用于将视频放入视图中或通过缩放来填充视图。

为了显示近程用户的视频源,咱们应用 SDK 中的 <RtcLocalView.SurfaceView> 组件,它能够获取近程用户的 UID 以及 channelIdrenderMode

Permission.ts

import {PermissionsAndroid} from 'react-native'

/**
 * @name requestCameraAndAudioPermission
 * @description Function to request permission for Audio and Camera
 */
export default async function requestCameraAndAudioPermission() {
    try {
        const granted = await PermissionsAndroid.requestMultiple([
            PermissionsAndroid.PERMISSIONS.CAMERA,
            PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
        ])
        if (granted['android.permission.RECORD_AUDIO'] === PermissionsAndroid.RESULTS.GRANTED
            && granted['android.permission.CAMERA'] === PermissionsAndroid.RESULTS.GRANTED
        ) {console.log('You can use the cameras & mic')
        } else {console.log('Permission denied')
        }
    } catch (err) {console.warn(err)
    }
}

导出一个函数,向 Android 上的操作系统申请摄像头和麦克风的权限。

Style.ts

import {Dimensions, StyleSheet} from 'react-native'

const dimensions = {width: Dimensions.get('window').width,
    height: Dimensions.get('window').height,
}

export default StyleSheet.create({
    max: {flex: 1,},
    buttonHolder: {
        height: 100,
        alignItems: 'center',
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'space-evenly',
    },
    button: {
        paddingHorizontal: 20,
        paddingVertical: 10,
        backgroundColor: '#0093E9',
        borderRadius: 25,
    },
    buttonText: {color: '#fff',},
    fullView: {
        width: dimensions.width,
        height: dimensions.height - 100,
    },
    remoteContainer: {
        width: '100%',
        height: 150,
        position: 'absolute',
        top: 5
    },
    remote: {
        width: 150,
        height: 150,
        marginHorizontal: 2.5
    },
    noUserText: {
        paddingHorizontal: 10,
        paddingVertical: 5,
        color: '#0093E9',
    },
})

Style.ts 文件蕴含了组件的 款式。

这就是疾速开发一个 React Native 视频聊天通话 App 的办法。你能够参考 Agora React Native API Reference 去查看能够帮忙你疾速增加更多功能的办法,比方将摄像头和麦克风静音,设置视频配置文件和音频混合等等。

获取更多文档、Demo、技术帮忙

  • 获取 SDK 开发文档,可拜访声网文档核心。
  • 如需参考各类场景 Demo,可拜访下载核心获取。
  • 如遇开发疑难,可拜访论坛发帖发问。
  • 理解更多教程、RTE 技术干货与技术流动,可拜访声网开发者社区。
  • 欢送扫码关注咱们。

退出移动版