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

如何实现通知跳转链接至应用?适配前后台及关闭状态需求

解决通知点击分状态跳转的问题

我之前做类似的通知跳转功能时也踩过一模一样的坑——不管应用开没开,点通知直接就蹦去浏览器了,完全没达到分状态处理的需求。其实核心就是要先判断应用当前的运行状态,再在通知点击的回调里做分支逻辑处理,给你分享下具体的实现思路和代码示例:

核心思路

  1. 实时检测应用状态:需要能区分应用是「完全关闭」「后台运行」还是「前台活跃」三种状态
  2. 通知点击分支处理:
    • 当应用完全关闭/后台运行时:点击通知先启动应用,等应用初始化完成后再打开目标链接
    • 当应用处于前台活跃时:点击通知直接打开浏览器链接

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:11:05