簡體   English   中英

檢測應用程序是否從推送通知啟動/打開

[英]Detect if the app was launched/opened from a push notification

是否可以通過推送通知知道應用程序是否已啟動/打開?

我想啟動事件可以在這里捕獲:

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

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

    }
}

但是,當應用程序在后台時,我如何檢測它是從推送通知中打開的?

請參閱此代碼:

- (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
    }
}

如同

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

遲到但可能有用

當應用程序未運行時

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

叫做 ..

您需要在哪里檢查推送通知

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");
}

我們遇到的問題是在應用程序啟動后正確更新視圖。 這里有復雜的生命周期方法序列,令人困惑。

生命周期方法

我們對 iOS 10 的測試揭示了針對各種情況的以下生命周期方法序列:

DELEGATE METHODS CALLED WHEN OPENING APP

    Opening app when system killed or user killed
        didFinishLaunchingWithOptions
        applicationDidBecomeActive

    Opening app when backgrounded
        applicationWillEnterForeground
        applicationDidBecomeActive

DELEGATE METHODS CALLED 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

問題

好的,所以現在我們需要:

  1. 確定用戶是否通過推送打開應用
  2. 根據推送狀態更新視圖
  3. 清除狀態,以便后續打開不會將用戶返回到相同位置。

棘手的一點是,必須在應用程序實際激活時更新視圖,這在所有情況下都是相同的生命周期方法。

我們的解決方案草圖

以下是我們解決方案的主要組成部分:

  1. 在 AppDelegate 上存儲一個notificationUserInfo實例變量。
  2. applicationWillEnterForegrounddidFinishLaunchingWithOptions中設置notificationUserInfo = nil
  3. didReceiveRemoteNotification:inactive中設置notificationUserInfo = userInfo
  4. applicationDidBecomeActive始終調用自定義方法openViewFromNotification並傳遞self.notificationUserInfo 如果self.notificationUserInfo為 nil 則提前返回,否則根據self.notificationUserInfo中的通知狀態打開視圖。

解釋

當從推送中打開didFinishLaunchingWithOptionsapplicationWillEnterForeground時,總是在didReceiveRemoteNotification:inactive之前立即調用,所以我們首先在這些方法中重置 notificationUserInfo,這樣就不會出現陳舊狀態。 然后,如果didReceiveRemoteNotification:inactive被調用,我們知道我們正在從推送中打開,所以我們設置self.notificationUserInfo ,然后由applicationDidBecomeActive拾取以將用戶轉發到正確的視圖。

最后一種情況是,如果用戶在應用程序切換器中打開了應用程序(即在應用程序處於前台時雙擊主頁按鈕),然后收到推送通知。 在這種情況下,只有didReceiveRemoteNotification:inactive被調用,WillEnterForeground 和 didFinishLaunching 都沒有被調用,所以你需要一些特殊的狀態來處理這種情況。

希望這可以幫助。

這是一篇陳舊的帖子......但它仍然缺少解決問題的實際解決方案(正如各種評論中所指出的那樣)。

最初的問題是關於檢測應用程序何時從推送通知啟動/打開例如用戶點擊通知。 沒有一個答案實際上涵蓋了這種情況。

原因可以在通知到達時的調用流程中看到, application:didReceiveRemoteNotification...

當收到通知在用戶點擊通知時再次調用。 因此,您無法僅通過查看UIApplicationState來判斷用戶是否點擊了它。

此外,您不再需要在application:didFinishLaunchingWithOptions...中處理應用程序“冷啟動”的情況,因為在 iOS 9+(可能也是 8)中啟動后再次調用application:didReceiveRemoteNotification...

那么,如何判斷用戶點擊是否啟動了事件鏈呢? 我的解決方案是標記應用程序開始退出后台或冷啟動的時間,然后在application:didReceiveRemoteNotification...中檢查該時間。 如果小於 0.1s,那么你可以很確定點擊觸發了啟動。

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

斯威夫特 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.1s 也相當保守,實際值約為 0.002s,所以 0.01 也可以。

當應用程序終止時,用戶點擊推送通知

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

當應用程序處於后台時,用戶點擊推送通知

如果用戶從系統顯示的警報中打開您的應用程序,系統可能會在您的應用程序即將進入前台時再次調用此方法,以便您可以更新用戶界面並顯示與通知有關的信息。

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

根據您的應用程序,它還可以向您發送帶有content-available靜默推送aps ,因此也要注意這一點 :) 請參閱https://stackoverflow.com/a/33778990/1418457

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
}

application:didReceiveRemoteNotification:檢查你的應用在前台還是后台時是否收到通知。

如果在后台收到,請從通知中啟動應用程序。

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

對於快速:

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 in the background

    }

}

為 Xamarin 用戶發布此內容。

