如何在AppDelegate外处理UIApplicationDidRegisterToRemoteNotificationsWithDeviceToken?
Great question! Since you're building an iOS framework, it makes total sense to decouple APNs token handling from the host app's AppDelegate—here are a few clean, framework-friendly approaches to pull this off:
1. Use NotificationCenter to Broadcast the Token
This is a low-coupling approach that lets any part of your framework listen for the token once it's received.
First, update the host app's AppDelegate to broadcast the token via a notification:
// In the host app's AppDelegate func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { // Convert token to a valid string (avoid using .description directly!) let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() // Post a notification with the token NotificationCenter.default.post( name: .apnsDeviceTokenReceived, object: nil, userInfo: ["token": tokenString] ) } // Define a reusable notification name (you can put this in your framework) extension Notification.Name { static let apnsDeviceTokenReceived = Notification.Name("APNsDeviceTokenReceived") }
Then, in your framework, create a handler class to listen for this notification:
class FrameworkAPNsHandler { init() { // Start listening when the handler is initialized NotificationCenter.default.addObserver( self, selector: #selector(handleTokenReceived(_:)), name: .apnsDeviceTokenReceived, object: nil ) } @objc private func handleTokenReceived(_ notification: Notification) { guard let token = notification.userInfo?["token"] as? String else { return } // Do your framework-specific logic with the token here print("Framework received APNs token: \(token)") } // Clean up the observer to avoid memory leaks deinit { NotificationCenter.default.removeObserver(self) } }
2. Use a Custom Delegate Pattern (Structured & Scalable)
If you want more control over who receives the token, a delegate pattern is a cleaner, more intentional choice for framework code.
First, create a singleton manager in your framework:
// In your framework protocol APNsManagerDelegate: AnyObject { func apnsManager(_ manager: APNsManager, didReceiveDeviceToken token: String) } class APNsManager { static let shared = APNsManager() weak var delegate: APNsManagerDelegate? private init() {} // Enforce singleton // Call this from the host app's AppDelegate func processDeviceToken(_ deviceToken: Data) { let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() delegate?.apnsManager(self, didReceiveDeviceToken: tokenString) } }
Update the host app's AppDelegate to forward the token to your manager:
// In host app's AppDelegate func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { APNsManager.shared.processDeviceToken(deviceToken) }
Then, in your framework, have your service class conform to the delegate:
class FrameworkCoreService: APNsManagerDelegate { init() { APNsManager.shared.delegate = self } func apnsManager(_ manager: APNsManager, didReceiveDeviceToken token: String) { // Handle token logic for your framework print("Framework core service got token: \(token)") } }
3. Use Closure Callbacks (Simple for Single Use Cases)
If your framework only needs one place to handle the token, a closure is the most concise option.
Update your framework's APNs manager to use a closure:
// In your framework class APNsManager { static let shared = APNsManager() var onTokenReceived: ((String) -> Void)? private init() {} func processDeviceToken(_ deviceToken: Data) { let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() onTokenReceived?(tokenString) } }
Then, in your framework's service class, set the closure:
class FrameworkNotificationService { init() { APNsManager.shared.onTokenReceived = { token in // Handle token here print("Framework notification service received token: \(token)") } } }
Key Reminders for Framework Development:
- Token Conversion: Never use
deviceToken.descriptionto get the token string—it includes extra characters like<and>that will break APNs requests. Stick with themap+joinedmethod shown above. - Host App Docs: Make sure to tell your framework users they need to call your
APNsManagermethod from their AppDelegate (or SceneDelegate, for scene-based apps) callback. - Permissions: The host app still needs to request push notification permissions using
UNUserNotificationCenter.current().requestAuthorization(...)before registering for remote notifications.
内容的提问来源于stack exchange,提问作者user591410

