在 React Native 的應用中,從頭開始添加視頻通話功能是很複雜的。要保證低延遲、負載平衡,還要注意管理用戶事件狀態,很是繁瑣。除此以外,還必須保證跨平臺的兼容性。html
固然有個簡單的方法能夠作到這一點。在本次的教程中,咱們將使用 Agora Video SDK 來構建一個 React Native 視頻通話 App。在深刻探討程序工做以前,咱們將介紹應用的結構、設置和執行。你能夠在幾分鐘內,經過幾個簡單的步驟,讓一個跨平臺的視頻通話應用運行起來。react
咱們將使用 Agora RTC SDK for React Native 來作例子。在這篇文章中,我使用的版本是 v3.1.6。android
注意:本文沒有采用 Token 鑑權,建議在生產環境中運行的全部RTE App 都採用Token鑑權。有關Agora平臺中基於Token的身份驗證的更多信息,請在聲網文檔中心搜索關鍵詞「Token」,參考相關文檔。
這就是咱們正在構建的應用程序的結構:ios
. ├── android ├── components │ └── Permission.ts │ └── Style.ts ├── ios ├── App.tsx .
npm install
來安裝解壓目錄中的 App 依賴項。./App.tsx
,將咱們以前生成的 App ID 填入 appId: "<YourAppId>"
cd ios && pod install
npx react-native run-android
/ npx react-native run-ios
來啓動應用程序。等待幾分鐘來構建和啓動應用程序。經過以上操做,你應該能夠在兩個設備之間進行視頻聊天通話。該應用默認使用 channel-x 做爲頻道名稱。npm
這個文件包含了 React Native 視頻通話App中視頻通話的全部核心邏輯。segmentfault
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聲明。接下來,爲應用狀態定義一個接口,包含:react-native
... 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 能夠在純音頻模式下工做。)session
init函數還爲視頻調用中的各類事件添加了事件監聽器。例如,UserJoined
事件爲咱們提供了用戶加入頻道時的 UID。咱們將這個 UID 存儲在咱們的狀態中,以便在之後渲染他們的視頻時使用。app
注意:若是在咱們加入以前有用戶鏈接到頻道,那麼在他們加入頻道以後,每一個用戶都會被觸發一個
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
。
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上的操做系統申請攝像頭和麥克風的權限。
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 去查看能夠幫助你快速添加更多功能的方法,好比將攝像頭和麥克風靜音,設置視頻配置文件和音頻混合等等。