如何实现通知跳转链接至应用?适配前后台及关闭状态需求
解决通知点击分状态跳转的问题
我之前做类似的通知跳转功能时也踩过一模一样的坑——不管应用开没开,点通知直接就蹦去浏览器了,完全没达到分状态处理的需求。其实核心就是要先判断应用当前的运行状态,再在通知点击的回调里做分支逻辑处理,给你分享下具体的实现思路和代码示例:
核心思路
- 实时检测应用状态:需要能区分应用是「完全关闭」「后台运行」还是「前台活跃」三种状态
- 通知点击分支处理:
- 当应用完全关闭/后台运行时:点击通知先启动应用,等应用初始化完成后再打开目标链接
- 当应用处于前台活跃时:点击通知直接打开浏览器链接
Android 具体实现
1. 监听应用生命周期,判断前台状态
推荐用ProcessLifecycleOwner来监听应用的全局生命周期,比ActivityManager更可靠:
class MyApplication : Application() { companion object { // 标记应用是否处于前台 var isAppInForeground = false } override fun onCreate() { super.onCreate() // 注册生命周期观察者 ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver { override fun onResume(owner: LifecycleOwner) { super.onResume(owner) isAppInForeground = true } override fun onPause(owner: LifecycleOwner) { super.onPause(owner) isAppInForeground = false } }) } }
2. 构建通知时设置动态跳转逻辑
在创建通知的PendingIntent时,根据应用当前状态选择不同的跳转目标:
fun createNotification(context: Context, link: String) { val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // 构建点击后的Intent val intent = if (MyApplication.isAppInForeground) { // 前台状态:直接打开浏览器 Intent(Intent.ACTION_VIEW, Uri.parse(link)).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK } } else { // 后台/关闭状态:先启动主Activity,传递链接参数 Intent(context, MainActivity::class.java).apply { putExtra("INTENT_KEY_OPEN_LINK", link) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP } } val pendingIntent = PendingIntent.getActivity( context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // Android 12+ 必须加FLAG_IMMUTABLE ) // 构建通知 val notification = NotificationCompat.Builder(context, "CHANNEL_ID") .setContentTitle("通知标题") .setContentText("点击查看详情") .setSmallIcon(R.drawable.ic_notification) .setContentIntent(pendingIntent) .setAutoCancel(true) .build() notificationManager.notify(1, notification) }
3. 主Activity处理传递的链接
在主Activity的onCreate和onNewIntent中接收链接并打开浏览器:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 处理启动时携带的链接 handleOpenLink(intent) } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) // 处理后台唤醒时携带的链接 handleOpenLink(intent) } private fun handleOpenLink(intent: Intent?) { intent?.getStringExtra("INTENT_KEY_OPEN_LINK")?.let { link -> startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link))) } } }
iOS 具体实现
1. 通知点击回调中判断应用状态
在UserNotificationCenterDelegate的回调里,通过UIApplication.shared.applicationState获取当前状态:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { // 从通知内容中取出目标链接 guard let link = response.notification.request.content.userInfo["link"] as? String else { completionHandler() return } let appState = UIApplication.shared.applicationState switch appState { case .active: // 前台状态:直接打开浏览器 if let url = URL(string: link) { UIApplication.shared.open(url) } case .background, .inactive: // 后台/关闭状态:先保存链接,等应用启动后处理 UserDefaults.standard.set(link, forKey: "PendingOpenLink") // 自动恢复应用到前台(iOS会处理启动逻辑) if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene { scene.windows.first?.makeKeyAndVisible() } @unknown default: break } completionHandler() }
2. 应用启动/激活时处理待打开链接
在SceneDelegate的sceneDidBecomeActive方法中,读取保存的链接并打开:
func sceneDidBecomeActive(_ scene: UIScene) { guard let pendingLink = UserDefaults.standard.string(forKey: "PendingOpenLink") else { return } // 打开链接 if let url = URL(string: pendingLink) { UIApplication.shared.open(url) } // 清空已处理的链接 UserDefaults.standard.removeObject(forKey: "PendingOpenLink") }
另外,如果应用是完全关闭状态,点击通知会触发scene(_:willConnectTo:options:),这里也可以加一次链接检查:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // 检查通知启动时携带的链接 if let notificationResponse = connectionOptions.notificationResponse { let userInfo = notificationResponse.notification.request.content.userInfo if let link = userInfo["link"] as? String, let url = URL(string: link) { UIApplication.shared.open(url) } } }
注意事项
- Android 12及以上版本,
PendingIntent必须设置FLAG_IMMUTABLE或FLAG_MUTABLE,根据是否需要修改Intent内容选择 - iOS中如果使用SceneDelegate,要确保所有场景激活的入口都处理了待打开链接
- 测试时一定要覆盖「应用关闭」「后台运行」「前台活跃」三种场景,避免逻辑遗漏
内容的提问来源于stack exchange,提问作者Martín Unzueta
相关产品推荐
相关产品推荐

