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

iOS自定义URL Scheme后台唤起时URL接收异常问题

Hey there! Let's break down what's going on here and fix that stubborn nil URL issue.

The core problem is this: on iOS 13 and later, when your app is already running in the background, URL handling gets routed to the SceneDelegate instead of the AppDelegate. Your current code only handles the AppDelegate's application(_:open:options:) method, which doesn't fire when the app is already active in the background. That's why your receivedURL stays nil when waking from the background—your AppDelegate method isn't even being called in that scenario!

Here's how to fix it, covering both cold starts and background wake-ups:

1. Add SceneDelegate URL Handling (iOS 13+)

If your app uses the scene-based lifecycle (default for iOS 13+), add this to your SceneDelegate to capture URLs when waking from the background:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        guard let url = URLContexts.first?.url else { return }
        // Post a notification with the URL (this skips relying on AppDelegate state)
        NotificationCenter.default.post(name: NSNotification.Name("ReceivedURLNotification"), object: url)
        // Optional: Update AppDelegate's receivedURL for cold start fallback
        if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
            appDelegate.receivedURL = url
        }
    }
}

2. Refactor MainViewController to Listen for Direct URL Notifications

Instead of waiting for the foreground notification to check the AppDelegate variable, listen for a dedicated notification that fires the moment a URL is received. This works for both cold starts and background wake-ups:

class MainViewController: UIViewController {
    @IBOutlet weak var urlToDecodeTextView: UITextView!
    let appDelegate = UIApplication.shared.delegate as? AppDelegate

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Handle URL from cold start
        if let url = appDelegate?.receivedURL {
            updateTextView(with: url)
            // Clear the URL so it doesn't reappear on future launches
            appDelegate?.receivedURL = nil
        }

        // Listen for incoming URLs (works for both cold start and background wake-up)
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleReceivedURL(_:)),
            name: NSNotification.Name("ReceivedURLNotification"),
            object: nil
        )

        // Keep foreground notification only if you need other foreground logic
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleEnteredForeground),
            name: UIApplication.willEnterForegroundNotification,
            object: nil
        )
    }

    @objc private func handleReceivedURL(_ notification: Notification) {
        guard let url = notification.object as? URL else { return }
        updateTextView(with: url)
    }

    @objc private func handleEnteredForeground() {
        print("Made it back to foreground")
        // Add any other foreground-specific logic here
    }

    private func updateTextView(with url: URL) {
        urlToDecodeTextView.text = url.absoluteString
    }

    deinit {
        // Clean up observers to avoid memory leaks
        NotificationCenter.default.removeObserver(self)
    }
}

3. Update AppDelegate to Post Notifications Too

Keep your existing AppDelegate code, but add the notification post so cold starts also trigger the same URL handling flow:

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    var receivedURL: URL?

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        receivedURL = url
        // Post the notification for immediate handling
        NotificationCenter.default.post(name: NSNotification.Name("ReceivedURLNotification"), object: url)
        return true
    }
}

Why This Works:

  • Cold Start: The AppDelegate captures the URL, posts a notification, and the MainViewController either picks it up via the notification or checks the receivedURL variable in viewDidLoad.
  • Background Wake-Up: The SceneDelegate captures the URL and posts the notification immediately, which the MainViewController catches right away—no need to wait for the foreground notification.

Quick Bonus Tip:

Clearing the receivedURL after handling it ensures old URLs don't pop up unexpectedly if the user closes and reopens the app later.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:41:45