一旦我收到推送通知并轻扫以打开它,它就会打开我的应用而不是我想要的VC。
所以我的问题是如何加载我想要的VC?我知道如果应用程序处于打开状态,我会将VC移到didReceiveRemoteNotification
内的另一个应用程序,但如果应用程序未打开,我该怎么做?或者它是否处于后台模式?
此外,我有两个不同的推送通知,因此我需要它来移动两个不同的VC中的一个。如何判断不同推送通知之间的区别?
感谢。
答案 0 :(得分:46)
针对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,然后调用将捕获此通知的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 :
}
例如,如果您收到消息通知并且由于令牌已过期而您尚未登录,则通知将永远不会在视图控制器中捕获,因为它永远不会被监视。
现在,您可以在视图控制器中捕获通知。在viewWillAppear中:
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(如果仍在堆栈中)将捕获通知并执行它(你可能想要这样做,但知道你更安全是更安全的正在进入)。所以我建议取消订阅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(类似于远程通知)。可以使用根视图Controller Local Notifications Root Pattern实现类似的逻辑,我个人认为它将取决于您要实现的内容。
这些例子用于说明如何简单实施。对于更大的项目,您将最终得到更复杂的架构,例如内部使用类似机制的协调器。
答案 1 :(得分: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
}
}
答案 2 :(得分: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])
}
}
在这里,你有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
答案 3 :(得分:2)
我发现上面的所有答案都非常有用。然而,当应用程序停用时,投票最多的人对我没有用。后来尝试将@NickCatib和@thefredelement的答案结合起来,并在执行storyboard.instantiateInitialViewController()时生成错误。"无法转换类型' UINavigationController'"的值。我发现这是因为我有一个带有NavController的storyboard文件作为rootViewController。为了解决这个问题,我创建了一个新的导航控制器,它解决了一个问题:我丢失了应用程序的正确导航,并且视图甚至没有显示后退按钮。我的问题的答案是使用@NickCatib和@thefredelement答案,但是使用标识符实例化视图并使用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)
这对我来说很好,我没有丢失应用程序的正确导航属性。
答案 4 :(得分:0)
以前答案的补充信息。
根据您的状态,您可以更改逻辑。 在方法 didReceiveRemoteNotification :
中 def update
@material.update_attribute(:attr_one, 'Atom')
@material.save(validate: false)
@material.update_attribute(:attr_two, 'Sublime')
@material.save(validate: true)
end
你可以像这样做一个开关
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {}
根据应用所处的当前状态执行您想要的操作。
答案 5 :(得分:0)
Swift Rabbit的答案是最好的。
我想补充说,当应用程序关闭到活动状态时,它仍然缺失。
您可以在appDelegate中添加didFinishedLaunchingWithOptions:
if let notification = launchOptions?[.remoteNotification] as? [AnyHashable : Any] {
notificationsUserInfo = notification as [AnyHashable : Any]
serveNotifications = true
}
您可以使用通知值创建全局变量或userdefault,并使用标志让应用程序的其余部分发出通知。
一旦mainViewController可见,您就可以执行操作来处理通知。
override func viewDidAppear(_ animated: Bool) {
if serveNotifications {
notificationManager.sharedInstance.processNotification(userInfo: notificationsUserInfo)
serveNotifications = false
}
}
小心。