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

Push notification 控制在SWIFT中接收推送通知后加载哪个视图控制器,push-notification,apple-push-notifications,appdelegate,Push Notification,Apple Push Notifications,Appdelegate,一旦我收到推送通知并滑动打开它,它只会打开我的应用程序,而不是我想要的VC 所以我的问题是如何加载我想要的VC?我知道如果应用程序已打开,我会将VC移到DidReceivereMotentification中的另一个,但如果应用程序未打开,我该如何操作?或者它是否处于后台模式 另外,我有两个不同的推送通知,因此我需要它来移动两个不同VCs中的一个。如何区分不同推送动作之间的差异 谢谢。运行应用程序时,您正在使用选项调用ApplicationIDLaunch: UIApplication.shar

一旦我收到推送通知并滑动打开它,它只会打开我的应用程序,而不是我想要的VC

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

另外,我有两个不同的推送通知,因此我需要它来移动两个不同VCs中的一个。如何区分不同推送动作之间的差异


谢谢。

运行应用程序时,您正在使用选项调用ApplicationIDLaunch:

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])
    }

}
if let notification = launchOptions?[.remoteNotification] as? [AnyHashable : Any] {

            notificationsUserInfo = notification as [AnyHashable : Any]
            serveNotifications = true

        }
这里有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

除了@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


}
}

为Swift 4.2更新

如前所述,您希望在ApplicationIDLaunchWithOptions中注册远程通知:

 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()
}
当您从锁屏/后台返回时,无法知道您将在哪个viewController中。我要做的是从appDelegate发送通知。当您收到远程通知时,将调用appDelegate中的DidReceiveEmoteNotification

 func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    let notif = JSON(userInfo) // SwiftyJSON required 
根据您的通知负载,您应该首先确保它不是nil,然后调用一个NSNotification,该通知将由应捕获此通知的ViewController捕获。在这里,您还可以根据收到的负载发布不同类型的通知。可能是这样的,举个例子:

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)
    }
}
离开视图控制器时,不要忘记取消订阅通知,否则,如果仍在堆栈中,viewController将捕获通知并执行它(您可能希望这样做,但更安全的是知道您将进入什么)。因此,我建议在视图中取消订阅将消失:

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()
}
现在,您已经设置了一个首选项,表示应用程序是使用远程通知启动的。在应用程序中应首先加载的控制器中,我建议在ViewDidDisplay中执行以下操作:

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存储库,用本地通知进行说明:(类似于远程通知)。可以使用根视图控制器实现类似的逻辑,我个人认为这取决于您想要实现什么


这里的这些例子说明了如何简单地实现它。对于更大的项目,您将得到更复杂的体系结构,例如内部使用类似机制的协调器

我发现上面所有的答案都非常有用。然而,当应用程序被停用时,投票最多的人对我来说并不起作用。后来,a尝试实现@NickCatib和@TheFredeElement组合的答案,它们在执行情节提要时生成了一个错误。InstanceInitialViewController()-“无法强制转换类型为'UINavigationController'的值”。我发现发生这种情况是因为我有一个脚本文件,其中NavController作为rootViewController。为了解决这个问题,我创建了一个新的导航控制器,解决了一个问题:我丢失了应用程序的正确导航,视图甚至没有显示后退按钮。我的问题的答案是使用@NickCatib和@thefreedelement answers,但使用标识符实例化视图并将其推送,使用rootViewController作为UINavigationController,如下所示

let rootViewController = self.window?.rootViewController as! UINavigationController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mvc = storyboard.instantiateViewControllerWithIdentifier("MyViewController") as! 
             MyViewController
rootViewController.pushViewController(mvc, animated: true)

这对我来说很好,并且我没有丢失应用程序的正确导航属性。

补充了前面答案的信息。

根据您的状态,您可以更改逻辑。 在方法中,破产管理通知

func应用程序(应用程序:UIApplication,didReceiveMemotentification用户信息:[NSObject:AnyObject]){}

你可以做这样的切换

let state=UIApplication.sharedApplication().applicationState
开关状态{
案例UIApplicationState.Active:
案例UIApplicationState.Inactive:
案例UIApplicationState.背景:
}


根据应用程序的当前状态执行所需的操作。

最佳答案是Swift Rabbit

我要补充的是,当应用程序从关闭状态变为活动状态时,它仍然缺失

您可以将以下选项添加到AppDelegate中的didFinishedLaunchingWithOptions中:

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])
    }

}
if let notification = launchOptions?[.remoteNotification] as? [AnyHashable : Any] {

            notificationsUserInfo = notification as [AnyHashable : Any]
            serveNotifications = true

        }
您可以使用通知的值创建一个全局变量或userdefault,并使用一个标志让应用程序的其余部分知道存在通知

一旦mainViewController可见,您就可以执行操作来处理通知。