Computer >> 컴퓨터 >  >> 스마트폰 >> iPhone

React Native 앱에 화상 통화를 추가하는 방법

영상 통화는 COVID-19 전염병 동안 필수적인 일상 활동이 되었습니다. 채팅 앱, 음성 통화 및 영상 통화와 같은 기능을 사용하여 친구 및 가족과 계속 연락할 수 있었습니다.

이제 영상 통화를 할 수 있는 자체 React Native 앱을 만들어 보겠습니다.

이 튜토리얼에서는 Twilio 프로그래밍 가능한 화상 통화 API를 사용하여 React Native 앱에서 화상 통화 기능을 구현하는 방법을 배울 것입니다.

프로세스는 매우 간단합니다. 간단히 화상 회의실을 만들고 다른 사람들을 해당 회의실에 초대합니다. 이렇게 하려면 카메라와 마이크에 액세스할 수 있어야 합니다. 따라서 테스트 목적으로 실제 스마트폰 장치를 사용해야 합니다.

Twilio API에 액세스하는 데 사용할 기본 패키지는 react-native-twilio-video-webrtc 패키지입니다.

요구사항

  • Twilio 계정
  • 테스트용 iOS 또는 Android 기기 최소 2대
  • React 네이티브 환경 설정.

시작하겠습니다!

Twilio API 키를 얻는 방법

Twilio API 키를 얻으려면 Twilio 계정이 필요합니다. 이를 위해 이 URL을 방문하십시오. 계정을 설정한 후 아래 스크린샷이 지시하는 위치로 이동해야 합니다.

React Native 앱에 화상 통화를 추가하는 방법

액세스 토큰 가져오기를 처리하도록 서버를 설정하는 방법

액세스 토큰을 가져오려면 새 노드 서버 프로젝트를 만들어야 합니다. 이를 위해 다음 명령을 실행하여 필요한 패키지를 설치해야 합니다.

yarn add dotenv express ngrok nodemon twilio

다음으로, 아래 코드 스니펫과 같이 환경 변수 파일(.env)에 Twilio 자격 증명을 추가해야 합니다.

PORT=3000
ACCOUNT_SID=AC5ceb0847c50c91b143ce07
API_KEY_SID=SKa173c10de99a26fd86969b
API_KEY_SECRET=Czv7IjNIZJis8s7jb5FePi

이제 API 엔드포인트를 생성해야 합니다. 먼저 아래 코드 스니펫에 설명된 대로 액세스 토큰을 얻기 위해 필요한 패키지를 가져오고 개체 인스턴스를 만들어야 합니다.

import 'dotenv/config';
import express from 'express';

import twilio from 'twilio';
import ngrok from 'ngrok';
const AccessToken = twilio.jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;

const app = express();

여기에서는 액세스 토큰을 가져오기 위해 API 엔드포인트를 만들 것입니다. Express 인스턴스에서 제공하는 get 메서드를 사용하여 액세스 토큰으로 응답하는 끝점 함수를 만들어야 합니다.

함수 내에서 Twillio 자격 증명을 사용하여 새 인스턴스를 생성해야 합니다. 그런 다음 모바일 장치의 등록 화면에서 받은 사용자 이름을 ID 속성으로 추가해야 합니다.

마지막으로 사용자가 동영상을 사용할 수 있도록 액세스 권한을 부여한 다음 JWT 토큰을 다시 기기에 반환합니다. 아래 스니펫에서 이 모든 작업을 수행하는 코드는 다음과 같습니다.

app.get('/getToken', (req, res) => {
  if (!req.query || !req.query.userName) {
    return res.status(400).send('Username parameter is required');
  }
  const accessToken = new AccessToken(
    process.env.ACCOUNT_SID,
    process.env.API_KEY_SID,
    process.env.API_KEY_SECRET,
  );

  // Set the Identity of this token
  accessToken.identity = req.query.userName;

  // Grant access to Video
  var grant = new VideoGrant();
  accessToken.addGrant(grant);

  // Serialize the token as a JWT
  var jwt = accessToken.toJwt();
  return res.send(jwt);
});

또한 동쪽 액세스를 위해 생성한 엔드포인트 API를 인터넷에 노출합니다. 이를 위해 다음 코드 스니펫의 코드를 사용할 수 있습니다.

