FCM通知唤起通话Activity异常:后台/关闭状态无法触发
解决FCM后台/关闭时无法唤起通话Activity的问题
核心问题分析
你的代码在前台正常是因为onMessageReceived会被直接触发,但应用后台或关闭时:
- 如果发送的是FCM通知消息(带
notification字段),系统会接管通知展示,不会走到onMessageReceived的启动逻辑; - Android 10+新增后台启动Activity限制,直接调用
startActivity会被系统拦截; - 缺少必要的Intent标记和全屏通知配置,无法像WhatsApp那样强制唤起通话界面。
解决方案步骤
1. 确保发送纯FCM数据消息
服务器端发送的消息必须是纯数据消息(不含notification字段),示例格式:
{ "to": "DEVICE_TOKEN", "data": { "title": "LLAMADA", "username": "xxx", "image": "xxx", "inviterToken": "xxx", "country": "xxx" }, "priority": "high" }
只有纯数据消息会在应用任何状态下触发onMessageReceived。
2. 使用全屏Intent+高优先级通知唤起Activity
修改onMessageReceived中处理"LLAMADA"的逻辑,替换直接startActivity的方式:
@Override public void onMessageReceived(@NonNull RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); String title = remoteMessage.getData().get("title"); if (title != null && title.equals("LLAMADA")) { // 1. 创建启动IncomingActivity的Intent Intent callIntent = new Intent(getApplicationContext(), IncomingActivity.class); callIntent.putExtra("username", remoteMessage.getData().get("username")); callIntent.putExtra("image", remoteMessage.getData().get("image")); callIntent.putExtra("inviterToken", remoteMessage.getData().get("inviterToken")); callIntent.putExtra("country", remoteMessage.getData().get("country")); // 添加必要的Intent标记 callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); // 2. 创建PendingIntent用于全屏唤起 PendingIntent fullScreenPendingIntent = PendingIntent.getActivity( getApplicationContext(), 0, callIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE // Android 12+需加FLAG_IMMUTABLE ); // 3. 构建高优先级通知 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "CALL_CHANNEL_ID") .setSmallIcon(R.drawable.ic_call_notification) .setContentTitle("来电提醒") .setContentText(remoteMessage.getData().get("username") + "正在呼叫你") .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(NotificationCompat.CATEGORY_CALL) // 设置全屏Intent,系统会直接唤起Activity .setFullScreenIntent(fullScreenPendingIntent, true) // 添加接听/拒接按钮(可选) .addAction(R.drawable.ic_accept, "接听", buildAcceptPendingIntent()) .addAction(R.drawable.ic_reject, "拒接", buildRejectPendingIntent()); // 4. 显示通知 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); // 确保通知渠道存在(Android 8+需要) createCallNotificationChannel(); notificationManager.notify(1001, builder.build()); } else { // 原有消息通知逻辑不变 Map<String, String> data = remoteMessage.getData(); String body = data.get("body"); String idNotification = data.get("idNotification"); if (!ifChatActivityInForeground(getBaseContext(), IGNORED_ACTIVITY_NAME)) { if (title.equals("MENSAJE")) { getImageReceiver(data); } else { showNotification(title, body, idNotification); } } } } // 创建通话专用通知渠道(Android 8+必须) private void createCallNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CharSequence name = "通话通知"; String description = "接收来电提醒"; int importance = NotificationManager.IMPORTANCE_HIGH; NotificationChannel channel = new NotificationChannel("CALL_CHANNEL_ID", name, importance); channel.setDescription(description); channel.setSound(null, null); // 可选:自定义来电铃声 NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } } // 构建接听按钮的PendingIntent(示例) private PendingIntent buildAcceptPendingIntent() { Intent acceptIntent = new Intent(this, CallAcceptService.class); // 传递必要参数 return PendingIntent.getService(this, 1, acceptIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); } // 构建拒接按钮的PendingIntent(示例) private PendingIntent buildRejectPendingIntent() { Intent rejectIntent = new Intent(this, CallRejectService.class); // 传递必要参数 return PendingIntent.getService(this, 2, rejectIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); }
3. 配置必要权限
在AndroidManifest.xml中添加:
<!-- Android 13+通知权限 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- 唤醒屏幕权限 --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 允许后台启动Activity(Android 10+) --> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 声明IncomingActivity的launchMode可选设置为singleTop --> <activity android:name=".IncomingActivity" android:launchMode="singleTop" android:showOnLockScreen="true" android:turnScreenOn="true"> </activity>
关键说明
- 全屏Intent:
setFullScreenIntent会让系统在收到通知时直接将Activity置于前台,绕过后台启动限制,这是实现类似WhatsApp来电的核心; - 通知渠道优先级:必须设置为
IMPORTANCE_HIGH,否则全屏Intent可能不生效; - PendingIntent标记:Android 12+必须添加
FLAG_IMMUTABLE或FLAG_MUTABLE,避免崩溃; - 纯数据消息:确保服务器不发送带
notification字段的消息,否则后台状态下onMessageReceived不会被触发。
内容的提问来源于stack exchange,提问作者Heinner Lara
相关产品推荐
相关产品推荐

