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
receivedURLvariable inviewDidLoad. - 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