app.listen(process.env.PORT, () =>
  console.log(`Server listening on port ${process.env.PORT}!`),
);

ngrok.connect(process.env.PORT).then((url) => {
  console.log(`Server forwarded to public url ${url}`);
});

마지막으로 아래 스크린샷과 같이 서버를 실행해야 합니다.

React Native 앱에 화상 통화를 추가하는 방법

여기에서 액세스 토큰을 반환하는 API 엔드포인트를 성공적으로 생성했습니다.

리액트 네이티브 프로젝트를 구성하는 방법

React Native 프로젝트에서 패키지를 수동으로 설정하고 Android 및 iOS 플랫폼 모두에서 카메라와 마이크에 액세스할 수 있는 권한을 구성해야 합니다.

하지만 먼저 react-navigation 필요한 패키지를 설치해야 합니다. 및 react-native-twilio-video-webrtc , 프로젝트 터미널에서 다음 명령을 실행하여:

yarn add @react-navigation/native @react-navigation/stack react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view react-native-dotenv react-native-permissions <https://github.com/blackuy/react-native-twilio-video-webrtc>

iOS용 설정

iOS의 경우 패키지를 수동으로 설정해야 합니다. 먼저 Podfile에서 IOS 타겟을 11로 증가해야 합니다. . 이것은 Twilio의 네이티브 비디오 SDK가 iOS 11.0 이상만 지원하기 때문에 필요합니다.

platform :ios, '11.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

Podfile에서 아래 코드 스니펫의 지시에 따라 권한 요청을 설정해야 합니다.

permissions_path = '../node_modules/react-native-permissions/ios'
  pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec"
  pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone.podspec"

그런 다음 info.plist를 열고 아래 코드 스니펫의 지시에 따라 카메라 및 마이크 액세스 권한을 요청하는 코드를 추가해야 합니다.

  <key>UIViewControllerBasedStatusBarAppearance</key>
	<false/>
  <key>NSCameraUsageDescription</key>
  <string>We require your permission to access the camera while in a video call</string>
  <key>NSMicrophoneUsageDescription</key>
  <string>We require your permission to access the microphone while in a video call</string>

이제 iOS 설정이 완료되었습니다.

Android용 설정

무엇보다도 ./android/settings.gradle에 다음 코드 줄을 추가해야 합니다. 파일:

project(':react-native-twilio-video-webrtc').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-twilio-video-webrtc/android')

또한 ./android/app/build.gradle에 패키지 구현 코드를 추가해야 합니다. 파일:

implementation project(':react-native-twilio-video-webrtc')

마지막으로 이것을 MainApplication.java로 가져와야 합니다. 파일도:

import com.twiliorn.library.TwilioPackage;

그런 다음 다음 코드를 사용하여 패키지를 활성화해야 합니다.

@Override
protected List getPackages() {
  @SuppressWarnings("UnnecessaryLocalVariable")
  List packages = new PackageList(this).getPackages();
  //  add the following code
  packages.add(new TwilioPackage());
  return packages;
}

방 등록 화면을 만드는 방법

여기에서는 React Native 앱을 호출하는 비디오에서 방에 등록할 수 있는 "방 등록"이라는 화면을 만들 것입니다.

먼저 아래 코드 스니펫과 같이 필요한 패키지를 가져와야 합니다.

import React, {useState, useRef, useEffect, useContext} from 'react';
import {
  StyleSheet,
  View,
  Text,
  StatusBar,
  TouchableOpacity,
  TextInput,
  Alert,
  KeyboardAvoidingView,
  Platform,
  ScrollView,
  Dimensions,
} from 'react-native';

import {
  TwilioVideoLocalView,
  TwilioVideoParticipantView,
  TwilioVideo,
} from 'react-native-twilio-video-webrtc';

import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
  • react-navigation:등록 화면 및 화상 통화 화면의 탐색을 처리합니다.
  • react-native:이 패키지를 사용하면 카메라와 마이크에 대한 액세스 권한을 처리할 수 있습니다.
  • react-native-twilio-video-webrtc:Twilio의 화상 통화 프로그래밍 가능 API에 액세스할 수 있습니다.

인스턴스 및 변수를 초기화하는 방법

