检测app是否从推送通知中启动/打开。

时间:2022-09-11 20:50:48

Is it possible to know if the app was launched/opened from a push notification?

是否有可能知道该应用程序是从推送通知中启动/打开的?

I guess the launching event can be caught here:

我想发布会可以在这里看到:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    if (launchOptions != nil) {
         // Launched from push notification
         NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    }
}

However, how can I detect it was opened from a push notification when the app was in background?

但是,当应用程序处于后台时,如何通过推送通知检测它被打开?

23 个解决方案

#1


170  

See This code :

看到这段代码:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground  )
    {
         //opened from a push notification when the app was on background
    }
}

same as

一样

-(void)application:(UIApplication *)application didReceiveLocalNotification (UILocalNotification *)notification

#2


109  

late but maybe useful

晚但也许有用

When app is not running

当app不运行时

  • (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  • UIApplication(BOOL)应用程序:(*)应用didFinishLaunchingWithOptions:launchOptions(NSDictionary *)

is called ..

叫. .

where u need to check for push notification

你需要在哪里检查推送通知

NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
    NSLog(@"app recieved notification from remote%@",notification);
    [self application:application didReceiveRemoteNotification:notification];
} else {
    NSLog(@"app did not recieve notification");
}

#3


20  

This is a well worn post... but it is still missing an actual solution to the problem (as is pointed out in the various comments).

这是一个很旧的帖子……但是它仍然缺少一个实际的问题解决方案(正如各种评论指出的那样)。

The original question is about detecting when the app was launched / opened from a push notification, e.g. a user taps on the notification. None of the answers actually cover this case.

最初的问题是关于检测应用程序何时从推送通知中启动/打开,例如用户点击通知。实际上,没有一个答案涉及到这个问题。

The reason can be seen in the call flow when a notification arrives, application:didReceiveRemoteNotification...

原因可以在通知到达时的调用流中看到,应用:didReceiveRemoteNotification…

gets called when the notification is received AND again when the notification is tapped by the user. Because of this, you can't tell by just looking at UIApplicationState wether the user tapped it.

当收到通知时调用,当用户轻击通知时再次调用。正因为如此,你不能只看用户是否点击了UIApplicationState。

Additionally, you no longer need to handle the situation of a 'cold start' of the app in application:didFinishLaunchingWithOptions... as application:didReceiveRemoteNotification... is called again after launching in iOS 9+ (maybe 8 as well).

此外,您不再需要处理应用程序“冷启动”的情况:didFinishLaunchingWithOptions…随着应用程序:didReceiveRemoteNotification…在iOS 9+(也可能是8)启动后再次调用。

So, how can you tell if the user tap started the chain of events? My solution is to mark the time at which the app begins to come out of the background or cold start and then check that time in application:didReceiveRemoteNotification.... If it is less than 0.1s, then you can be pretty sure the tap triggered the startup.

那么,如何判断用户点击是否启动了事件链?我的解决方案是马克的时间应用程序开始的背景或冷启动应用程序然后检查时间:didReceiveRemoteNotification ....如果它小于0.1s,那么您可以非常确定是点击触发了启动。

Swift 2.x

快2.倍

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

斯威夫特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)
      }
    }
}

I have tested this for both cases (app in background, app not running) on iOS 9+ and it works like a charm. 0.1s is pretty conservative too, the actual value is ~0.002s so 0.01 is fine as well.

我在ios9 +上测试过这两种情况(后台的应用程序,不运行的应用程序),它运行起来很有魅力。0。1也很保守,实际值是0。002s所以0。01也可以。

#4


17  

Swift 2.0 For 'Not Running' State (Local & Remote Notification)

