在SWIFT中接收推送通知后控制哪个视图控制器加载

Hen*_*own 30 push-notification apple-push-notifications appdelegate

一旦我收到推送通知并轻扫以打开它,它就会打开我的应用而不是我想要的VC.

所以我的问题是如何加载我想要的VC?我知道如果应用程序是打开的,我会将VC移到另一个内部,didReceiveRemoteNotification但如果应用程序未打开,我该怎么做?或者它是否处于后台模式?

此外,我有两个不同的推送通知,因此我需要它移动两个不同的VC中的一个.如何区分不同的推送通知?

谢谢.

Swi*_*bit 48

更新了Swift 3.0

就像它说的那样,你想在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()
}
Run Code Online (Sandbox Code Playgroud)

从lockScreen/Background返回时,无法知道在哪个viewController中.我所做的是从appDelegate发送通知.当您收到remoteNotification时,将调用appDelegate中的didReceiveRemoteNotification.

 func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    let notif = JSON(userInfo) // SwiftyJSON required 
Run Code Online (Sandbox Code Playgroud)

根据您的通知所包含的内容,您应首先确保它不是nil,然后调用将捕获此通知的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, for example :    

}
Run Code Online (Sandbox Code Playgroud)

例如,如果您收到消息通知并且由于令牌已过期而您不再登录,则通知将永远不会在视图控制器中捕获,因为它永远不会被监视.

现在,您可以在视图控制器中捕获通知.在viewWillAppear中:

 override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(self.catchIt), name: NSNotification.Name(rawValue: "myNotif"), object: nil)
}
Run Code Online (Sandbox Code Playgroud)

现在你添加了这个观察者,每次在这个控制器中调用一个通知时,也会调用函数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)
    }
}
Run Code Online (Sandbox Code Playgroud)

离开视图控制器时不要忘记取消订阅通知,否则viewController(如果仍然在堆栈中)将捕获通知并执行它(你可能想要这样做,但知道你要进入什么更安全).所以我建议在viewWillDisappear中取消订阅:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.removeObserver(self)
}
Run Code Online (Sandbox Code Playgroud)

这样做,您将加载所需的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()
}
Run Code Online (Sandbox Code Playgroud)

现在,您已设置首选项,说明应用程序是使用远程通知启动的.在应该首先在应用程序中加载的控制器中,我建议在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])
    }
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.我还创建了一个github存储库来说明本地通知:本地通知观察者模式(类似于远程通知).可以使用根视图控制器本地通知根模式实现类似的逻辑,我个人认为它将取决于您要实现的内容.

  • 这个非常好的帖子做得很好,但有一件事我会避免使用NSUserDefaults().你可以在app delegate中设置rootViewController并在那里设置值.哦,请将prefs.removeObjectForKey("startUpNotification")修复为prefs.removeObjectForKey("startUpNotif"),因为这是你使用的密钥 (2认同)

Fre*_*ust 7

除了@ NickCatib的回答之外,要了解在应用程序运行时是否收到通知,如果是,在前台或后台,您需要在AppDelegate中使用此方法:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {


// You can determine your application state by
if UIApplication.sharedApplication().applicationState == UIApplicationState.Active {

// Do something you want when the app is active

} else {

// Do something else when your app is in the background


}
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*ash 5

当您运行应用程序时,您正在调用applicationDidLaunchWithOptions:

UIApplication.sharedApplication().registerUserNotificationSettings ( UIUserNotificationSettings(forTypes: (UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound), categories: nil))



if( launchOptions != nil){
    var notificationDict: AnyObject? = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey]
    if(notificationDict != nil){
        handleNotification(notificationDict! as! [NSObject : AnyObject])
    }

}
Run Code Online (Sandbox Code Playgroud)

在这里,你有handleNotification,这基本上是我的自定义函数,我从通知中提取数据并使用该信息来显示相应的控制器.

这是一个例子:

let notificationType = userInfo["aps"]!["alert"]!!["some-key-I-Need"]! as! String
var storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainViewController = storyboard.instantiateInitialViewController() as! MyViewController
self.window?.rootViewController  = mainViewController
Run Code Online (Sandbox Code Playgroud)