먼저 반응 탐색을 위한 인스턴스를 생성할 것입니다. 그런 다음 아래 코드 스니펫과 같이 상태를 분산하기 위해 상태와 컨텍스트 변수를 초기화합니다.

const Stack = createStackNavigator();
const initialState = {
  isAudioEnabled: true,
  status: 'disconnected',
  participants: new Map(),
  videoTracks: new Map(),
  userName: '',
  roomName: '',
  token: '',
};

const AppContext = React.createContext(initialState);

const dimensions = Dimensions.get('window');

부트스트랩 탐색

App.js에서 파일에서 탐색 컨테이너 스택을 만들 것입니다. Stack 사용 아래 코드 스니펫에 지시된 대로 컨텍스트를 사용하여 모든 화면에 상태를 배포할 구성 요소입니다.

export default () => {
  const [props, setProps] = useState(initialState);

  return (
    <>
      <StatusBar barStyle="dark-content" />
      <AppContext.Provider value={{props, setProps}}>
        <NavigationContainer>
          <Stack.Navigator>
            <Stack.Screen name="Home" component={HomeScreen} />
            <Stack.Screen name="Video Call" component={VideoCallScreen} />
          </Stack.Navigator>
        </NavigationContainer>
      </AppContext.Provider>
    </>
  );
};

등록 화면을 만드는 방법

등록 화면에는 사용자 자격 증명을 가져오고 사용자가 화상 통화방에 참여할 수 있도록 하는 모달 대화 상자가 있습니다.

먼저 컨텍스트에서 register.js로 소품을 가져와야 합니다. 아래 코드 스니펫에 표시된 대로 파일:

import React, {useState, useRef, useEffect, useContext} from 'react';
import {
  checkMultiple,
  request,
  requestMultiple,
  PERMISSIONS,
  RESULTS,
} from 'react-native-permissions';

