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
相关产品推荐
相关产品推荐

