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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 14:45:49