Swift 2.0用于“不运行”状态(本地和远程通知)

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {


// Handle notification
if (launchOptions != nil) {

    // For local Notification
    if let localNotificationInfo = launchOptions?[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {

        if let something = localNotificationInfo.userInfo!["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }


    } else

    // For remote Notification
    if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as! [NSObject : AnyObject]? {

        if let something = remoteNotification["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }
    }

}


return true

}

}

#5


17  

The issue we had was in correctly updating the view after the app is launched. There are complicated sequences of lifecycle methods here that get confusing.

我们遇到的问题是在应用启动后正确更新视图。这里有复杂的生命周期方法序列,让人感到困惑。

Lifecycle Methods

生命周期方法

Our testing for iOS 10 revealed the following sequences of lifecycle methods for the various cases:

我们对ios10的测试揭示了不同情况下的生命周期方法序列:

DELEGATE METHODS CALLED WHEN OPENING APP  

Opening app when system killed or user killed  
    didFinishLaunchingWithOptions  
    applicationDidBecomeActive    

Opening app when backgrounded  
    applicationWillEnterForeground  
    applicationDidBecomeActive  

DELEGATE METHODS WHEN OPENING PUSH

Opening push when system killed
    [receiving push causes didFinishLaunchingWithOptions (with options) and didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

Opening push when user killed
    didFinishLaunchingWithOptions (with options)
    didReceiveRemoteNotification:inactive [only completionHandler version]
    applicationDidBecomeActive

Opening push when backgrounded
    [receiving push causes didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

The problem

这个问题

Ok, so now we need to:

现在我们需要:

  1. Determine if the user is opening the app from a push
  2. 确定用户是否从push中打开应用程序
  3. Update the view based on the push state
  4. 基于push状态更新视图
  5. Clear the state so that subsequent opens don't return the user to the same position.
  6. 清除状态,以便后续打开不会将用户返回到相同的位置。

The tricky bit is that updating the view has to happen when the application actually becomes active, which is the same lifecycle method in all cases.

棘手的一点是,当应用程序实际成为活动时,必须更新视图,这在所有情况下都是相同的生命周期方法。

Sketch of our solution

我们的解决方案的草图

Here are the main components of our solution:

以下是我们解决方案的主要组成部分:

  1. Store a notificationUserInfo instance variable on the AppDelegate.
  2. 在AppDelegate上存储notificationUserInfo实例变量。
  3. Set notificationUserInfo = nil in both applicationWillEnterForeground and didFinishLaunchingWithOptions.
  4. 在applicationwillenter前台和didFinishLaunchingWithOptions中设置notificationUserInfo = nil。
  5. Set notificationUserInfo = userInfo in didReceiveRemoteNotification:inactive
  6. 在didReceiveRemoteNotification中设置notificationUserInfo = userInfo:不活动
  7. From applicationDidBecomeActive always call a custom method openViewFromNotification and pass self.notificationUserInfo. If self.notificationUserInfo is nil then return early, otherwise open the view based on the notification state found in self.notificationUserInfo.
  8. 从applicationDidBecomeActive始终调用自定义方法openViewFromNotification并传递self.notificationUserInfo。如果自我。notificationUserInfo是nil然后提前返回,否则根据self.notificationUserInfo中发现的通知状态打开视图。

Explanation

解释

When opening from a push didFinishLaunchingWithOptions or applicationWillEnterForeground is always called immediately before didReceiveRemoteNotification:inactive, so we first reset notificationUserInfo in these methods so there's no stale state. Then, if didReceiveRemoteNotification:inactive is called we know we're opening from a push so we set self.notificationUserInfo which is then picked up by applicationDidBecomeActive to forward the user to the right view.

当从didFinishLaunchingWithOptions或applicationwillenter前台打开时,总是在didReceiveRemoteNotification之前立即调用:非活动的,所以我们首先在这些方法中重置notificationUserInfo,这样就不会有不稳定的状态。然后,如果didReceiveRemoteNotification:不活动被称为我们知道我们从推中打开,所以我们设置self。notificationUserInfo后,applicationDidBecomeActive将用户转发到正确的视图。

There is one final case which is if the user has the app open within the app switcher (i.e. by double tapping the home button while the app is in the foreground) and then receives a push notification. In this case only didReceiveRemoteNotification:inactive is called, and neither WillEnterForeground nor didFinishLaunching gets called so you need some special state to handle that case.

最后一种情况是,如果用户让应用程序在应用切换器中打开(即当应用程序在前台时双击home按钮),然后接收到推送通知。在这种情况下,只调用didReceiveRemoteNotification:不调用inactive,不调用willenter前台和didFinishLaunching,所以您需要一些特殊的状态来处理这个情况。

Hope this helps.

希望这个有帮助。

#6


14  

In application:didReceiveRemoteNotification: check whether you have received the notification when your app is in the foreground or background.

应用:didReceiveRemoteNotification:检查你的应用在前台或后台时你是否收到通知。

If it was received in the background, launch the app from the notification.

如果是在后台接收,则从通知启动app。

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        NSLog(@"Notification received by running app");
    } else {
        NSLog(@"App opened from Notification");
    }
}

#7


11  

When app is terminated, and user taps on push notification

当app终止时,用户点击推送通知

public func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
   if launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] != nil {
      print("from push")
    }
}

When app is in background, and user taps on push notificaion

当app在后台时,用户点击按钮notificaion

If the user opens your app from the system-displayed alert, the system may call this method again when your app is about to enter the foreground so that you can update your user interface and display information pertaining to the notification.

如果用户从系统显示的警报打开您的应用程序,系统可能会在您的应用程序即将进入前台时再次调用此方法,以便您可以更新您的用户界面并显示有关通知的信息。

public func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
  if application.applicationState == .Inactive {
    print("from push")
  }
}

Depending on your app, it can also send you silent push with content-available inside aps, so be aware of this as well :) See https://*.com/a/33778990/1418457

根据您的应用程序,它还可以通过aps中的内容向您发送静默推送,所以请注意:)参见https://*.com/a/33778990/1418457

#8


9  

For swift:

迅速:

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

    if application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background {
        //opened from a push notification when the app was on background

    }

}

#9


3  

Yes, you can detect by this method in appDelegate:

是的,你可以用这个方法在appDelegate中检测到:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
      /* your Code*/
}

For local Notification:

为当地的通知:

- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
         /* your Code*/
}

#10


2  

if somebody wants the answer in swift 3

如果有人想要快速3的答案

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    switch application.applicationState {
    case .active:
        //app is currently active, can update badges count here
        break
    case .inactive:
        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here
        break
    case .background:
        //app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
        break
    default:
        break
    }
}

#11


1  

I'll start with a state chart that I created for my own use to visualize it more accurately and to consider all other states: https://docs.google.com/spreadsheets/d/e/2PACX-1vSdKOgo_F1TZwGJBAED4C_7cml0bEATqeL3P9UKpBwASlT6ZkU3iLdZnOZoevkMzOeng7gs31IFhD-L/pubhtml?gid=0&single=true

我将从一个我自己创建的状态图开始,以便更准确地可视化它,并考虑所有其他的状态:https://docs.google.com/spreadsheets/d/2pacx - 1vsdkogo_f1tzwgjbaed4c_7cml0beatqel3pbwaslt6zkmzoevkmzoevkmzoevkmzoevkmzoevkmzoevkmzoevkmzovs31ifhd - l/pubhtml?

Using this chart, we can see what is actually required in order to develop a robust notification handling system that works in almost all possible use cases.

使用这个图表,我们可以看到,为了开发一个健壮的通知处理系统,实际上需要什么,该系统可以在几乎所有可能的用例中工作。

Complete solution ↓

完整的解决方案↓

  • Store notification payload in didReceiveRemoteNotification
  • 在didReceiveRemoteNotification中存储通知有效负载。
  • Clear stored notification in applicationWillEnterForeground and didFinishLaunchingWithOptions
  • 清除applicationwillenter前台和didFinishLaunchingWithOptions中存储的通知
  • To tackle cases where control Center/ Notification center pulled, you can use a flag willResignActiveCalled and set it to false initially, Set this to true in applicationWillResignActive method,
  • 为了处理控制中心/通知中心拉出的情况,您可以使用一个标记willresignactivec并将其设置为false,在applicationWillResignActive方法中设置为true,
  • In didReceiveRemoteNotification method, save notifications(userInfo) only when willResignActiveCalled is false.
  • 在didReceiveRemoteNotification方法中,只有当被重新激活的用户名是假的时候才保存通知(userInfo)。
  • Reset willResignActiveCalled to false in applicationDidEnterBackground and applicationDidBecomeActive method.
  • 在applicationDidEnterBackground和applicationDidBecomeActive方法中,将重命名为false。