檢測應用程序是否通過推送通知啟動的關鍵是AppDelegate.FinishedLaunching(UIApplication app, NSDictionary options)方法和傳入的選項字典。

如果它是本地通知,則選項字典將包含此鍵: UIApplication.LaunchOptionsLocalNotificationKey

如果是遠程通知,它將是UIApplication.LaunchOptionsRemoteNotificationKey

當鍵是LaunchOptionsLocalNotificationKey時,對象是UILocalNotification類型。 然后,您可以查看通知並確定它是哪個特定通知。

專業提示: UILocalNotification中沒有標識符,與UNNotificationRequest相同。 在包含 requestId 的 UserInfo 中放置一個字典鍵,以便在測試UILocalNotification時,您將有一個特定的 requestId 可用於基於某些邏輯。

我發現即使在 iOS 10+ 設備上,當使用UNUserNotificationCenterAddNotificationRequestUNMutableNotificationContent創建位置通知時,當應用程序未運行(我殺死它)並通過點擊通知中心中的通知啟動時,字典仍然包含UILocalNotificaiton對象。

這意味着我檢查基於通知的啟動的代碼將適用於 iOS8 和 iOS 10+ 設備

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;
}

是的,您可以在appDelegate中通過此方法檢測:

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

對於本地通知:

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

如果有人想要 swift 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
    }
}

如果您運行的是iOS 13或更高版本,請在SceneDelegate 中使用此代碼:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
    guard let notificationResponse = connectionOptions.notificationResponse else { return }
    
    let pushTitle = notificationResponse.notification.request.content.title
    let pushSubtitle = notificationResponse.notification.request.content.subtitle
    let pushBody = notificationResponse.notification.request.content.body
    
    // do your staff here
}

直接來自文檔

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

如果應用正在運行並收到遠程通知,應用會調用此方法處理通知。

您對此方法的實現應使用通知來采取適當的行動。

稍晚一點

如果推送通知到達時應用程序未運行,則該方法將啟動應用程序並在啟動選項字典中提供適當的信息。

該應用程序不會調用此方法來處理該推送通知。

相反,您對

application:willFinishLaunchingWithOptions:

或者

application:didFinishLaunchingWithOptions:

方法需要獲取推送通知有效負載數據並適當響應。

我將從我為自己創建的狀態圖開始,以便更准確地對其進行可視化並考慮所有其他狀態: https ://docs.google.com/spreadsheets/d/e/2PACX-1vSdKOgo_F1TZwGJBAED4C_7cml0bEATqeL3P9UKpBwASlT6ZkU3iLdZnOZoevkMzOeng7gs31IFhD-L/pubhtml ?gid=0&single=true

使用此圖表,我們可以看到開發一個適用於幾乎所有可能用例的強大通知處理系統實際需要什么。

完整解決方案↓

  • didReceiveRemoteNotification中存儲通知負載
  • 清除applicationWillEnterForegrounddidFinishLaunchingWithOptions中存儲的通知
  • 要解決控制中心/通知中心被拉動的情況,您可以使用標志willResignActiveCalled並將其最初設置為false ,在applicationWillResignActive方法中將此設置為true
  • didReceiveRemoteNotification方法中,僅當 willResignActiveCalled 為 false 時才保存通知(userInfo)。
  • applicationDidEnterBackgroundapplicationDidBecomeActive方法中將willResignActiveCalled 重置為 false

注意:在對 Eric 答案的評論中建議了類似的答案,但是,狀態表有助於找到所有可能的場景,就像我在我的應用程序中所做的那樣。

如果沒有處理任何特定情況,請在下面找到完整的代碼並在下面評論:

應用委托

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 :在這里您可以編寫所有代碼以導航到應用程序的不同部分,處理數據庫(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
    }
  }
}

M.Othman 的答案對於不包含場景委托的應用程序是正確的對於場景委托應用程序這在iOS 13上對我有用

這是應該在將連接場景中編寫的代碼

if connectionOptions.notificationResponse == nil { 
//Not opened from push notification
} else {
  //Opened from push notification
}

用於支持早期版本的應用程序委托的代碼didFinishLaunchingWithOptions

let notification = launchOptions?[UIApplication.LaunchOptionsKey.remoteNotification]
        if (notification != nil) {

            //Launched from push notification
        } else {

            //Launch from other source
        }
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)
        }
    }
}

只有一種可靠的方法,它僅適用於iOS 10+

使用UNUserNotificationCenter實現UNUserNotificationCenterDelegate方法:

- (void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {

    //Here you can get your original push if you need to
    NSDictionary* pusDict = response.notification.request.content.userInfo;

    if ([response.actionIdentifier isEqualToString: UNNotificationDefaultActionIdentifier]) {
        //User tapped the notification
    } else if ([response.actionIdentifier isEqualToString: UNNotificationDismissActionIdentifier]) {
        //User dismissed the notification 
    } else if ([response.actionIdentifier isEqualToString: MYCustomActionId]) {
        //User chose my custom defined action
    }
    ...
}

2021,Swift 5,僅限本地通知

UNUserNotificationCenter.current().delegate = self

extension YourClass: UNUserNotificationCenterDelegate {

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let notificationIdentifier = response.notification.request.identifier

        // If this is called, then your app was opened from a local notification with this identifier
    }
}


