反应本机权限不适用于相机和记录

时间:2021-03-25 17:02:40

标签: react-native webrtc

我正在使用 React-Native,在我的项目中使用 WEBRTC 时我不断收到此错误,谁能告诉我哪里出错了

代码:

    import React, {useEffect, useState, useCallback} from 'react';
    import {View, StyleSheet, Alert, PermissionsAndroid} from 'react-native';
    import {Text} from 'react-native-paper';
    import {Button} from 'react-native-paper';
    import AsyncStorage from '@react-native-community/async-storage';
    import {TextInput} from 'react-native-paper';

    import {useFocusEffect} from '@react-navigation/native';

    import InCallManager from 'react-native-incall-manager';

    import {
      RTCPeerConnection,
      RTCIceCandidate,
      RTCSessionDescription,
      RTCView,
      MediaStream,
      MediaStreamTrack,
      mediaDevices,
      registerGlobals,
    } from 'react-native-webrtc';

    async function requestCameraPermission() {
      try {
        const granted = await PermissionsAndroid.request(
          PermissionsAndroid.PERMISSIONS.CAMERA,
          {
            title: 'Cool Photo App Camera Permission',
            message:
              'Cool Photo App needs access to your camera ' +
              'so you can take awesome pictures.',
            buttonNeutral: 'Ask Me Later',
            buttonNegative: 'Cancel',
            buttonPositive: 'OK',
          },
        );
        if (granted === PermissionsAndroid.RESULTS.GRANTED) {
          console.log('You can use the camera');
        } else {
          console.log('Camera permission denied');
        }
      } catch (err) {
        console.warn(err);
      }
    }


    export default function CallScreen({navigation, ...props}) {
      requestCameraPermission();
      let name;
      let connectedUser;
      const [userId, setUserId] = useState('');
      const [socketActive, setSocketActive] = useState(false);
      const [calling, setCalling] = useState(false);
      // Video Scrs
      const [localStream, setLocalStream] = useState({toURL: () => null});
      const [remoteStream, setRemoteStream] = useState({toURL: () => null});
      const [conn, setConn] = useState(new WebSocket('ws://localhost:8080'));
      const [yourConn, setYourConn] = useState(
        //change the config as you need
        new RTCPeerConnection({
          iceServers: [
            {
              urls: 'stun:stun.l.google.com:19302',  
            }, {
              urls: 'stun:stun1.l.google.com:19302',    
            }, {
              urls: 'stun:stun2.l.google.com:19302',    
            }

          ],
        }),
      );
      const [offer, setOffer] = useState(null);

      const [callToUsername, setCallToUsername] = useState(null);

      useFocusEffect(
        useCallback(() => {
          AsyncStorage.getItem('userId').then(id => {
            console.log(id);
            if (id) {
              setUserId(id);
            } else {
              setUserId('');
              navigation.push('Login');
            }
          });
        }, [userId]),
      );

      useEffect(() => {
        navigation.setOptions({
          title: 'Your ID - ' + userId,
          headerRight: () => (
            <Button mode="text" onPress={onLogout} style={{paddingRight: 10}}>
              Logout
            </Button>
          ),
        });
      }, [userId]);

      /**
       * Calling Stuff
       */

      useEffect(() => {
        if (socketActive && userId.length > 0) {
          try {
            InCallManager.start({media: 'audio'});
            InCallManager.setForceSpeakerphoneOn(true);
            InCallManager.setSpeakerphoneOn(true);
            InCallManager.requestRecordPermission();
            InCallManager.requestCameraPermission();
          

          } catch (err) {
            console.log('InApp Caller ---------------------->', err);
          }

          console.log(InCallManager);

          send({
            type: 'login',
            name: userId,
          });
        }
      }, [socketActive, userId]);

      const onLogin = () => {};

      useEffect(() => {
        /**
         *
         * Sockets Signalling
         */
        conn.onopen = () => {
          console.log('Connected to the signaling server');
          setSocketActive(true);
        };
        //when we got a message from a signaling server
        conn.onmessage = msg => {
          let data;
          if (msg.data === 'Hello world') {
            data = {};
          } else {
            data = JSON.parse(msg.data);
            console.log('Data --------------------->', data);
            switch (data.type) {
              case 'login':
                console.log('Login');
                break;
              //when somebody wants to call us
              case 'offer':
                handleOffer(data.offer, data.name);
                console.log('Offer');
                break;
              case 'answer':
                handleAnswer(data.answer);
                console.log('Answer');
                break;
              //when a remote peer sends an ice candidate to us
              case 'candidate':
                handleCandidate(data.candidate);
                console.log('Candidate');
                break;
              case 'leave':
                handleLeave();
                console.log('Leave');
                break;
              default:
                break;
            }
          }
        };
        conn.onerror = function(err) {
          console.log('Got error', err);
        };
        /**
         * Socjket Signalling Ends
         */

        let isFront = false;
        mediaDevices.enumerateDevices().then(sourceInfos => {
          let videoSourceId;
          for (let i = 0; i < sourceInfos.length; i++) {
            const sourceInfo = sourceInfos[i];
            if (
              sourceInfo.kind == 'videoinput' &&
              sourceInfo.facing == (isFront ? 'front' : 'environment')
            ) {
              videoSourceId = sourceInfo.deviceId;
            }
          }
          mediaDevices
            .getUserMedia({
              audio: true,
              video: {
                mandatory: {
                  minWidth: 500, // Provide your own width, height and frame rate here
                  minHeight: 300,
                  minFrameRate: 30,
                },
                facingMode: isFront ? 'user' : 'environment',
                optional: videoSourceId ? [{sourceId: videoSourceId}] : [],
              },
            })
            .then(stream => {
              // Got stream!
              setLocalStream(stream);

              // setup stream listening
              yourConn.addStream(stream);
            })
            .catch(error => {
              // Log error
            });
        });

        yourConn.onaddstream = event => {
          console.log('On Add Stream', event);
          setRemoteStream(event.stream);
        };

        // Setup ice handling
        yourConn.onicecandidate = event => {
          if (event.candidate) {
            send({
              type: 'candidate',
              candidate: event.candidate,
            });
          }
        };
      }, []);

      const send = message => {
        //attach the other peer username to our messages
        if (connectedUser) {
          message.name = connectedUser;
          console.log('Connected iser in end----------', message);
        }

        conn.send(JSON.stringify(message));
      };

      const onCall = () => {
        setCalling(true);

        connectedUser = callToUsername;
        console.log('Caling to', callToUsername);
        // create an offer

        yourConn.createOffer().then(offer => {
          yourConn.setLocalDescription(offer).then(() => {
            console.log('Sending Ofer');
            console.log(offer);
            send({
              type: 'offer',
              offer: offer,
            });
            // Send pc.localDescription to peer
          });
        });
      };

      //when somebody sends us an offer
      const handleOffer = async (offer, name) => {
        console.log(name + ' is calling you.');

        console.log('Accepting Call===========>', offer);
        connectedUser = name;

        try {
          await yourConn.setRemoteDescription(new RTCSessionDescription(offer));

          const answer = await yourConn.createAnswer();

          await yourConn.setLocalDescription(answer);
          send({
            type: 'answer',
            answer: answer,
          });
        } catch (err) {
          console.log('Offerr Error', err);
        }
      };

      //when we got an answer from a remote user
      const handleAnswer = answer => {
        yourConn.setRemoteDescription(new RTCSessionDescription(answer));
      };

      //when we got an ice candidate from a remote user
      const handleCandidate = candidate => {
        setCalling(false);
        console.log('Candidate ----------------->', candidate);
        yourConn.addIceCandidate(new RTCIceCandidate(candidate));
      };

      //hang up
      const hangUp = () => {
        send({
          type: 'leave',
        });

        handleLeave();
      };

      const handleLeave = () => {
        connectedUser = null;
        setRemoteStream({toURL: () => null});

        yourConn.close();
        // yourConn.onicecandidate = null;
        // yourConn.onaddstream = null;
      };

      const onLogout = () => {
        // hangUp();

        AsyncStorage.removeItem('userId').then(res => {
          navigation.push('Login');
        });
      };

      const acceptCall = async () => {
        console.log('Accepting Call===========>', offer);
        connectedUser = offer.name;

        try {
          await yourConn.setRemoteDescription(new RTCSessionDescription(offer));

          const answer = await yourConn.createAnswer();

          await yourConn.setLocalDescription(answer);

          send({
            type: 'answer',
            answer: answer,
          });
        } catch (err) {
          console.log('Offerr Error', err);
        }
      };
      const rejectCall = async () => {
        send({
          type: 'leave',
        });
        ``;
        setOffer(null);

        handleLeave();
      };

      /**
       * Calling Stuff Ends
       */

      return (
        <View style={styles.root}>
          <View style={styles.inputField}>
            <TextInput
              label="Enter Friends Id"
              mode="outlined"
              style={{marginBottom: 7}}
              onChangeText={text => setCallToUsername(text)}
            />
            <Button
              mode="contained"
              onPress={onCall}
              loading={calling}
              //   style={styles.btn}
              contentStyle={styles.btnContent}
              disabled={!(socketActive && userId.length > 0)}>
              Call
            </Button>
          </View>

          <View style={styles.videoContainer}>
            <View style={[styles.videos, styles.localVideos]}>
              <Text>Your Video</Text>
              <RTCView streamURL={localStream.toURL()} style={styles.localVideo} />
            </View>
            <View style={[styles.videos, styles.remoteVideos]}>
              <Text>Friends Video</Text>
              <RTCView
                streamURL={remoteStream.toURL()}
                style={styles.remoteVideo}
              />
            </View>
          </View>
        </View>
      );
    }

    const styles = StyleSheet.create({
      root: {
        backgroundColor: '#fff',
        flex: 1,
        padding: 20,
      },
      inputField: {
        marginBottom: 10,
        flexDirection: 'column',
      },
      videoContainer: {
        flex: 1,
        minHeight: 450,
      },
      videos: {
        width: '100%',
        flex: 1,
        position: 'relative',
        overflow: 'hidden',

        borderRadius: 6,
      },
      localVideos: {
        height: 100,
        marginBottom: 10,
      },
      remoteVideos: {
        height: 400,
      },
      localVideo: {
        backgroundColor: '#f2f2f2',
        height: '100%',
        width: '100%',
      },
      remoteVideo: {
        backgroundColor: '#f2f2f2',
        height: '100%',
        width: '100%',
      },
    });