Note: A Similar answer is suggested in comments on Eric's answer, however, the state sheet helps in finding all possible scenarios as I did in my app.

注意:在Eric的回答的评论中也有类似的答案,但是状态表可以帮助我找到所有可能的场景,就像我在我的应用中所做的那样。

Please find the complete code below and comment below if any specific case is not handled:

如有特殊情况未处理,请参阅以下完整代码及评论:

AppDelegate

AppDelegate

class AppDelegate: UIResponder, UIApplicationDelegate {
  private var willResignActiveCalled = false

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    NotificationUtils.shared.notification = nil
    return true
  }
  func applicationWillResignActive(_ application: UIApplication) {
    willResignActiveCalled = true
  }
  func applicationDidEnterBackground(_ application: UIApplication) {
    willResignActiveCalled = false
  }
  func applicationWillEnterForeground(_ application: UIApplication) {
    NotificationUtils.shared.notification = nil
  }
  func applicationDidBecomeActive(_ application: UIApplication) {
    willResignActiveCalled = false
    NotificationUtils.shared.performActionOnNotification()
  }
  func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    if !willResignActiveCalled { // Check if app is in inactive by app switcher, control center, or notification center
      NotificationUtils.shared.handleNotification(userInfo: userInfo)
    }
  }
}

NotificationUtils : This is where you can write all your dirty code to navigating to different parts of the application, handling Databases(CoreData/Realm) and do all other stuff that needs to be done when a notification is received.

NotificationUtils:在这里,您可以编写所有脏代码,以导航到应用程序的不同部分,处理数据库(CoreData/Realm),并完成收到通知时需要完成的所有其他工作。

   class NotificationUtils {
  static let shared = NotificationUtils()
  private init() {}

  var notification : [AnyHashable: Any]?

  func handleNotification(userInfo : [AnyHashable: Any]){
    if UIApplication.shared.applicationState == UIApplicationState.active {
      self.notification = userInfo //Save Payload
      //Show inApp Alert/Banner/Action etc
      // perform immediate action on notification
    }
    else if UIApplication.shared.applicationState == UIApplicationState.inactive{
      self.notification = userInfo
    }
    else if UIApplication.shared.applicationState == UIApplicationState.background{
      //Process notification in background,
      // Update badges, save some data received from notification payload in Databases (CoreData/Realm)
    }
  }

  func performActionOnNotification(){
    // Do all the stuffs like navigating to ViewControllers, updating Badges etc
    defer {
      notification = nil
    }
  }
}

#12


0  

Straight from the documentation for

直接从文档中

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo:nil

If the app is running and receives a remote notification, the app calls this method to process the notification.

如果应用程序正在运行并接收远程通知,则应用程序调用此方法来处理通知。

Your implementation of this method should use the notification to take an appropriate course of action.

这个方法的实现应该使用通知来采取适当的行动。

And a little bit later

过了一会儿

If the app is not running when a push notification arrives, the method launches the app and provides the appropriate information in the launch options dictionary.

如果当推送通知到达时应用程序没有运行,该方法将启动应用程序并在启动选项字典中提供适当的信息。

The app does not call this method to handle that push notification.

应用程序不会调用这个方法来处理推送通知。

Instead, your implementation of the

相反,您的实现

application:willFinishLaunchingWithOptions:

or

application:didFinishLaunchingWithOptions:

method needs to get the push notification payload data and respond appropriately.

方法需要获取推送通知有效负载数据并作出适当响应。

#13


0  

You can use:

您可以使用:

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

to handle the remote push notifications.

处理远程推送通知。

Check here the documentation

检查下面的文档

#14


0  

I haven't tried it yet but maybe you could send yourself a notification? http://nshipster.com/nsnotification-and-nsnotificationcenter/

我还没试过,你可以给自己发个通知吗?http://nshipster.com/nsnotification-and-nsnotificationcenter/

#15


0  

     // shanegao's code in Swift 2.0
     func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
    {
            if ( application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background ){
                    print("opened from a push notification when the app was on background")
            }else{
                    print("opened from a push notification when the app was on foreground")
            }
    }

#16


0  

The problem with this question is that "opening" the app isn't well-defined. An app is either cold-launched from a not-running state, or it's reactivated from an inactive state (e.g. from switching back to it from another app). Here's my solution to distinguish all of these possible states:

这个问题的问题是“打开”应用程序并没有很好的定义。一个应用程序要么从非运行状态冷启动,要么从非活动状态重新激活(例如从另一个应用程序切换回)。我的解决方案是区分所有这些可能的状态:

typedef NS_ENUM(NSInteger, MXAppState) {
    MXAppStateActive = 0,
    MXAppStateReactivated = 1,
    MXAppStateLaunched = 2
};

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // ... your custom launch stuff
    [[MXDefaults instance] setDateOfLastLaunch:[NSDate date]];
    // ... more custom launch stuff
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // Through a lot of trial and error (by showing alerts), I can confirm that on iOS 10
    // this method is only called when the app has been launched from a push notification
    // or when the app is already in the Active state.  When you receive a push
    // and then launch the app from the icon or apps view, this method is _not_ called.
    // So with 99% confidence, it means this method is called in one of the 3 mutually exclusive cases
    //    1) we are active in the foreground, no action was taken by the user
    //    2) we were 'launched' from an inactive state (so we may already be in the main section) by a tap
    //       on a push notification
    //    3) we were truly launched from a not running state by a tap on a push notification
    // Beware that cases (2) and (3) may both show UIApplicationStateInactive and cant be easily distinguished.
    // We check the last launch date to distinguish (2) and (3).

    MXAppState appState = [self mxAppStateFromApplicationState:[application applicationState]];
    //... your app's logic
}

- (MXAppState)mxAppStateFromApplicationState:(UIApplicationState)state {
    if (state == UIApplicationStateActive) {
        return MXAppStateActive;
    } else {
        NSDate* lastLaunchDate = [[MXDefaults instance] dateOfLastLaunch];
        if (lastLaunchDate && [[NSDate date] timeIntervalSinceDate:lastLaunchDate] < 0.5f) {
            return MXAppStateLaunched;
        } else {
            return MXAppStateReactivated;
        }
    }
    return MXAppStateActive;
}

And MXDefaults is just a little wrapper for NSUserDefaults.

MXDefaults只是NSUserDefaults的一个小包装。