const RegisterScreen = ({navigation}) => {
  const {props, setProps} = useContext(AppContext);

다음으로 카메라 및 마이크 권한을 처리하는 함수를 만들어야 합니다. 함수에 대한 코드는 아래 코드 스니펫에 제공됩니다.

const _checkPermissions = (callback) => {
    const iosPermissions = [PERMISSIONS.IOS.CAMERA, PERMISSIONS.IOS.MICROPHONE];
    const androidPermissions = [
      PERMISSIONS.ANDROID.CAMERA,
      PERMISSIONS.ANDROID.RECORD_AUDIO,
    ];
    checkMultiple(
      Platform.OS === 'ios' ? iosPermissions : androidPermissions,
    ).then((statuses) => {
      const [CAMERA, AUDIO] =
        Platform.OS === 'ios' ? iosPermissions : androidPermissions;
      if (
        statuses[CAMERA] === RESULTS.UNAVAILABLE ||
        statuses[AUDIO] === RESULTS.UNAVAILABLE
      ) {
        Alert.alert(
          'Error',
          'Hardware to support video calls is not available',
        );
      } else if (
        statuses[CAMERA] === RESULTS.BLOCKED ||
        statuses[AUDIO] === RESULTS.BLOCKED
      ) {
        Alert.alert(
          'Error',
          'Permission to access hardware was blocked, please grant manually',
        );
      } else {
        if (
          statuses[CAMERA] === RESULTS.DENIED &&
          statuses[AUDIO] === RESULTS.DENIED
        ) {
          requestMultiple(
            Platform.OS === 'ios' ? iosPermissions : androidPermissions,
          ).then((newStatuses) => {
            if (
              newStatuses[CAMERA] === RESULTS.GRANTED &&
              newStatuses[AUDIO] === RESULTS.GRANTED
            ) {
              callback && callback();
            } else {
              Alert.alert('Error', 'One of the permissions was not granted');
            }
          });
        } else if (
          statuses[CAMERA] === RESULTS.DENIED ||
          statuses[AUDIO] === RESULTS.DENIED
        ) {
          request(statuses[CAMERA] === RESULTS.DENIED ? CAMERA : AUDIO).then(
            (result) => {
              if (result === RESULTS.GRANTED) {
                callback && callback();
              } else {
                Alert.alert('Error', 'Permission not granted');
              }
            },
          );
        } else if (
          statuses[CAMERA] === RESULTS.GRANTED ||
          statuses[AUDIO] === RESULTS.GRANTED
        ) {
          callback && callback();
        }
      }
    });
  };

그런 다음 앱이 시작될 때마다 이 권한 확인 기능을 호출해야 합니다. 이를 위해 useEffect 내부에서 함수를 호출해야 합니다. 아래 코드 스니펫의 지시에 따라 후크:

useEffect(() => {
    _checkPermissions();
  }, []);

마지막으로 방 이름과 사용자 이름을 허용하는 두 개의 입력이 있는 간단한 양식을 만들어야 합니다. 그런 다음 입력을 서버로 보내 Twilio API에 등록해야 합니다. 이에 대한 코드는 아래 코드 스니펫에 제공됩니다.

return (
    <KeyboardAvoidingView
      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
      style={styles.container}>
      <ScrollView contentContainerStyle={styles.container}>
        <View style={styles.form}>
          <View style={styles.formGroup}>
            <Text style={styles.text}>User Name</Text>
            <TextInput
              style={styles.textInput}
              autoCapitalize="none"
              value={props.userName}
              onChangeText={(text) => setProps({...props, userName: text})}
            />
          </View>
          <View style={styles.formGroup}>
            <Text style={styles.text}>Room Name</Text>
            <TextInput
              style={styles.textInput}
              autoCapitalize="none"
              value={props.roomName}
              onChangeText={(text) => setProps({...props, roomName: text})}
            />
          </View>
          <View style={styles.formGroup}>
            <TouchableOpacity
              disabled={false}
              style={styles.button}
              onPress={() => {
                _checkPermissions(() => {
                  fetch(`https://ae7a722dc260.ngrok.io/getToken?userName=${props.userName}`)
                    .then((response) => {
                      if (response.ok) {
                        response.text().then((jwt) => {
                          setProps({...props, token: jwt});
                          navigation.navigate('Video Call');
                          return true;
                        });
                      } else {
                        response.text().then((error) => {
                          Alert.alert(error);
                        });
                      }
                    })
                    .catch((error) => {
                      console.log('error', error);
                      Alert.alert('API not available');
                    });
                });
              }}>
              <Text style={styles.buttonText}>Connect to Video Call</Text>
            </TouchableOpacity>
          </View>
        </View>
      </ScrollView>
    </KeyboardAvoidingView>
  );

아래 에뮬레이터 스크린샷과 같은 결과를 얻을 수 있습니다.

React Native 앱에 화상 통화를 추가하는 방법

여기에서 서버에서 실행되는 Twilio API에 등록하기 위해 방 이름과 사용자 이름을 입력할 수 있는 모달 형식의 방 등록 화면을 볼 수 있습니다.

화상 통화 화면을 구축하는 방법

화상 통화 화면에는 두 개의 창이 있습니다. 하나는 자신의 카메라 보기를 표시하고 다른 하나는 수신자의 카메라 보기를 표시합니다.

먼저 상태를 받아들이기 위해 컨텍스트를 초기화해야 합니다. 그런 다음 useRef을 사용하여 참조 변수를 만듭니다. 아래 코드 스니펫에 지시된 대로 상태에 액세스하기 위한 후크:

const VideoCallScreen = ({navigation}) => {
  const twilioVideo = useRef(null);
  const {props, setProps} = useContext(AppContext);

다음으로 connect을 사용하여 연결을 초기화해야 합니다. twilioVideo의 메소드 아래 코드 스니펫의 지시에 따라 방 이름과 액세스 토큰을 제공하는 객체:

useEffect(() => {
    twilioVideo.current.connect({
      roomName: props.roomName,
      accessToken: props.token,
    });
    setProps({...props, status: 'connecting'});
    return () => {
      _onEndButtonPress();
    };
  }, []);

이제 화상 통화 화면의 본문 템플릿을 만들어야 합니다. 여기에서는 연결이 설정되고 조건부 렌더링을 사용하여 스트리밍되는 경우에만 참가자의 카메라 보기를 표시합니다. 이에 대한 전체 코드는 아래 코드 스니펫에 제공됩니다.

{(props.status === 'connected' || props.status === 'connecting') && (
        <View style={styles.callWrapper}>
          {props.status === 'connected' && (
            <View style={styles.grid}>
              {Array.from(props.videoTracks, ([trackSid, trackIdentifier]) => (
                <TwilioVideoParticipantView
                  style={styles.remoteVideo}
                  key={trackSid}
                  trackIdentifier={trackIdentifier}
                />
              ))}
            </View>
          )}
        </View>
      )}

다음으로 통화 종료, 음소거, 전면 및 후면 카메라 전환과 같은 인비디오 기능을 제어하는 ​​기능을 만들어야 합니다. 필요한 기능의 코딩 구현은 아래 코드 스니펫에 제공됩니다.

const _onEndButtonPress = () => {
    twilioVideo.current.disconnect();
    setProps(initialState);
  };

  const _onMuteButtonPress = () => {
    twilioVideo.current
      .setLocalAudioEnabled(!props.isAudioEnabled)
      .then((isEnabled) => setProps({...props, isAudioEnabled: isEnabled}));
  };

  const _onFlipButtonPress = () => {
    twilioVideo.current.flipCamera();
  };

여기서는 disconnect를 사용했습니다. , setLocalAudioEnabledflipCamera twilioVideo에서 제공하는 메소드 인스턴스를 사용하여 필요한 인비디오 기능을 실행합니다.

이제 기능을 트리거하기 위해 몇 가지 버튼을 렌더링해야 합니다. 이를 위해 다음 코드 스니펫의 코드를 사용해야 합니다.

       <View style={styles.optionsContainer}>
        <TouchableOpacity style={styles.button} onPress={_onEndButtonPress}>
          <Text style={styles.buttonText}>End</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.button} onPress={_onMuteButtonPress}>
          <Text style={styles.buttonText}>
            {props.isAudioEnabled ? 'Mute' : 'Unmute'}
          </Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.button} onPress={_onFlipButtonPress}>
          <Text style={styles.buttonText}>Flip</Text>
        </TouchableOpacity>
      </View>

