Android Studio中应用后台时如何从通知打开URI
问题根源
当应用在后台时,FCM的通知类型消息会直接交给系统通知栏处理,不会触发FirebaseMessagingService的onMessageReceived方法——这就导致你当前在这个方法里构建的PendingIntent完全没用。只有纯数据类型消息才会在后台时也触发onMessageReceived,或者得靠配置通知payload的click_action配合Manifest来搞定。
两种可行解决方案
方案1:统一前台/后台逻辑(推荐)
这个方案让所有消息都走你自己的通知构建逻辑,不管前台后台都能生效:
修改PendingIntent的启动标记
后台启动Activity必须加FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP(按需调整),不然系统不让你从后台拉起Activity。另外Android 12及以上对PendingIntent的标记有强制要求,得加上FLAG_IMMUTABLE:Intent notificationIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(commingUrl)); // 加标记让后台能正常启动Activity notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); // 适配Android 12+的PendingIntent要求 int pendingFlags = PendingIntent.FLAG_ONE_SHOT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { pendingFlags |= PendingIntent.FLAG_IMMUTABLE; } PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, pendingFlags);让推送端发纯数据消息
告诉推送的同事,别发带notification字段的消息,只发data字段的。这样不管应用在前台还是后台,都会触发onMessageReceived,执行你写的构建通知代码。示例payload:{ "to": "设备的FCM_TOKEN", "data": { "title": "你的通知标题", "body": "你的通知内容", "commingUrl": "https://目标网址.com" } }
方案2:适配系统自动展示的通知
如果没法改推送消息类型,只能用通知类型消息,那就这么搞:
推送payload里加click_action字段
在通知的payload里加个click_action,值设成你自定义的action,比如OPEN_MY_URI:{ "to": "设备的FCM_TOKEN", "notification": { "title": "通知标题", "body": "通知内容", "click_action": "OPEN_MY_URI" }, "data": { "commingUrl": "https://目标网址.com" } }Manifest里给Activity加Intent Filter
找个用来处理跳转的Activity(或者新建个中转Activity),在Manifest里加对应的intent-filter:<activity android:name=".YourActivity" android:exported="true"> <intent-filter> <action android:name="OPEN_MY_URI" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>在Activity里获取URI并跳转
在这个Activity的onCreate或者onNewIntent里,从Intent的extra里拿到commingUrl然后跳转:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handleUri(getIntent()); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); handleUri(intent); } private void handleUri(Intent intent) { if (intent != null && intent.getExtras() != null) { String url = intent.getExtras().getString("commingUrl"); if (url != null && !url.isEmpty()) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); finish(); // 中转Activity用完就关 } } }
修改后的完整openAnotherApp方法(方案1)
void openAnotherApp(@NonNull RemoteMessage remoteMessage, Context context, String title, String body, String commingUrl) { Intent notificationIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(commingUrl)); // 添加后台启动Activity的必要标记 notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); // 适配Android 12及以上的PendingIntent标记要求 int pendingFlags = PendingIntent.FLAG_ONE_SHOT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { pendingFlags |= PendingIntent.FLAG_IMMUTABLE; } PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, pendingFlags); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.notification) .setContentTitle(title) .setContentText(body) .setAutoCancel(true) .setPriority(NotificationCompat.PRIORITY_DEFAULT); notificationBuilder.setContentIntent(pendingIntent); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(0, notificationBuilder.build()); }
注意:别忘了提前创建好CHANNEL_ID对应的通知渠道,不然通知可能显示不出来。
内容的提问来源于stack exchange,提问作者devio