#17


0  

For swift

为迅速

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

    ++notificationNumber
    application.applicationIconBadgeNumber =  notificationNumber;

    if let aps = userInfo["aps"] as? NSDictionary {

        var message = aps["alert"]
        println("my messages : \(message)")

    }
}

#18


0  

When app is in background as shanegao you can use

当应用程序处于后台时,你可以使用它。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground  )
    {
         //opened from a push notification when the app was on background
    }
}

But if you want to launch the application and when app is closed and you want to debug your application you can go to Edit Scheme and in left menu select Run and then in launch select Wait for executable to be launched and then you application launch when you click on push notification

但如果你想启动应用程序时,应用程序关闭,您想要调试应用程序你可以去编辑方案和在发射选择左菜单选择Run然后等待执行启动,然后当你点击推送式通知应用程序启动

Edit Scheme > Run > Wait for executable to be launched

编辑方案>运行>等待可执行文件被启动

#19


0  

Swift 3.0

斯威夫特3.0

In AppDelegate, in the function 'didFinishLaunchingWithOptions' handle remote notification with some delay and open your Viewcontroller. You can use delay to handle notification after loading app successfully.

在AppDelegate中,在函数didFinishLaunchingWithOptions中,用一些延迟处理远程通知并打开视图控制器。成功加载app后,可以使用delay处理通知。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as! [NSObject : AnyObject]? {

            AppHelper.delay(0.8, closure: {
                self.handelNotification(dic: remoteNotification as! [String : Any])
            })
 }

#20


0  

Posting this for Xamarin users.

把这贴在Xamarin用户身上。

The key to detecting if the app was launched via a push notification is the AppDelegate.FinishedLaunching(UIApplication app, NSDictionary options) method, and the options dictionary that's passed in.

检测app是否通过推送通知启动的关键是AppDelegate。完成启动(UIApplication app, NSDictionary选项)方法,以及传入的选项字典。

The options dictionary will have this key in it if it's a local notification: UIApplication.LaunchOptionsLocalNotificationKey.

如果是本地通知,那么options字典将包含这个键:UIApplication.LaunchOptionsLocalNotificationKey。

If it's a remote notification, it will be UIApplication.LaunchOptionsRemoteNotificationKey.

如果是远程通知,它将是UIApplication.LaunchOptionsRemoteNotificationKey。

When the key is LaunchOptionsLocalNotificationKey, the object is of type UILocalNotification. You can then look at the notification and determine which specific notification it is.

当密钥是LaunchOptionsLocalNotificationKey时,对象是类型UILocalNotification。然后,您可以查看通知并确定它是哪个特定通知。

Pro-tip: UILocalNotification doesn't have an identifier in it, the same way UNNotificationRequest does. Put a dictionary key in the UserInfo containing a requestId so that when testing the UILocalNotification, you'll have a specific requestId available to base some logic on.

支持提示:UILocalNotification没有标识符,就像UNNotificationRequest一样。在包含requestId的UserInfo中放置一个dictionary键,以便在测试UILocalNotification时,您可以使用一个特定的requestId作为一些逻辑的基础。

I found that even on iOS 10+ devices that when creating location notifications using the UNUserNotificationCenter's AddNotificationRequest & UNMutableNotificationContent, that when the app is not running(I killed it), and is launched by tapping the notification in the notification center, that the dictionary still contains the UILocalNotificaiton object.

我发现,即使是在ios10 +设备上,当使用UNUserNotificationCenter的AddNotificationRequest & UNMutableNotificationContent创建位置通知时,当应用程序没有运行(我杀死了它)并通过点击通知中心的通知启动时,字典仍然包含uinotificaiton对象。

This means that my code that checks for notification based launch will work on iOS8 and iOS 10+ devices

这意味着我检查基于通知的启动的代码将适用于iOS8和ios10 +设备

public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
    _logger.InfoFormat("FinishedLaunching");

    if(options != null)
    {
        if (options.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
        {
            //was started by tapping a local notification when app wasn't previously running.
            //works if using UNUserNotificationCenter.Current.AddNotificationRequest OR UIApplication.SharedApplication.PresentLocalNotificationNow);

            var localNotification = options[UIApplication.LaunchOptionsLocalNotificationKey] as UILocalNotification;

            //I would recommended a key such as this :
            var requestId = localNotification.UserInfo["RequestId"].ToString();
        }               
    }
    return true;
}

#21


0  

func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
    print("Push notification received: \(data)")

    if let info = data["aps"] as? Dictionary<String, AnyObject> {
        let alertMsg = info["alert"] as! String
        print(alertMsg)
        switch application.applicationState {
        case .active:
            print("do stuff in case App is active")
        case .background:
            print("do stuff in case App is in background")
           // navigateToChatDetailViewControler(pushdata: data)
        case .inactive:
            print("do stuff in case App is inactive")
            // navigateToChatDetailViewControler(pushdata: data)
        }
    }
}

#22


-1  

For Swift Users:

快速用户:

If you want to launch a different page on opening from push or something like that, you need to check it in didFinishLaunchingWithOptions like:

如果你想从push或类似的东西开始打开一个不同的页面,你需要在didFinishLaunchingWithOptions中检查它,比如:

let directVc: directVC! = directVC(nibName:"directVC", bundle: nil)
let pushVc: pushVC! = pushVC(nibName:"pushVC", bundle: nil)

if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
     self.navigationController = UINavigationController(rootViewController: pushVc!)
} else {
     self.navigationController = UINavigationController(rootViewController: directVc!)
}
self.window!.rootViewController = self.navigationController

#23


-1  

IN SWIFT:

迅速:

I'm running Push Notifications (with background fetching). When my app is in the background and I receive a push notification, I found that didReceiveRemoteNotification in appDelegate would be called twice; once for when notification is received and another when user clicks on the notification alert.

我正在运行推送通知(后台取回)。当我的app在后台,我收到推送通知时,我发现appDelegate中的didReceiveRemoteNotification会调用两次;一次用于接收通知,另一次用于用户单击通知警报。

To detect if notification alert was clicked, just check if applicationState raw value == 1 inside didReceiveRemoteNotification in appDelegate.