마지막 단계는 TwilioVideo을 추가하는 것입니다. 모든 화상 통화 이벤트를 처리하고 관찰하도록 구성된 구성요소입니다. 구성된 전체 TwilioVideo 구성 요소는 아래 코드 스니펫에서 제공됩니다.

      <TwilioVideo
        ref={twilioVideo}
        onRoomDidConnect={() => {
          setProps({...props, status: 'connected'});
        }}
        onRoomDidDisconnect={() => {
          setProps({...props, status: 'disconnected'});
          navigation.goBack();
        }}
        onRoomDidFailToConnect={(error) => {
          Alert.alert('Error', error.error);
          setProps({...props, status: 'disconnected'});
          navigation.goBack();
        }}
        onParticipantAddedVideoTrack={({participant, track}) => {
          if (track.enabled) {
            setProps({
              ...props,
              videoTracks: new Map([
                ...props.videoTracks,
                [
                  track.trackSid,
                  {
                    participantSid: participant.sid,
                    videoTrackSid: track.trackSid,
                  },
                ],
              ]),
            });
          }
        }}
        onParticipantRemovedVideoTrack={({track}) => {
          const videoTracks = props.videoTracks;
          videoTracks.delete(track.trackSid);
          setProps({...props, videoTracks});
        }}
      />

방의 사용자 간에 적절한 연결을 설정할 수 있는 경우 다음과 같은 결과를 얻을 수 있습니다.

React Native 앱에 화상 통화를 추가하는 방법

위의 스크린샷은 한 방에 있는 두 참가자 간의 영상 통화를 보여줍니다.

이를 통해 React Native 앱에서 화상 통화 기능을 성공적으로 구현했습니다.

결론

이 튜토리얼은 React Native 앱에서 화상 통화를 설정하는 방법에 대한 초보자 수준의 학습 리소스를 제공하는 것을 목표로 했습니다. Twilio의 프로그래밍 가능한 화상 통화 API를 사용하여 이 작업을 수행했습니다.

React Native 부분뿐만 아니라 별도의 Node 서버 프로젝트에서 전체 API 구현을 다루었습니다.

이제 다음 단계는 익명 통화 시작 또는 여러 참가자 화상 통화방과 같은 고급 기능을 추가하는 것입니다.

기능 영감과 적절한 영상 통화 앱에 대해서는 강력한 기능을 갖춘 영상 채팅 앱의 상태를 제공하는 instamobile.io를 확인하세요.

다음에 만나요 여러분, 해피 코딩!