React Native视频通话APP:实现关闭状态下呼入唤醒跳转通话界面
问题描述
- 正在开发一款React Native视频通话APP,后端采用Firebase搭配Voximplant
- 已实现APP处于打开状态时,呼入电话会自动为已登出用户登录并跳转至通话界面,但该功能仅在APP启动时生效
- 需要实现APP处于关闭状态时,呼入电话通过推送唤醒APP并跳转至通话界面,按Voximplant建议集成推送通知后,测试发现APP关闭状态下无法被唤醒,控制台输出警告
warning: FCM headlesstask not registered
登录页面相关代码
import { useNavigation } from "@react-navigation/native"; import React, {useState, useEffect} from "react"; import {View, TextInput, StyleSheet, Pressable, Text, Alert} from 'react-native'; import {Voximplant} from 'react-native-voximplant'; import { ACC_NAME, APP_NAME } from "../../constants"; import messaging from "@react-native-firebase/messaging"; import AsyncStorage from "@react-native-async-storage/async-storage"; const LoginScreen = () => { const[username, setUsername] = useState(''); const[passsword, setPassword] = useState(''); const voximplant = Voximplant.getInstance(); const navigation = useNavigation(); const msg = messaging(); let token = ''; useEffect(async() => { const connect = async () => { const status = await voximplant.getClientState(); if(status === Voximplant.ClientState.DISCONNECTED) { await voximplant.connect(); } else if(status === Voximplant.ClientState.LOGGED_IN) { redirectHome(); } } connect(); pushBackgroundHandler(); pushMessaging(); }, []); const pushManager = async () => { return await msg.getToken(); } const pushMessaging = async () => { await msg.onMessage(async (remoteMessage) => { console.log( `PushManager(android): onMessage: ${remoteMessage.data}` ); await pushNotificationReceived(remoteMessage.data); }); } const refreshToken = async () => { token = await msg.onTokenRefresh(remoteToken => remoteToken); console.log(`PushManager(android): Refresh token: ${token}`); } const pushBackgroundHandler = async () => { await msg.setBackgroundMessageHandler(async(remoteMessage) => { console.log( `PushManager(android): background notification: ${ remoteMessage }`, ); await pushNotificationReceived(remoteMessage.data); }); } const pushNotificationReceived = async (notification) => { await tokenSignin(notification); } const signin = async () => { try { const user = `${username}@${APP_NAME}.${ACC_NAME}.voximplant.com`; const authResult = await voximplant.login(user, passsword); processPushToken(authResult); redirectHome(); } catch(e) { console.log(e); Alert.alert(e.name, `Error code: ${e.code}`); } }; const tokenSignin = async (notification) => { console.log("push notification login"); try { const username = await AsyncStorage.getItem('username'); const accessToken = await AsyncStorage.getItem('accessToken'); const user = `${username}@${APP_NAME}.${ACC_NAME}.voximplant.com`; const authResult = await voximplant.loginWithToken(user, accessToken); processPushToken(authResult); voximplant.handlePushNotification(notification); redirectHome(); } catch(e) { console.log(e); Alert.alert(e.name, `Error code: ${e.code}`); } }; const registerPushToken = async () => { token = await pushManager(); voximplant.registerPushNotificationsToken(token); } const processPushToken = async (authResult) => { const loginTokens = authResult.tokens; if (loginTokens !== null) { await AsyncStorage.setItem('accessToken', loginTokens.accessToken); await AsyncStorage.setItem('refreshToken', loginTokens.refreshToken); await AsyncStorage.setItem('accessExpire', loginTokens.accessExpire.toString()); await AsyncStorage.setItem('refreshExpire', loginTokens.refreshExpire.toString()); await AsyncStorage.setItem('username', username); registerPushToken(); } else { console.error('LoginSuccessful: login tokens are invalid'); } } const redirectHome = () => { navigation.reset({ index: 0, routes: [ { name: 'Contacts' } ] }); }; return ( <View style={styles.page}> <TextInput placeholder="username" style={styles.input} onChangeText={setUsername} value={username} autoCapitalize="none" /> <TextInput placeholder="password" style={styles.input} onChangeText={setPassword} value={passsword} secureTextEntry /> <Pressable style={styles.button} onPress={signin}> <Text>Sign in</Text> </Pressable> </View> ) }; const styles = StyleSheet.create({ page: { padding: 10, alignItems: 'stretch', flex: 1, justifyContent: 'center' }, input: { backgroundColor: 'white', padding: 10, marginVertical: 10, borderRadius: 5 }, button: { backgroundColor: 'dodgerblue', padding: 10, marginVertical: 10, borderRadius: 5, alignItems: 'center' } }); export default LoginScreen;
内容的提问来源于stack exchange,提问作者Oriade
相关产品推荐
相关产品推荐