要检测是否单击了通知警报,只需检查appDelegate中didReceiveRemoteNotification中应用程序状态原始值是否= 1。

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject: AnyObject]) {
    // If not from alert click applicationState(1)
    if (application.applicationState.rawValue != 1) {
        // Run your code here
    }
}

I hope this helps.

我希望这可以帮助。

#1


170  

See This code :

看到这段代码:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground  )
    {
         //opened from a push notification when the app was on background
    }
}

same as

一样

-(void)application:(UIApplication *)application didReceiveLocalNotification (UILocalNotification *)notification

#2


109  

late but maybe useful

晚但也许有用

When app is not running

当app不运行时

  • (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  • UIApplication(BOOL)应用程序:(*)应用didFinishLaunchingWithOptions:launchOptions(NSDictionary *)

is called ..

叫. .

where u need to check for push notification

你需要在哪里检查推送通知

NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
    NSLog(@"app recieved notification from remote%@",notification);
    [self application:application didReceiveRemoteNotification:notification];
} else {
    NSLog(@"app did not recieve notification");
}

#3


20  

This is a well worn post... but it is still missing an actual solution to the problem (as is pointed out in the various comments).

这是一个很旧的帖子……但是它仍然缺少一个实际的问题解决方案(正如各种评论指出的那样)。

The original question is about detecting when the app was launched / opened from a push notification, e.g. a user taps on the notification. None of the answers actually cover this case.

最初的问题是关于检测应用程序何时从推送通知中启动/打开,例如用户点击通知。实际上,没有一个答案涉及到这个问题。

The reason can be seen in the call flow when a notification arrives, application:didReceiveRemoteNotification...

原因可以在通知到达时的调用流中看到,应用:didReceiveRemoteNotification…

gets called when the notification is received AND again when the notification is tapped by the user. Because of this, you can't tell by just looking at UIApplicationState wether the user tapped it.

当收到通知时调用,当用户轻击通知时再次调用。正因为如此,你不能只看用户是否点击了UIApplicationState。

Additionally, you no longer need to handle the situation of a 'cold start' of the app in application:didFinishLaunchingWithOptions... as application:didReceiveRemoteNotification... is called again after launching in iOS 9+ (maybe 8 as well).

此外,您不再需要处理应用程序“冷启动”的情况:didFinishLaunchingWithOptions…随着应用程序:didReceiveRemoteNotification…在iOS 9+(也可能是8)启动后再次调用。

So, how can you tell if the user tap started the chain of events? My solution is to mark the time at which the app begins to come out of the background or cold start and then check that time in application:didReceiveRemoteNotification.... If it is less than 0.1s, then you can be pretty sure the tap triggered the startup.

那么,如何判断用户点击是否启动了事件链?我的解决方案是马克的时间应用程序开始的背景或冷启动应用程序然后检查时间:didReceiveRemoteNotification ....如果它小于0.1s,那么您可以非常确定是点击触发了启动。

Swift 2.x

快2.倍

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

斯威夫特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)
      }
    }
}

I have tested this for both cases (app in background, app not running) on iOS 9+ and it works like a charm. 0.1s is pretty conservative too, the actual value is ~0.002s so 0.01 is fine as well.

我在ios9 +上测试过这两种情况(后台的应用程序,不运行的应用程序),它运行起来很有魅力。0。1也很保守,实际值是0。002s所以0。01也可以。

#4


17  

Swift 2.0 For 'Not Running' State (Local & Remote Notification)

Swift 2.0用于“不运行”状态(本地和远程通知)

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {


// Handle notification
if (launchOptions != nil) {

    // For local Notification
    if let localNotificationInfo = launchOptions?[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {

        if let something = localNotificationInfo.userInfo!["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }


    } else

    // For remote Notification
    if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as! [NSObject : AnyObject]? {

        if let something = remoteNotification["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }
    }

}


return true

}

}

#5


17  

The issue we had was in correctly updating the view after the app is launched. There are complicated sequences of lifecycle methods here that get confusing.

我们遇到的问题是在应用启动后正确更新视图。这里有复杂的生命周期方法序列,让人感到困惑。

Lifecycle Methods

生命周期方法

Our testing for iOS 10 revealed the following sequences of lifecycle methods for the various cases:

我们对ios10的测试揭示了不同情况下的生命周期方法序列:

DELEGATE METHODS CALLED WHEN OPENING APP  

Opening app when system killed or user killed  
    didFinishLaunchingWithOptions  
    applicationDidBecomeActive    

Opening app when backgrounded  
    applicationWillEnterForeground  
    applicationDidBecomeActive  

DELEGATE METHODS WHEN OPENING PUSH

Opening push when system killed
    [receiving push causes didFinishLaunchingWithOptions (with options) and didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

Opening push when user killed
    didFinishLaunchingWithOptions (with options)
    didReceiveRemoteNotification:inactive [only completionHandler version]
    applicationDidBecomeActive

Opening push when backgrounded
    [receiving push causes didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

The problem

这个问题

Ok, so now we need to:

现在我们需要:

  1. Determine if the user is opening the app from a push
  2. 确定用户是否从push中打开应用程序
  3. Update the view based on the push state
  4. 基于push状态更新视图
  5. Clear the state so that subsequent opens don't return the user to the same position.
  6. 清除状态,以便后续打开不会将用户返回到相同的位置。

The tricky bit is that updating the view has to happen when the application actually becomes active, which is the same lifecycle method in all cases.

棘手的一点是,当应用程序实际成为活动时,必须更新视图,这在所有情况下都是相同的生命周期方法。

Sketch of our solution

我们的解决方案的草图

Here are the main components of our solution:

以下是我们解决方案的主要组成部分:

  1. Store a notificationUserInfo instance variable on the AppDelegate.
  2. 在AppDelegate上存储notificationUserInfo实例变量。
  3. Set notificationUserInfo = nil in both applicationWillEnterForeground and didFinishLaunchingWithOptions.
  4. 在applicationwillenter前台和didFinishLaunchingWithOptions中设置notificationUserInfo = nil。
  5. Set notificationUserInfo = userInfo in didReceiveRemoteNotification:inactive
  6. 在didReceiveRemoteNotification中设置notificationUserInfo = userInfo:不活动
  7. From applicationDidBecomeActive always call a custom method openViewFromNotification and pass self.notificationUserInfo. If self.notificationUserInfo is nil then return early, otherwise open the view based on the notification state found in self.notificationUserInfo.
  8. 从applicationDidBecomeActive始终调用自定义方法openViewFromNotification并传递self.notificationUserInfo。如果自我。notificationUserInfo是nil然后提前返回,否则根据self.notificationUserInfo中发现的通知状态打开视图。

Explanation

解释

When opening from a push didFinishLaunchingWithOptions or applicationWillEnterForeground is always called immediately before didReceiveRemoteNotification:inactive, so we first reset notificationUserInfo in these methods so there's no stale state. Then, if didReceiveRemoteNotification:inactive is called we know we're opening from a push so we set self.notificationUserInfo which is then picked up by applicationDidBecomeActive to forward the user to the right view.

当从didFinishLaunchingWithOptions或applicationwillenter前台打开时,总是在didReceiveRemoteNotification之前立即调用:非活动的,所以我们首先在这些方法中重置notificationUserInfo,这样就不会有不稳定的状态。然后,如果didReceiveRemoteNotification:不活动被称为我们知道我们从推中打开,所以我们设置self。notificationUserInfo后,applicationDidBecomeActive将用户转发到正确的视图。

There is one final case which is if the user has the app open within the app switcher (i.e. by double tapping the home button while the app is in the foreground) and then receives a push notification. In this case only didReceiveRemoteNotification:inactive is called, and neither WillEnterForeground nor didFinishLaunching gets called so you need some special state to handle that case.

最后一种情况是,如果用户让应用程序在应用切换器中打开(即当应用程序在前台时双击home按钮),然后接收到推送通知。在这种情况下,只调用didReceiveRemoteNotification:不调用inactive,不调用willenter前台和didFinishLaunching,所以您需要一些特殊的状态来处理这个情况。

Hope this helps.

希望这个有帮助。

#6


14  

In application:didReceiveRemoteNotification: check whether you have received the notification when your app is in the foreground or background.

应用:didReceiveRemoteNotification:检查你的应用在前台或后台时你是否收到通知。

If it was received in the background, launch the app from the notification.

如果是在后台接收,则从通知启动app。

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        NSLog(@"Notification received by running app");
    } else {
        NSLog(@"App opened from Notification");
    }
}

#7


11  

When app is terminated, and user taps on push notification

当app终止时,用户点击推送通知

public func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
   if launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] != nil {
      print("from push")
    }
}

