在 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、技术帮助

使用 Agora SDK 开发 React Native 视频通话App的更多相关文章

  1. React Native发布APP之打包iOS应用

    用React Native开发好APP之后,如何将APP发布以供用户使用呢?一款APP的发布流程无外乎:签名打包—>发布到各store这两大步骤.本文将向大家分享如何签名打包一款React Na ...

  2. React Native & CodePush & App Center

    React Native & CodePush & App Center https://docs.microsoft.com/en-us/appcenter/distribution ...

  3. 关于开发React Native的注意事项

    今天在写一个简单的RN的Demo时,一连出现了好几个错误,最后幸亏得以解决,在这里把我踩过的坑以及解决办法分享出来: 1.运行出现错误:Could not connect to development ...

  4. React Native的APP打包教程

    1.改软件的名称 2.改软件的图标 3.给做好的项目打成APP包 改软件的名称 找到项目的改名的位置 然后用记事本打开strings.xml,然后改自己想要的名字 改软件的图标 找到如下5个文件,然后 ...

  5. React Native & Web APP

    React Native Build native mobile apps using JavaScript and React https://facebook.github.io/react-na ...

  6. 带你从零学ReactNative开发跨平台App开发[react native SqlLite 终极运用](十二)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  7. 带你从零学ReactNative开发跨平台App开发-[react native 仿boss直聘](十三)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  8. 前段开发 react native tab功能

    import React, { Component } from 'react'; import { StyleSheet, Text, View, Image, } from 'react-nati ...

  9. 打造开发React Native的Sublime

     之前一年多一直用Sublime Text做前端开发,最近做React开发,发现不太好用,就尝试其他编辑器.WebStorm和VS Code都用过,WebStorm基本不用装插件,可以直接用,但用习惯 ...

  10. react native改变app的图标和名称

    beauty\android\app\src\main\res

随机推荐

  1. vite 路径别名 @ 配置

    vite.config.ts resolve.alias 配置 const path = require('path'); import { defineConfig } from 'vite'; i ...

  2. zk中控考勤机默认密码登陆

    网络空间搜索: app="ZKTECO-考勤管理系统" 找到某一个考勤系统 进行弱口令登陆:admin/****** 成功! End!!!

  3. java 操作PDF (spire.pdf)api

    https://www.e-iceblue.cn/pdf_java_image_shapes/replace-image-with-new-image-in-pdf-in-java.html mave ...

  4. 搭建react项目

    1.打开新建的项目空文件夹,终端输入命令:npm init,文件夹生成package.json文件: 2.安装webpack.webpack-cli和cross-env:npm install web ...

  5. C# core 最简单的方式写入日志

    System.IO.StreamWriter sw = System.IO.File.AppendText( LogPath + LogFielPrefix + "Error-" ...

  6. 一招彻底解决——双系统下windows时间错误显示

    双系统下windows与ubuntu系统时间不同步 我的笔电是windows系统,工作需要安装了ubuntu,于是成为双系统,于是从18年我就遇到了装了ubuntu系统之后windows时间显示错误的 ...

  7. eclipse静态资源保存不重启(热部署静态资源/html)

    简单的来说就是windows->Prefrence->搜索 build automatically 并勾选就可以 不同的版本设置选项可能略微不同,其实比较简单但是新手可能不好找,所以帮到的 ...

  8. Linux让部署在服务器上的项目一直保持运行状态…&跑多个项目

    在idea通过package得到的.jar包或者.war包可通过 java -jar xxx.jar/xxx.war 命令直接在linux或者windows系统运行:   将打好包的项目放在linux ...

  9. 龙中华著《Spring Boot实战派》读书笔记之基础篇

    第四章 Spring Boot 基础 4.1 了解Spring Boot 项目结构 src/main/java //入口类,等 src/main/resources //静态文件和配置文件 src/t ...

  10. Ubuntu常用命令(二)

    clash 启动 #.clash -d . sudo /home/lizhenyun/clash/clash -d /home/lizhenyun/clash/ deb包安装 sudo dpkg -i ...