如果您的應用程序中有SceneDelegate ,那么您應該使用下面的代碼來管理本地/遠程通知,當您的應用程序被終止/終止並且您通過點擊通知打開應用程序時

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
    //Handle Notification Response
    guard let notifiResponse = connectionOptions.notificationResponse else { return }
    
    if notifiResponse.notification.request.trigger is UNTimeIntervalNotificationTrigger { //Local Notification
        Messaging.messaging().appDidReceiveMessage(notifiResponse.notification.request.content.userInfo)
        
        print("Receive Local Notifications")            
    }
    else if notifiResponse.notification.request.trigger is UNPushNotificationTrigger{ //Remote Notification
        
        print("Receive Remote Notifications")
    }                
}

當您的應用程序處於后台/前台狀態時,使用您的AppDelegate管理本地/遠程通知。

extension AppDelegate : UNUserNotificationCenterDelegate {   

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
                   
        if response.notification.request.trigger is UNTimeIntervalNotificationTrigger{
             print("Receive Local Notifications")
        }
        else if response.notification.request.trigger is UNPushNotificationTrigger{
             print("Receive Remote Notifications")
        }
    
        let userInfo = response.notification.request.content.userInfo
        completionHandler()
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
       print("willPresent Notifications")

       if notification.request.trigger is UNTimeIntervalNotificationTrigger{
            print("Receive Local Notifications")
       }
       else {
            print("Receive Remote Notifications")
       }
       completionHandler([.banner, .list, .sound])
    }
}
     // 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")
            }
    }

這個問題的問題在於“打開”應用程序的定義不明確。 應用程序要么從非運行狀態冷啟動,要么從非活動狀態重新激活(例如,從另一個應用程序切換回它)。 這是我區分所有這些可能狀態的解決方案:

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;
}

MXDefaults只是NSUserDefaults的一個小包裝。

Xcode 10 斯威夫特 4.2

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

    let state : UIApplicationState = application.applicationState
    if (state == .Inactive || state == .Background) {
        // coming from background
    } else {
        // App is running in foreground
    }
}

M.Othman 對 Swift 5 的回答。(盡管不再推薦使用 NSLog )

在設置顯示RootViewController所需的所有內容后添加以下內容。 在您的application(_:didReceiveRemoteNotification)中,您應該添加可以區分首次啟動和后台啟動類型的邏輯。

if let launchOptions = launchOptions, 
let notification = launchOptions[UIApplicationLaunchOptionsKey.remoteNotification] 
as? [AnyHashable : Any] {
    NSLog("app recieved notification from remote \(notification)")
    self.application(application, didReceiveRemoteNotification: notification)
} else {
    NSLog("app did not recieve notification")
}

可以在以下位置找到解決此問題的其他一些 Swift 特定答案: 點擊通知時如何處理 Swift 3 中的啟動選項? 遇到語法問題

您可以使用:

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

處理遠程推送通知。

在這里查看文檔

我還沒有嘗試過,但也許你可以給自己發個通知? http://nshipster.com/nsnotification-and-nsnotificationcenter/

為了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)")

    }
}

對於 Swift 用戶:

如果你想在從 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

當應用程序在后台作為shanegao時,您可以使用

- (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
    }
}

但是,如果您想啟動應用程序並且當應用程序關閉並且您想調試您的應用程序時,您可以轉到編輯方案並在左側菜單中選擇運行,然后在啟動中選擇等待可執行文件啟動,然后您的應用程序在您啟動時啟動點擊推送通知

編輯方案 > 運行 > 等待可執行文件啟動

迅速:

我正在運行推送通知(帶有后台獲取)。 當我的應用在后台並收到推送通知時,我發現 appDelegate 中的 didReceiveRemoteNotification 會被調用兩次; 一次是在收到通知時,另一次是在用戶單擊通知警報時。

要檢測是否單擊了通知警報,只需檢查 appDelegate 中的 didReceiveRemoteNotification 中的 applicationState 原始值是否 == 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
    }
}

我希望這有幫助。

斯威夫特3.0

在AppDelegate中,在函數'didFinishLaunchingWithOptions'中延遲處理遠程通知,然后打開Viewcontroller。 成功加載應用后,您可以使用延遲來處理通知。

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

是否可以通過推送通知了解應用程序是否已啟動/打開?

我想啟動事件可以在這里找到:

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

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

    }
}

但是,當應用程序在后台運行時,如何從推送通知中檢測到它已打開?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM