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

iOS应用关闭时Swift集成OneSignal推送的URL跳转问题

iOS关闭状态下OneSignal推送URL跳转失败的解决方案

我在iOS平台用Swift开发WebView应用,已集成Universal Link和OneSignal。目前应用在关闭、后台状态下DeepLink均可正常工作,但遇到OneSignal推送的问题:应用关闭时点击带URL的推送无法跳转到对应URL,但前台或后台状态下,URL能正常在WebView中打开。我猜测问题需在SceneDelegate.swift中解决,但尝试多种方法仍未找到方案,相关代码如下:

AbcViewController.swift

import UIKit
import WebKit
import OneSignalFramework
class AbcViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!
    var urlOneSignalNotification: URL?
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(handNotURL), name: Notification.Name(rawValue: "urlReceived"), object: nil)
        
        // Define default URL
        let defaultURL = URL(string: "example.com")!
        let url =  urlOneSignalNotification ?? defaultURL
        var request = URLRequest(url: url)
        webView.load(request)
    }
    
    // Get
    @objc func handNotURL(_ notification: Notification) {
        if let url = notification.object as? URL {
            urlOneSignalNotification = url
            // Load the URL in the web view
            let request = URLRequest(url: urlOneSignalNotification!)
            webView.load(request)
        } else {
            urlOneSignalNotification = nil 
        }
    }
}

AppDelegate.swift

import UIKit
import OneSignalFramework
import UserNotifications
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
//...
}
extension AppDelegate: UNUserNotificationCenterDelegate {
  func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        guard let data = userInfo as? [String: Any] else {
            completionHandler(.noData)
            return
        }
       
        if let customData = data["custom"] as? [String: Any], let urlString = customData["u"] as? String {
            if let url = URL(string: urlString) {
                NotificationCenter.default.post(name: Notification.Name(rawValue: "urlReceived"), object: url)
            } else {
            }
        } 
       
        completionHandler(.newData)
    }
}

问题原因与解决步骤

问题核心在于:应用关闭状态下,didReceiveRemoteNotification不会被触发,且此时ViewController还未初始化,通过NotificationCenter传递URL完全失效。必须在SceneDelegate中处理启动时的推送参数,保存URL后再传递给ViewController加载。

1. 修改SceneDelegate.swift

添加代码处理场景启动及后台唤醒时的推送数据:

import UIKit
import OneSignalFramework

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    // 暂存从推送提取的URL
    private var pendingNotificationURL: URL?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // 处理应用关闭时点击推送启动的情况
        if let notificationResponse = connectionOptions.notificationResponse {
            extractNotificationURL(from: notificationResponse.notification.request.content.userInfo)
        }
        
        guard let windowScene = (scene as? UIWindowScene) else { return }
        window = UIWindow(windowScene: windowScene)
        
        // 初始化根ViewController时传递推送URL
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        if let rootVC = storyboard.instantiateViewController(withIdentifier: "AbcViewController") as? AbcViewController {
            rootVC.urlOneSignalNotification = pendingNotificationURL
            window?.rootViewController = rootVC
            window?.makeKeyAndVisible()
        }
    }
    
    // 处理后台状态下点击推送唤醒应用的情况
    func scene(_ scene: UIScene, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
        extractNotificationURL(from: userInfo)
        if let url = pendingNotificationURL,
           let rootVC = window?.rootViewController as? AbcViewController {
            rootVC.webView.load(URLRequest(url: url))
        }
    }
    
    // 统一提取推送中的URL
    private func extractNotificationURL(from userInfo: [AnyHashable: Any]) {
        guard let data = userInfo as? [String: Any],
              let customData = data["custom"] as? [String: Any],
              let urlString = customData["u"] as? String,
              let url = URL(string: urlString) else {
            pendingNotificationURL = nil
            return
        }
        pendingNotificationURL = url
    }
}

2. 优化AbcViewController的视图加载逻辑

确保视图初始化时能正确使用传递的推送URL:

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(handNotURL), name: Notification.Name(rawValue: "urlReceived"), object: nil)
    
    // 修正默认URL的格式错误(需添加协议头)
    let defaultURL = URL(string: "https://example.com")!
    let targetURL = urlOneSignalNotification ?? defaultURL
    webView.load(URLRequest(url: targetURL))
}

3. 清理AppDelegate中的无效代码

由于关闭状态下didReceiveRemoteNotification不会执行,且后台唤醒的推送已由SceneDelegate处理,可注释掉AppDelegate中的通知发送代码,避免重复操作:

// NotificationCenter.default.post(name: Notification.Name(rawValue: "urlReceived"), object: url)

关键注意事项

  • 确保你的ViewController在Storyboard中的ID设置为AbcViewController,否则需对应修改SceneDelegate中的实例化代码。
  • 推送URL必须包含完整协议头(如https://),否则URL(string:)会返回nil,导致跳转失效。

内容的提问来源于stack exchange,提问作者perps4214213

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 12:53:09