Это хорошо изношенный пост ... но в нем все еще отсутствует реальное решение проблемы (как указано в различных комментариях).
Первоначальный вопрос касается определения, когда приложение было запущено
/ открыто из push-уведомления, например, пользователь нажимает на уведомление. Ни один из ответов на самом деле не охватывает этот случай.
Причину можно увидеть в потоке вызовов, когда приходит уведомление, application:didReceiveRemoteNotification...
вызывается при получении уведомления И снова, когда уведомление прослушивается пользователем. Из-за этого вы не можете сказать, просто взглянув на UIApplicationState
то, нажал ли пользователь.
Кроме того, вам больше не нужно справляться с ситуацией «холодного старта» приложения в том application:didFinishLaunchingWithOptions...
виде, в каком он application:didReceiveRemoteNotification...
вызывается снова после запуска в iOS 9+ (возможно, и в 8).
Итак, как вы можете определить, что пользователь нажал на цепочку событий? Мое решение состоит в том, чтобы отметить время, когда приложение начинает выходить из фона или холодного запуска, а затем отметить это время application:didReceiveRemoteNotification...
. Если оно меньше 0,1 с, то вы можете быть уверены, что нажатие вызвало запуск.
Swift 2.x
class AppDelegate: UIResponder, UIApplicationDelegate {
var wakeTime : NSDate = NSDate() // when did our application wake up most recently?
func applicationWillEnterForeground(application: UIApplication) {
// time stamp the entering of foreground so we can tell how we got here
wakeTime = NSDate()
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
// ensure the userInfo dictionary has the data you expect
if let type = userInfo["type"] as? String where type == "status" {
// IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
if application.applicationState != UIApplicationState.Background && NSDate().timeIntervalSinceDate(wakeTime) < 0.1 {
// User Tap on notification Started the App
}
else {
// DO stuff here if you ONLY want it to happen when the push arrives
}
completionHandler(.NewData)
}
else {
completionHandler(.NoData)
}
}
}
Swift 3
class AppDelegate: UIResponder, UIApplicationDelegate {
var wakeTime : Date = Date() // when did our application wake up most recently?
func applicationWillEnterForeground(_ application: UIApplication) {
// time stamp the entering of foreground so we can tell how we got here
wakeTime = Date()
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// ensure the userInfo dictionary has the data you expect
if let type = userInfo["type"] as? String, type == "status" {
// IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
if application.applicationState != UIApplicationState.background && Date().timeIntervalSince(wakeTime) < 0.1 {
// User Tap on notification Started the App
}
else {
// DO stuff here if you ONLY want it to happen when the push arrives
}
completionHandler(.newData)
}
else {
completionHandler(.noData)
}
}
}
Я проверил это для обоих случаев (приложение в фоновом режиме, приложение не запущено) на iOS 9+, и оно работает как шарм. 0,1 с тоже довольно консервативно, фактическое значение ~ 0,002 с, поэтому 0,01 тоже хорошо.