When app is in background, and user taps on push notificaion

当app在后台时,用户点击按钮notificaion

If the user opens your app from the system-displayed alert, the system may call this method again when your app is about to enter the foreground so that you can update your user interface and display information pertaining to the notification.

如果用户从系统显示的警报打开您的应用程序,系统可能会在您的应用程序即将进入前台时再次调用此方法,以便您可以更新您的用户界面并显示有关通知的信息。

public func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
  if application.applicationState == .Inactive {
    print("from push")
  }
}

Depending on your app, it can also send you silent push with content-available inside aps, so be aware of this as well :) See https://*.com/a/33778990/1418457

根据您的应用程序,它还可以通过aps中的内容向您发送静默推送,所以请注意:)参见https://*.com/a/33778990/1418457

#8


9  

For swift:

迅速:

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

    if application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background {
        //opened from a push notification when the app was on background

    }

}

#9


3  

Yes, you can detect by this method in appDelegate:

是的,你可以用这个方法在appDelegate中检测到:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
      /* your Code*/
}

For local Notification:

为当地的通知:

- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
         /* your Code*/
}

#10


2  

if somebody wants the answer in swift 3

如果有人想要快速3的答案

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    switch application.applicationState {
    case .active:
        //app is currently active, can update badges count here
        break
    case .inactive:
        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here
        break
    case .background:
        //app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
        break
    default:
        break
    }
}

#11


1  

I'll start with a state chart that I created for my own use to visualize it more accurately and to consider all other states: https://docs.google.com/spreadsheets/d/e/2PACX-1vSdKOgo_F1TZwGJBAED4C_7cml0bEATqeL3P9UKpBwASlT6ZkU3iLdZnOZoevkMzOeng7gs31IFhD-L/pubhtml?gid=0&single=true

我将从一个我自己创建的状态图开始,以便更准确地可视化它,并考虑所有其他的状态:https://docs.google.com/spreadsheets/d/2pacx - 1vsdkogo_f1tzwgjbaed4c_7cml0beatqel3pbwaslt6zkmzoevkmzoevkmzoevkmzoevkmzoevkmzoevkmzoevkmzovs31ifhd - l/pubhtml?

Using this chart, we can see what is actually required in order to develop a robust notification handling system that works in almost all possible use cases.

使用这个图表,我们可以看到,为了开发一个健壮的通知处理系统,实际上需要什么,该系统可以在几乎所有可能的用例中工作。

Complete solution ↓

完整的解决方案↓

  • Store notification payload in didReceiveRemoteNotification
  • 在didReceiveRemoteNotification中存储通知有效负载。
  • Clear stored notification in applicationWillEnterForeground and didFinishLaunchingWithOptions
  • 清除applicationwillenter前台和didFinishLaunchingWithOptions中存储的通知
  • To tackle cases where control Center/ Notification center pulled, you can use a flag willResignActiveCalled and set it to false initially, Set this to true in applicationWillResignActive method,
  • 为了处理控制中心/通知中心拉出的情况,您可以使用一个标记willresignactivec并将其设置为false,在applicationWillResignActive方法中设置为true,
  • In didReceiveRemoteNotification method, save notifications(userInfo) only when willResignActiveCalled is false.
  • 在didReceiveRemoteNotification方法中,只有当被重新激活的用户名是假的时候才保存通知(userInfo)。
  • Reset willResignActiveCalled to false in applicationDidEnterBackground and applicationDidBecomeActive method.
  • 在applicationDidEnterBackground和applicationDidBecomeActive方法中,将重命名为false。

Note: A Similar answer is suggested in comments on Eric's answer, however, the state sheet helps in finding all possible scenarios as I did in my app.

注意:在Eric的回答的评论中也有类似的答案,但是状态表可以帮助我找到所有可能的场景,就像我在我的应用中所做的那样。

Please find the complete code below and comment below if any specific case is not handled:

