在 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>
组件,须要提供 channelId
和 renderMode
。连贯到同一 个 channelId
的用户能够互相通信,而 renderMode
用于将视频放入视图中或通过缩放来填充视图。
为了显示近程用户的视频源,咱们应用 SDK 中的 <RtcLocalView.SurfaceView>
组件,它能够获取近程用户的 UID
以及 channelId
和 renderMode
。
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 技术干货与技术流动,可拜访声网开发者社区。
- 欢送扫码关注咱们。