错误:

        [Unhandled promise rejection: TypeError: null is not an object (evaluating '_InCallManager.checkCameraPermission')]
    at node_modules\react-native-incall-manager\index.js:137:4 in InCallManager#checkCameraPermission
    at node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
    at node_modules\regenerator-runtime\runtime.js:293:29 in invoke
    at node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
    at node_modules\regenerator-runtime\runtime.js:154:27 in invoke
    at node_modules\regenerator-runtime\runtime.js:189:16 in PromiseImpl$argument_0
    at node_modules\react-native\node_modules\promise\setimmediate\core.js:45:6 in tryCallTwo
    at node_modules\react-native\node_modules\promise\setimmediate\core.js:200:22 in doResolve
    at node_modules\react-native\node_modules\promise\setimmediate\core.js:66:11 in Promise
    at node_modules\regenerator-runtime\runtime.js:188:15 in callInvokeWithMethodAndArg
    at node_modules\regenerator-runtime\runtime.js:211:38 in enqueue
    at node_modules\regenerator-runtime\runtime.js:238:8 in exports.async
    at [native code]:null in checkCameraPermission
    at node_modules\react-native-incall-manager\index.js:22:8 in InCallManager#constructor
    at http://192.168.1.102:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&minify=false:168267:34 in <unknown>
    at node_modules\metro\src\lib\polyfills\require.js:321:11 in loadModuleImplementation
    at http://192.168.1.102:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&minify=false:167304:68 in <unknown>
    at node_modules\metro\src\lib\polyfills\require.js:321:11 in loadModuleImplementation
    at http://192.168.1.102:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&minify=false:134166:54 in <unknown>
    at node_modules\metro\src\lib\polyfills\require.js:321:11 in loadModuleImplementation
    at node_modules\expo\AppEntry.js:3:0 in <global>
    at node_modules\metro\src\lib\polyfills\require.js:321:11 in loadModuleImplementation
    at node_modules\metro\src\lib\polyfills\require.js:201:44 in guardedLoadModule
    at http://192.168.1.102:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&minify=false:170463:3 in global code

    [Unhandled promise rejection: TypeError: null is not an object (evaluating '_InCallManager.checkRecordPermission')]
    at node_modules\react-native-incall-manager\index.js:123:4 in InCallManager#checkRecordPermission
    at node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
    at node_modules\regenerator-runtime\runtime.js:293:29 in invoke
    at node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
    at node_modules\regenerator-runtime\runtime.js:154:27 in invoke
    at node_modules\regenerator-runtime\runtime.js:189:16 in PromiseImpl$argument_0
    at node_modules\react-native\node_modules\promise\setimmediate\core.js:45:6 in tryCallTwo
    at node_modules\react-native\node_modules\promise\setimmediate\core.js:200:22 in doResolve
    at node_modules\react-native\node_modules\promise\setimmediate\core.js:66:11 in Promise
    at node_modules\regenerator-runtime\runtime.js:188:15 in callInvokeWithMethodAndArg
    at node_modules\regenerator-runtime\runtime.js:211:38 in enqueue
    at node_modules\regenerator-runtime\runtime.js:238:8 in exports.async
    at [native code]:null in checkRecordPermission
    at node_modules\react-native-incall-manager\index.js:21:13 in InCallManager#constructor
    at http://192.168.1.102:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&minify=false:168267:34 in <unknown>
    at node_modules\metro\src\lib\polyfills\require.js:321:11 in loadModuleImplementation
    at http://192.168.1.102:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&minify=false:167304:68 in <unknown>
    at node_modules\metro\src\lib\polyfills\require.js:321:11 in loadModuleImplementation
    at http://192.168.1.102:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&minify=false:134166:54 in <unknown>
    at node_modules\metro\src\lib\polyfills\require.js:321:11 in loadModuleImplementation
    at node_modules\expo\AppEntry.js:3:0 in <global>
    at node_modules\metro\src\lib\polyfills\require.js:321:11 in loadModuleImplementation
    at node_modules\metro\src\lib\polyfills\require.js:201:44 in guardedLoadModule
    at http://192.168.1.102:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&minify=false:170463:3 in global code