如有特殊情况未处理,请参阅以下完整代码及评论:

AppDelegate

AppDelegate

class AppDelegate: UIResponder, UIApplicationDelegate {
  private var willResignActiveCalled = false

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    NotificationUtils.shared.notification = nil
    return true
  }
  func applicationWillResignActive(_ application: UIApplication) {
    willResignActiveCalled = true
  }
  func applicationDidEnterBackground(_ application: UIApplication) {
    willResignActiveCalled = false
  }
  func applicationWillEnterForeground(_ application: UIApplication) {
    NotificationUtils.shared.notification = nil
  }
  func applicationDidBecomeActive(_ application: UIApplication) {
    willResignActiveCalled = false
    NotificationUtils.shared.performActionOnNotification()
  }
  func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    if !willResignActiveCalled { // Check if app is in inactive by app switcher, control center, or notification center
      NotificationUtils.shared.handleNotification(userInfo: userInfo)
    }
  }
}

NotificationUtils : This is where you can write all your dirty code to navigating to different parts of the application, handling Databases(CoreData/Realm) and do all other stuff that needs to be done when a notification is received.

NotificationUtils:在这里,您可以编写所有脏代码,以导航到应用程序的不同部分,处理数据库(CoreData/Realm),并完成收到通知时需要完成的所有其他工作。

   class NotificationUtils {
  static let shared = NotificationUtils()
  private init() {}

  var notification : [AnyHashable: Any]?

  func handleNotification(userInfo : [AnyHashable: Any]){
    if UIApplication.shared.applicationState == UIApplicationState.active {
      self.notification = userInfo //Save Payload
      //Show inApp Alert/Banner/Action etc
      // perform immediate action on notification
    }
    else if UIApplication.shared.applicationState == UIApplicationState.inactive{
      self.notification = userInfo
    }
    else if UIApplication.shared.applicationState == UIApplicationState.background{
      //Process notification in background,
      // Update badges, save some data received from notification payload in Databases (CoreData/Realm)
    }
  }

  func performActionOnNotification(){
    // Do all the stuffs like navigating to ViewControllers, updating Badges etc
    defer {
      notification = nil
    }
  }
}

#12


0  

Straight from the documentation for

直接从文档中

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo:nil

If the app is running and receives a remote notification, the app calls this method to process the notification.

如果应用程序正在运行并接收远程通知,则应用程序调用此方法来处理通知。

Your implementation of this method should use the notification to take an appropriate course of action.

这个方法的实现应该使用通知来采取适当的行动。

And a little bit later

过了一会儿

If the app is not running when a push notification arrives, the method launches the app and provides the appropriate information in the launch options dictionary.

如果当推送通知到达时应用程序没有运行,该方法将启动应用程序并在启动选项字典中提供适当的信息。

The app does not call this method to handle that push notification.

应用程序不会调用这个方法来处理推送通知。

Instead, your implementation of the

相反,您的实现

application:willFinishLaunchingWithOptions:

or

application:didFinishLaunchingWithOptions:

method needs to get the push notification payload data and respond appropriately.

方法需要获取推送通知有效负载数据并作出适当响应。

#13


0  

You can use:

您可以使用:

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

to handle the remote push notifications.

处理远程推送通知。

Check here the documentation

检查下面的文档

#14


0  

I haven't tried it yet but maybe you could send yourself a notification? http://nshipster.com/nsnotification-and-nsnotificationcenter/

我还没试过,你可以给自己发个通知吗?http://nshipster.com/nsnotification-and-nsnotificationcenter/

#15


0  

     // shanegao's code in Swift 2.0
     func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
    {
            if ( application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background ){
                    print("opened from a push notification when the app was on background")
            }else{
                    print("opened from a push notification when the app was on foreground")
            }
    }

#16


0  

The problem with this question is that "opening" the app isn't well-defined. An app is either cold-launched from a not-running state, or it's reactivated from an inactive state (e.g. from switching back to it from another app). Here's my solution to distinguish all of these possible states:

这个问题的问题是“打开”应用程序并没有很好的定义。一个应用程序要么从非运行状态冷启动,要么从非活动状态重新激活(例如从另一个应用程序切换回)。我的解决方案是区分所有这些可能的状态:

typedef NS_ENUM(NSInteger, MXAppState) {
    MXAppStateActive = 0,
    MXAppStateReactivated = 1,
    MXAppStateLaunched = 2
};

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // ... your custom launch stuff
    [[MXDefaults instance] setDateOfLastLaunch:[NSDate date]];
    // ... more custom launch stuff
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // Through a lot of trial and error (by showing alerts), I can confirm that on iOS 10
    // this method is only called when the app has been launched from a push notification
    // or when the app is already in the Active state.  When you receive a push
    // and then launch the app from the icon or apps view, this method is _not_ called.
    // So with 99% confidence, it means this method is called in one of the 3 mutually exclusive cases
    //    1) we are active in the foreground, no action was taken by the user
    //    2) we were 'launched' from an inactive state (so we may already be in the main section) by a tap
    //       on a push notification
    //    3) we were truly launched from a not running state by a tap on a push notification
    // Beware that cases (2) and (3) may both show UIApplicationStateInactive and cant be easily distinguished.
    // We check the last launch date to distinguish (2) and (3).

    MXAppState appState = [self mxAppStateFromApplicationState:[application applicationState]];
    //... your app's logic
}

- (MXAppState)mxAppStateFromApplicationState:(UIApplicationState)state {
    if (state == UIApplicationStateActive) {
        return MXAppStateActive;
    } else {
        NSDate* lastLaunchDate = [[MXDefaults instance] dateOfLastLaunch];
        if (lastLaunchDate && [[NSDate date] timeIntervalSinceDate:lastLaunchDate] < 0.5f) {
            return MXAppStateLaunched;
        } else {
            return MXAppStateReactivated;
        }
    }
    return MXAppStateActive;
}

And MXDefaults is just a little wrapper for NSUserDefaults.

MXDefaults只是NSUserDefaults的一个小包装。

#17


0  

For swift

为迅速

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

    ++notificationNumber
    application.applicationIconBadgeNumber =  notificationNumber;

    if let aps = userInfo["aps"] as? NSDictionary {

        var message = aps["alert"]
        println("my messages : \(message)")

    }
}

