Android 10接收通知无法打开应用求助(Android 9代码正常)
解决Android 10+中FCM消息触发启动Activity失效的问题
你遇到的问题其实是Android 10(API 29)引入的两个关键限制导致的:后台应用无法直接启动Activity,以及静态注册广播接收器对隐式广播的限制。下面我会一步步帮你调整代码,适配Android 10及以上版本:
1. 理解核心限制
- Android 10开始,系统严格限制后台应用启动Activity,只有当应用处于前台、拥有前台服务、正在处理用户输入等少数场景下才允许启动。
- 从Android 8.0(API 26)开始,静态注册的广播接收器就无法接收大部分隐式广播了,你之前的
sendImplicitBroadcast虽然转成了显式广播,但这种遍历包管理器的方式在Android 10+的后台环境下依然可能被限制。
2. 替换广播逻辑为前台服务启动Activity
最可靠的方式是通过前台服务来启动通话Activity,因为前台服务属于系统允许启动Activity的合法场景。
步骤2.1:创建前台服务类
新建CallForegroundService.java,用于处理通话启动逻辑:
import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.os.Build; import android.os.IBinder; import androidx.core.app.NotificationCompat; public class CallForegroundService extends Service { private static final int CALL_NOTIFICATION_ID = 1001; private static final String CALL_CHANNEL_ID = "incoming_call_channel"; @Override public void onCreate() { super.onCreate(); // Android 8.0+必须创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( CALL_CHANNEL_ID, "Incoming Call Alerts", NotificationManager.IMPORTANCE_HIGH ); channel.setDescription("Notifications for incoming video calls"); NotificationManager notificationManager = getSystemService(NotificationManager.class); if (notificationManager != null) { notificationManager.createNotificationChannel(channel); } } } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 1. 创建前台通知(必须,否则系统会杀死服务) String senderName = intent.getStringExtra("sender"); Notification notification = new NotificationCompat.Builder(this, CALL_CHANNEL_ID) .setContentTitle("Incoming Video Call") .setContentText(String.format("%s is calling you", senderName)) .setSmallIcon(R.drawable.ic_video_call) // 替换成你的应用图标 .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(NotificationCompat.CATEGORY_CALL) .setAutoCancel(true) .build(); // 启动前台服务 startForeground(CALL_NOTIFICATION_ID, notification); // 2. 启动通话接收Activity Intent activityIntent = new Intent(this, ReceiveCallActivity.class); activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); activityIntent.putExtra("title", intent.getStringExtra("title")); activityIntent.putExtra("sender", senderName); // 适配Android 10+的启动逻辑 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { startActivity(activityIntent, ActivityOptions.makeBasic().toBundle()); } else { startActivity(activityIntent); } // 3. 启动Activity后停止前台服务(可选,根据需求调整) stopForeground(false); stopSelf(); return START_NOT_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
步骤2.2:修改FCM服务逻辑
在FirebaseNotificationService的onMessageReceived中,替换原来的广播发送逻辑,改为启动前台服务:
@Override public void onMessageReceived(RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); Map<String, String> dataMap = remoteMessage.getData(); if (dataMap == null) { return; } if (dataMap.get("title").equalsIgnoreCase("video_call")) { Intent serviceIntent = new Intent(this, CallForegroundService.class); serviceIntent.putExtra("title", dataMap.get("title")); serviceIntent.putExtra("sender", dataMap.get("sender")); // Android 8.0+必须用startForegroundService if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); } else { startService(serviceIntent); } } }
步骤2.3:调整ReceiveCallActivity的代码和Manifest配置
首先,在ReceiveCallActivity的onCreate方法中添加锁屏显示和唤醒逻辑(Android 10+废弃了Manifest中的对应属性,必须代码设置):
import android.os.Build; import android.os.Bundle; import android.view.WindowManager; import androidx.appcompat.app.AppCompatActivity; public class ReceiveCallActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 处理锁屏显示和唤醒屏幕 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { setShowWhenLocked(true); setTurnScreenOn(true); } else { getWindow().addFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD ); } // 你的其他初始化代码 setContentView(R.layout.activity_receive_call); // ... } }
然后,在AndroidManifest.xml中更新Activity和服务的注册:
<!-- 注册前台服务 --> <service android:name=".services.CallForegroundService" android:foregroundServiceType="phoneCall" /> <!-- Android 12+必须指定类型 --> <!-- 更新ReceiveCallActivity的配置 --> <activity android:name=".ReceiveCallActivity" android:excludeFromRecents="true" android:launchMode="singleTask" android:taskAffinity="" android:exported="true" />
3. 添加必要权限
在AndroidManifest.xml中添加前台服务和唤醒锁权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" /> <!-- Android 12+需要 --> <uses-permission android:name="android.permission.WAKE_LOCK" />
4. 移除旧的广播相关代码
可以删除VideoCallReceiver类,以及Manifest中对应的接收器注册,因为现在已经不需要通过广播来启动Activity了。
这样调整后,你的代码在Android 10及以上版本就能正常触发通话界面的启动了。前台服务会绕过后台启动Activity的限制,同时代码中的锁屏唤醒逻辑也能确保通话界面在锁屏状态下正常显示。
内容的提问来源于stack exchange,提问作者Shahal
相关产品推荐
相关产品推荐