上面的错误是一个警告,但是一旦我输入登录值并点击按钮,我就会收到这个错误:

                You can use the camera
            Error [TypeError: null is not an object (evaluating 'WebRTCModule.peerConnectionInit')]

            TypeError: null is not an object (evaluating 'WebRTCModule.peerConnectionInit')

            This error is located at:
                in CallScreen (at SceneView.tsx:122)
                in StaticContainer
                in StaticContainer (at SceneView.tsx:115)
                in EnsureSingleNavigator (at SceneView.tsx:114)
                in SceneView (at useDescriptors.tsx:153)
                in RCTView (at View.js:34)
                in View (at CardContainer.tsx:245)
                in RCTView (at View.js:34)
                in View (at CardContainer.tsx:244)
                in RCTView (at View.js:34)
                in View (at CardSheet.tsx:33)
                in ForwardRef(CardSheet) (at Card.tsx:573)
                in RCTView (at View.js:34)
                in View (at createAnimatedComponent.js:165)
                in AnimatedComponent (at createAnimatedComponent.js:215)
                in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:555)
                in PanGestureHandler (at GestureHandlerNative.tsx:13)
                in PanGestureHandler (at Card.tsx:549)
                in RCTView (at View.js:34)
                in View (at createAnimatedComponent.js:165)
                in AnimatedComponent (at createAnimatedComponent.js:215)
                in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:544)
                in RCTView (at View.js:34)
                in View (at Card.tsx:538)
                in Card (at CardContainer.tsx:206)
                in CardContainer (at CardStack.tsx:620)
                in RCTView (at View.js:34)
                in View (at Screens.tsx:84)
                in MaybeScreen (at CardStack.tsx:613)
                in RCTView (at View.js:34)
                in View (at Screens.tsx:54)
                in MaybeScreenContainer (at CardStack.tsx:495)
                in CardStack (at StackView.tsx:462)
                in KeyboardManager (at StackView.tsx:458)
                in RNCSafeAreaProvider (at SafeAreaContext.tsx:76)
                in SafeAreaProvider (at SafeAreaProviderCompat.tsx:42)
                in SafeAreaProviderCompat (at StackView.tsx:455)
                in GestureHandlerRootView (at GestureHandlerRootView.android.tsx:26)
                in GestureHandlerRootView (at StackView.tsx:454)
                in StackView (at createStackNavigator.tsx:87)
                in StackNavigator (at App.js:39)
                in EnsureSingleNavigator (at BaseNavigationContainer.tsx:409)
                in ForwardRef(BaseNavigationContainer) (at NavigationContainer.tsx:91)
                in ThemeProvider (at NavigationContainer.tsx:90)
                in ForwardRef(NavigationContainer) (at App.js:38)
                in App (created by ExpoRoot)
                in ExpoRoot (at renderApplication.js:45)
                in RCTView (at View.js:34)
                in View (at AppContainer.js:106)
                in RCTView (at View.js:34)
                in View (at AppContainer.js:132)
                in AppContainer (at renderApplication.js:39)

            at node_modules\react-
            at [native code]:null in performSyncWorkOnRoot
            at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5321:31 in runWithPriority$argument_1
            at node_modules\scheduler\cjs\scheduler.development.js:653:23 in unstable_runWithPriority
            at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5316:21 in flushSyncCallbackQueueImpl
            at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5304:28 in flushSyncCallbackQueue
            at node_modules\react-
            at [native code]:null in dispatchAction
            at node_modules\@react-navigation\core\src\useSyncState.tsx:38:9 in React.useCallback$argument_0
            at http://192.168.1.102:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&minify=false:138144:20 in <unknown>
            at node_modules\@react-navigation\core\src\useNavigationHelpers.tsx:43:21 in dispatch
            at node_modules\@react-navigation\core\src\useNavigationCache.tsx:77:12 in dispatch
            at node_modules\@react-navigation\core\src\useNavigationCache.tsx:89:24 in acc.name
            at screens\LoginScreen.js:19:6 in onLogin
            at node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
            at node_modules\regenerator-runtime\runtime.js:293:29 in invoke
            at node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
            at node_modules\regenerator-runtime\runtime.js:154:27 in invoke
            at node_modules\regenerator-runtime\runtime.js:164:18 in PromiseImpl.resolve.then$argument_0
            at node_modules\react-native\node_modules\promise\setimmediate\core.js:37:13 in tryCallOne
            at node_modules\react-native\node_modules\promise\setimmediate\core.js:123:24 in setImmediate$argument_0
            at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:130:14 in _callTimer
            at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:181:14 in _callImmediatesPass
            at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:441:30 in callImmediates
            at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:387:6 in __callImmediates
            at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:135:6 in __guard$argument_0
            at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:364:10 in __guard
            at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:134:4 in flushedQueue
            at [native code]:null in flushedQueue
            at [native code]:null in invokeCallbackAndReturnFlushedQueue

            Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
            at node_modules\react-native\Libraries\LogBox\LogBox.js:173:8 in registerError
            at node_modules\react-native\Libraries\LogBox\LogBox.js:59:8 in errorImpl
            at node_modules\react-native\Libraries\LogBox\LogBox.js:33:4 in console.error
            at node_modules\expo\build\environment\react-native-logs.fx.js:27:4 in error
        setImmediate$argument_0
            at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:130:14 in _callTimer
            at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:181:14 in _callImmediatesPass
            at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:441:30 in callImmediates
            at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:387:6 in __callImmediates
            at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:135:6 in __guard$argument_0
            at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:364:10 in __guard
            at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:134:4 in flushedQueue
            at [native code]:null in flushedQueue
            at [native code]:null in invokeCallbackAndReturnFlushedQueue