#18


0  

When app is in background as shanegao you can use

当应用程序处于后台时,你可以使用它。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground  )
    {
         //opened from a push notification when the app was on background
    }
}

But if you want to launch the application and when app is closed and you want to debug your application you can go to Edit Scheme and in left menu select Run and then in launch select Wait for executable to be launched and then you application launch when you click on push notification

但如果你想启动应用程序时,应用程序关闭,您想要调试应用程序你可以去编辑方案和在发射选择左菜单选择Run然后等待执行启动,然后当你点击推送式通知应用程序启动

Edit Scheme > Run > Wait for executable to be launched

编辑方案>运行>等待可执行文件被启动

#19


0  

Swift 3.0

斯威夫特3.0

In AppDelegate, in the function 'didFinishLaunchingWithOptions' handle remote notification with some delay and open your Viewcontroller. You can use delay to handle notification after loading app successfully.

在AppDelegate中,在函数didFinishLaunchingWithOptions中,用一些延迟处理远程通知并打开视图控制器。成功加载app后,可以使用delay处理通知。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as! [NSObject : AnyObject]? {

            AppHelper.delay(0.8, closure: {
                self.handelNotification(dic: remoteNotification as! [String : Any])
            })
 }

#20


0  

Posting this for Xamarin users.

把这贴在Xamarin用户身上。

The key to detecting if the app was launched via a push notification is the AppDelegate.FinishedLaunching(UIApplication app, NSDictionary options) method, and the options dictionary that's passed in.

检测app是否通过推送通知启动的关键是AppDelegate。完成启动(UIApplication app, NSDictionary选项)方法,以及传入的选项字典。

The options dictionary will have this key in it if it's a local notification: UIApplication.LaunchOptionsLocalNotificationKey.

如果是本地通知,那么options字典将包含这个键:UIApplication.LaunchOptionsLocalNotificationKey。

If it's a remote notification, it will be UIApplication.LaunchOptionsRemoteNotificationKey.

如果是远程通知,它将是UIApplication.LaunchOptionsRemoteNotificationKey。

When the key is LaunchOptionsLocalNotificationKey, the object is of type UILocalNotification. You can then look at the notification and determine which specific notification it is.

当密钥是LaunchOptionsLocalNotificationKey时,对象是类型UILocalNotification。然后,您可以查看通知并确定它是哪个特定通知。

Pro-tip: UILocalNotification doesn't have an identifier in it, the same way UNNotificationRequest does. Put a dictionary key in the UserInfo containing a requestId so that when testing the UILocalNotification, you'll have a specific requestId available to base some logic on.

支持提示:UILocalNotification没有标识符,就像UNNotificationRequest一样。在包含requestId的UserInfo中放置一个dictionary键,以便在测试UILocalNotification时,您可以使用一个特定的requestId作为一些逻辑的基础。

I found that even on iOS 10+ devices that when creating location notifications using the UNUserNotificationCenter's AddNotificationRequest & UNMutableNotificationContent, that when the app is not running(I killed it), and is launched by tapping the notification in the notification center, that the dictionary still contains the UILocalNotificaiton object.

我发现,即使是在ios10 +设备上,当使用UNUserNotificationCenter的AddNotificationRequest & UNMutableNotificationContent创建位置通知时,当应用程序没有运行(我杀死了它)并通过点击通知中心的通知启动时,字典仍然包含uinotificaiton对象。

This means that my code that checks for notification based launch will work on iOS8 and iOS 10+ devices

这意味着我检查基于通知的启动的代码将适用于iOS8和ios10 +设备

public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
    _logger.InfoFormat("FinishedLaunching");

    if(options != null)
    {
        if (options.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
        {
            //was started by tapping a local notification when app wasn't previously running.
            //works if using UNUserNotificationCenter.Current.AddNotificationRequest OR UIApplication.SharedApplication.PresentLocalNotificationNow);

            var localNotification = options[UIApplication.LaunchOptionsLocalNotificationKey] as UILocalNotification;

            //I would recommended a key such as this :
            var requestId = localNotification.UserInfo["RequestId"].ToString();
        }               
    }
    return true;
}

#21


0  

func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
    print("Push notification received: \(data)")

    if let info = data["aps"] as? Dictionary<String, AnyObject> {
        let alertMsg = info["alert"] as! String
        print(alertMsg)
        switch application.applicationState {
        case .active:
            print("do stuff in case App is active")
        case .background:
            print("do stuff in case App is in background")
           // navigateToChatDetailViewControler(pushdata: data)
        case .inactive:
            print("do stuff in case App is inactive")
            // navigateToChatDetailViewControler(pushdata: data)
        }
    }
}

#22


-1  

For Swift Users:

快速用户:

If you want to launch a different page on opening from push or something like that, you need to check it in didFinishLaunchingWithOptions like:

如果你想从push或类似的东西开始打开一个不同的页面,你需要在didFinishLaunchingWithOptions中检查它,比如:

let directVc: directVC! = directVC(nibName:"directVC", bundle: nil)
let pushVc: pushVC! = pushVC(nibName:"pushVC", bundle: nil)

if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
     self.navigationController = UINavigationController(rootViewController: pushVc!)
} else {
     self.navigationController = UINavigationController(rootViewController: directVc!)
}
self.window!.rootViewController = self.navigationController

#23


-1  

IN SWIFT:

迅速:

I'm running Push Notifications (with background fetching). When my app is in the background and I receive a push notification, I found that didReceiveRemoteNotification in appDelegate would be called twice; once for when notification is received and another when user clicks on the notification alert.

我正在运行推送通知(后台取回)。当我的app在后台,我收到推送通知时,我发现appDelegate中的didReceiveRemoteNotification会调用两次;一次用于接收通知,另一次用于用户单击通知警报。

To detect if notification alert was clicked, just check if applicationState raw value == 1 inside didReceiveRemoteNotification in appDelegate.

要检测是否单击了通知警报,只需检查appDelegate中didReceiveRemoteNotification中应用程序状态原始值是否= 1。

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject: AnyObject]) {
    // If not from alert click applicationState(1)
    if (application.applicationState.rawValue != 1) {
        // Run your code here
    }
}

I hope this helps.

我希望这可以帮助。