为 Swift 4.2 更新
如前所述,您想在 applicationDidLaunchWithOptions 中注册远程通知:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let pushSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
UIApplication.shared.registerUserNotificationSettings(pushSettings)
UIApplication.shared.registerForRemoteNotifications()
}
当您从 lockScreen/Background 回来时,无法知道您将在哪个 viewController 中。我所做的是从 appDelegate 发送通知。当收到remoteNotification 时,会调用appDelegate 中的didReceiveRemoteNotification。
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
let notif = JSON(userInfo) // SwiftyJSON required
根据您的通知负载,您应该首先确保它不为 nil,然后调用一个 NSNotification,该 NSNotification 将被应该捕获此通知的 viewControllers 捕获。这也是您可以根据收到的有效负载发布不同类型的通知的地方。可能是这个样子,举个例子吧:
if notif["callback"]["type"] != nil {
NotificationCenter.default.post(name: Notification.Name(rawValue: "myNotif"), object: nil)
// This is where you read your JSON to know what kind of notification you received
}
如果您收到消息通知并且由于令牌已过期而不再登录,则该通知将永远不会在视图控制器中捕获,因为它永远不会被监视。
现在是在视图控制器中捕获通知的部分。在视图中会出现:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(self.catchIt), name: NSNotification.Name(rawValue: "myNotif"), object: nil)
}
现在你添加了这个观察者,每次在这个控制器中调用一个通知,函数catchIt也会被调用。您必须在要实现特定操作的每个视图控制器中实现它。
func catchIt(_ userInfo: Notification){
let prefs: UserDefaults = UserDefaults.standard
prefs.removeObject(forKey: "startUpNotif")
if userInfo.userInfo?["userInfo"] != nil{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: RedirectAppInactiveVC = storyboard.instantiateViewController(withIdentifier: "RedirectAppInactiveVC") as! RedirectAppInactiveVC
self.navigationController?.pushViewController(vc, animated: true)
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: RedirectAppActiveVC = storyboard.instantiateViewController(withIdentifier: "RedirectAppActiveVC") as! RedirectAppActiveVC
self.navigationController?.pushViewController(vc, animated: true)
}
}
离开视图控制器时不要忘记取消订阅通知,否则视图控制器,如果仍在堆栈中,将捕获通知并执行它(你可能想要这样做,但知道你的内容更安全正在进入)。所以我建议在viewWillDisappear中退订:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.removeObserver(self)
}
这样做,您将加载所需的 viewController。现在我们还没有处理所有的病例。如果您还没有打开您的应用程序怎么办。显然,没有加载任何 UIViewController,它们都无法捕捉到通知。您想知道您是否在 appDelegate 中的 didFinishLaunchingWithOptions: 中收到通知。我要做的是:
let prefs: UserDefaults = UserDefaults.standard
if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? NSDictionary {
prefs.set(remoteNotification as! [AnyHashable: Any], forKey: "startUpNotif")
prefs.synchronize()
}
现在,您已设置首选项,说明应用程序是使用远程通知启动的。在应首先在应用程序中加载的控制器中,我建议在 viewDidAppear 中执行以下操作:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let prefs: UserDefaults = UserDefaults.standard
if prefs.value(forKey: "startUpNotif") != nil {
let userInfo: [AnyHashable: Any] = ["inactive": "inactive"]
NotificationCenter.default.post(name: Notification.Name(rawValue: "myNotif"), object: nil, userInfo: userInfo as [AnyHashable: Any])
}
}
希望对您有所帮助。我还制作了一个 GitHub 存储库来说明本地通知:Local Notifications Observer Pattern(类似于远程通知)。类似的逻辑可以使用根视图控制器Local Notifications Root Pattern来实现,我个人认为这取决于你要实现什么。
这些示例用于说明如何简单地实现它。对于更大的项目,您最终会得到更复杂的架构,例如内部使用类似机制的协调器。