我已经完成了资源所说的一切,所以我添加了这个:

      import React from 'react';
      import {NavigationContainer} from '@react-navigation/native';
      import {createStackNavigator} from '@react-navigation/stack';
      import {View, StyleSheet, Alert, PermissionsAndroid} from 'react-native';

      import LoginScreen from './screens/LoginScreen';
      import CallScreen from './screens/CallScreen';
      import {SafeAreaView} from 'react-native-safe-area-context';

      const Stack = createStackNavigator();

      const requestCameraPermission = async () => {
        try {
          const granted = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.CAMERA,
            {
              title: "Cool Photo App Camera Permission",
              message:
                "Cool Photo App needs access to your camera " +
                "so you can take awesome pictures.",
              buttonNeutral: "Ask Me Later",
              buttonNegative: "Cancel",
              buttonPositive: "OK"
            }
          );
          if (granted === PermissionsAndroid.RESULTS.GRANTED) {
            console.log("You can use the camera");
          } else {
            console.log("Camera permission denied");
          }
        } catch (err) {
          console.warn(err);
        }
      };

      const App = () => {

        requestCameraPermission();

        return (
          <NavigationContainer>
            <Stack.Navigator>
              <Stack.Screen
                name="Login"
                component={LoginScreen}
                options={{headerShown: false}}
              />
              <Stack.Screen name="Call" component={CallScreen} />
            </Stack.Navigator>
          </NavigationContainer>
        );
      };

      export default App;

我关注的资源在这里:https://www.npmjs.com/package/react-native-incall-manager

0 个答案:

没有答案