You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:47:47