Expo中实现后台来电弹窗UI:CallKeep配置及替代方案求助
Expo + React Native WebRTC 后台来电弹窗解决方案(CallKeep深度配置+替代方案)
一、Expo环境下CallKeep完整配置步骤(EAS Build必做)
1. 依赖安装与基础配置
别用原生的react-native-callkeep,Expo环境必须用官方适配的expo-callkeep,先装依赖:
npx expo install expo-callkeep
然后在app.json或者app.config.js里加配置,把占位符换成你自己的信息:
{ "expo": { "plugins": [ [ "expo-callkeep", { "ios": { "appGroupName": "group.your.bundle.id.callkeep", "ringtoneFileName": "your-ringtone.caf" }, "android": { "alertTitle": "来电通知", "alertDescription": "有视频通话请求", "cancelButton": "拒绝", "acceptButton": "接听" } } ] ], "ios": { "bundleIdentifier": "your.bundle.id", "backgroundModes": ["voip", "audio", "fetch", "remote-notifications"] }, "android": { "package": "your.package.name", "permissions": [ "android.permission.INTERNET", "android.permission.CAMERA", "android.permission.RECORD_AUDIO", "android.permission.VIBRATE", "android.permission.FOREGROUND_SERVICE", "android.permission.WAKE_LOCK", "com.android.permission.SCHEDULE_EXACT_ALARM" ], "useNextNotificationsApi": true } } }
2. iOS平台关键配置(没做这些肯定成不了)
- VoIP推送证书:去Apple开发者后台生成VoIP推送证书,绑定你的bundle ID,下载后导入Keychain,导出p12给服务端用——这是iOS后台唤醒的核心,没有这个,App后台收不到来电推送。
- App Group配置:在Apple开发者后台给你的App创建App Group,名称要和
app.json里的appGroupName完全一致,CallKeep靠这个在后台和App通信。 - 代码初始化与事件监听:
import * as CallKeep from 'expo-callkeep'; import * as Notifications from 'expo-notifications'; // App启动时就初始化CallKeep async function setupCallKeep() { const options = { ios: { appName: '你的应用名' }, android: { alertTitle: '来电', alertDescription: '视频通话请求', cancelButton: '拒绝', acceptButton: '接听', }, }; await CallKeep.setup(options); // 绑定接听、拒绝、来电事件 CallKeep.addEventListener('didReceiveStartCallAction', handleIncomingCall); CallKeep.addEventListener('answerCall', handleAnswerCall); CallKeep.addEventListener('endCall', handleEndCall); } // 收到VoIP推送后,调用这个方法弹出来电界面 async function showIncomingCall(callId, callerName) { await CallKeep.displayIncomingCall(callId, callerName, callerName, 'video'); } // 注册VoIP推送令牌,发给服务端用来推送来电 async function registerVoipToken() { const token = await Notifications.getExpoPushTokenAsync({ type: 'voip' }); // 把token传给你的服务端存起来 }
3. Android平台关键配置
- 前台服务与后台保活:Android系统杀后台狠,光靠CallKeep不够,配合
expo-task-manager和expo-background-fetch做个心跳任务,维持和服务端的连接:
import * as TaskManager from 'expo-task-manager'; import * as BackgroundFetch from 'expo-background-fetch'; const BACKGROUND_TASK_NAME = 'webrtc-keep-alive'; // 定义后台任务,发心跳包 TaskManager.defineTask(BACKGROUND_TASK_NAME, async () => { // 这里写发送心跳到服务端的逻辑 return BackgroundFetch.Result.NewData; }); // 注册后台任务 async function registerBackgroundTask() { await BackgroundFetch.registerTaskAsync(BACKGROUND_TASK_NAME, { minimumInterval: 15, // 每15分钟触发一次,按需调整 stopOnTerminate: false, startOnBoot: true, }); }
- 高优先级推送:Android上要用FCM的高优先级推送,确保App在后台能收到来电通知,收到后调用
CallKeep.displayIncomingCall就能弹出系统级来电界面。
4. EAS Build必看提醒
- 绝对不能用Expo Go测试,必须用EAS Build生成自定义开发客户端或者正式包,Expo Go不支持CallKeep和VoIP推送。
- iOS要确保推送证书已经上传到Expo后台,
eas.json里的profile配置正确(比如ad-hoc或app-store分发);Android release包要确认权限都被正确授予。
二、CallKeep替代方案
要是折腾半天还是不行,试试这两个选项:
- react-native-incall-manager:主打通话状态管理,配合本地通知实现后台来电提醒,缺点是要自己写来电界面,优点是自定义空间大。
- expo-notifications + 自定义弹窗:后台收到推送时发高优先级通知,点击通知直接唤醒App进入通话界面,实现简单,但没有系统原生来电界面的体验好。
内容的提问来源于stack exchange,提问作者Johndev247
相关产品推荐
相关产品推荐

