アプリがプッシュ通知から起動/開かれたかどうかを検出します


172

アプリがプッシュ通知から起動/開かれたかどうかを知ることは可能ですか?

起動イベントはここでキャッチできると思います:

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

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

    }
}

しかし、アプリがバックグラウンドにあるときにプッシュ通知から開かれたことをどのように検出できますか?


6
これは古いですが、非常に便利な投稿です。残念ながら、トップの回答は実際には問題を解決しません(コメントが示すように)。現在の回答が完成していないため、新しい回答を「承認済み」としてマークすることを検討してください。
MobileVet

1
この質問には10万回以上の閲覧がありますが、選択された回答は正しくないか完全です。訪問者には、投票ではなくアクティブで並べ替えて、最新の解決策を見つけることを検討してください。
アルバートレンショー

回答:


187

このコードを参照してください:

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

19
@ManuelM。これは、バックグラウンドのアプリがプッシュ通知からフォアグラウンドに移動したことを検出する方法を示すという点で良い答えです。アプリが実行されていない場合は、以下のM.Othmanの回答が必要です。
OpenUserX03 2014年

6
application:didReceiveRemoteNotification:アプリがバックグラウンドで実行されているかどうかに関係なく通知をタップした後、この呼び出しが私のニーズに完全に合っているため、この呼び出しを取得しています。iOS 7および8でテスト済み
Newtz

16
他の人が指摘したように、これは「プッシュ通知からの起動/オープン」を検出しません。これは、通知が開かれたときではなく、受信されたときに呼び出されます。そのため、bgで通知を受け取ったが、アプリアイコンをタップしてアプリを開く場合、ここにあるコードは引き続き実行され、ユーザーが開こうとしていないページを開く可能性があります。
Bao Lei

4
@ManuelM。このメソッドは、バックグラウンドモード(リモート通知がチェックされている場合)でアプリが通知センターとアプリアイコンのどちらから開かれたかを通知しません。チェックされていない場合に実行されます。:私はこのポストの違い文書化しましたstackoverflow.com/questions/32061897/...
バオ・レイ

2
これがGoogleクラウドメッセージングで動作することを確認しました。
CularBytes

127

遅いが多分役に立つ

アプリが実行されていないとき

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

2
上記のスニペットでは、通知は(UILocalNotification *)ではなく(NSDictionary *)として宣言する必要があることに注意してください
cosmix

1
これにより、実行していないときに、アプリに通知があったかどうかを確認できます。問題は、通知からアプリが開かれたかどうかを検出する方法でした。この場合、アプリがまったく実行されていなくても、didReceiveRemoteNotificationが呼び出されます。-多くの場合非常に重要ですが、質問に対する正しい答えではないので、私はあなたの答えが好きです。
Axel Zehden 2016

あなたの答えとこの答えはどちらも同じことをしていますか?
ハニー

38

私たちが抱えていた問題は、アプリの起動後にビューを正しく更新することでした。混乱を招く複雑なライフサイクルメソッドのシーケンスがここにあります。

ライフサイクルメソッド

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 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. notificationUserInfoAppDelegateにインスタンス変数を格納します。
  2. 設定しnotificationUserInfo = nil、両方にapplicationWillEnterForegrounddidFinishLaunchingWithOptions
  3. 設定するnotificationUserInfo = userInfoにはdidReceiveRemoteNotification:inactive
  4. からapplicationDidBecomeActive常にカスタムメソッドopenViewFromNotificationを呼び出して渡しself.notificationUserInfoます。self.notificationUserInfoがnilの場合は早く戻り、それ以外の場合はにある通知状態に基づいてビューを開きself.notificationUserInfoます。

説明

プッシュから開くとき、didFinishLaunchingWithOptionsまたはapplicationWillEnterForeground常に直前に呼び出されるdidReceiveRemoteNotification:inactiveため、まずこれらのメソッドでnotificationUserInfoをリセットして、古い状態がないようにします。次に、didReceiveRemoteNotification:inactiveが呼び出された場合、プッシュから開いていることを確認できるので、ユーザーを正しいビューに転送self.notificationUserInfoするapplicationDidBecomeActiveためにピックアップされます。

最後のケースとして、ユーザーがアプリスイッチャー内でアプリを開いている(つまり、アプリがフォアグラウンドにあるときにホームボタンをダブルタップする)場合にプッシュ通知を受け取ります。この場合のみdidReceiveRemoteNotification:inactive呼び出され、WillEnterForegroundもdidFinishLaunchingも呼び出されないため、その場合を処理するには特別な状態が必要です。

お役に立てれば。


最後に、うまくいくもの、ありがとう!フラグ「appResuming」を作成しreceive、アプリの状態がアクティブまたはアプリが再開しているときにメソッドで画面を開きたいと思っていました。これにより、アプリがまだアクティブでないときにVCを変更すると問題が発生する可能性があります。Appleが再びライフサイクルを変更するまで、あなたのソリューションは素晴らしいように見えます。
shelll

iOS 9の場合、ライフサイクルメソッドは同じ方法と順序で呼び出されますか?私はすでにiOS 9デバイスを持っていないので、これを適切にテストできません。
shelll

2
アプリスイッチャーを除いて、2つのエッジケースがあります。1)通知センターが上から引っ張られてアプリをオーバーレイするとき2)wifi / BTなどを備えたiOSのパネルが下から引っ張られてアプリをオーバーレイするとき。3つのケースすべてで、applicationWillResignActiveが呼び出され、次にが呼び出されapplicationDidBecomeActiveます。したがって、applicationWillResignActiveが呼び出された後は、applicationDidEnterBackgroundまたはapplicationDidBecomeActiveが呼び出されるまで、受信した通知を保存しないでください。
shelll 2017

これらのケース@shelllを追加していただきありがとうございます。常に複雑になります!iOS9についてはわかりません。私はそれらが同じであると仮定することはおそらく安全だと思いますが、誰が知っています。
エリックコナー2017

頭を上げただけです。私は今日iOS 11 Beta 9をテストしていて、フォアグラウンドにアプリがあり、電話をロックし、ロック画面からプッシュ通知を選択した場合、applicationWillEnterForegroundを呼び出す直前に、didReceiveRemoteNotification:backgroundを呼び出していることがわかりました。 iOS 10でapplicationWillEnterForegroundを呼び出し、次にdidReceiveRemoteNotification:inactiveを呼び出しているところを見ているので、これはまだカバーされていないエッジケースです。私の意見では、これはiOSコードのバグですが、iOS 11のリリースがどれほど近いかを考えると、注意する必要があります。
Roy

24

これは使い古された投稿ですが、まだ問題に対する実際の解決策がありません(さまざまなコメントで指摘されています)。

元の質問は、プッシュ通知からアプリがいつ起動 / 開かれたかを検出することです。たとえば、ユーザーが通知をタップします。実際にはこのケースをカバーする回答はありません。

理由は、通知が到着したときにコールフローで確認できます。 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)
    }
  }
}

スウィフト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でも問題ありません。


1
これは、通知を実際にタップすることと、アプリの上にステータスバーを開くことを区別する唯一の実用的なソリューションのようです。
liviucmg

4
これは、すべてのStackOverflowからの唯一の実用的なソリューションです。追加したいのは、iOS 10以降をサポートしている場合は、UNNotificationCenterAPI、特にUNNotificationCenterDelegateメソッドを使用するだけです。これらのAPIはuserNotificationCenter(UNUserNotificationCenter, didReceive: UNNotificationResponse, withCompletionHandler: @escaping () -> Void) 、ユーザーが実際に通知をタップしたときにのみfunc メソッドを呼び出します。
DenHeadless

Swift 3はどのように見えますか?
JochenÖsterreicher2017

アプリが非アクティブな状態(ユーザーが通知センターを下にスワイプするか、コントロールセンターを上にスワイプ)の場合、ソリューションは機能せず、通知を受け取ります。ユーザーが通知をタップすると、アプリはapplicationWillEnterForeground 呼び出しを受信しないため、ソリューションはタップを検出できません。
DevGansta

@DevGanstaのようにクラスを追加するUNUserNotificationCenter.current().delegateapplication:didFinishLaunchingWithOptionsuserNotificationCenter(didReceive response)説明した場合にタップ後にアプリが呼び出されます
Dorian Roy

22

アプリが終了し、ユーザーがプッシュ通知をタップしたとき

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を参照してください


2
汚いハックのように感じられず、正解だと答えるだけです。アプリがバックグラウンドであり、ユーザーが手動で開いている場合、それを確認する方法はありませんか?プッシュコールドスタートを確認しながら、バックグラウンドからプッシュできます。
JochenÖsterreicher2017

1
@JochenÖsterreicherこんにちは、ここに要約します。medium.com/ @ onmyway133 /…を確認してください
onmyway133

19

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

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
}

15

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

3
ユーザーが別の画面にいるときに通知が送信された場合(たとえば、ユーザーがステータスバーをプルダウンしてアプリから通知を受信した場合)、「通知から開いたアプリ」は誤検知になります。
Kevin Cooper

4
@Kevinその通りです。Appleが通知を処理するプロセスを設計するためにどうやらインターンを配置したように見えるのかと不思議に思う...
Andreas

アクティブ状態で受信した通知をタップしたかどうかをどのように検出できるか
Mayank Jain

13

迅速に:

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

    }

}

4

はい、appDelegateでこのメソッドを使用して検出できます。

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

ローカル通知の場合:

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

1
アプリが実行されていない場合、このメソッドは呼び出されません。それがここで尋ねられたものです
Pfitz 2013年

私の問題は通知の処理ではなく、バナーをクリックしたときに(アプリがバックグラウンドにあるときに)開かれたかどうかを知ることです。
joao 2013年

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

しかし、アプリが終了したときにプッシュ通知をタップしてアプリが開かれているかどうかを知る方法
user3804063

1
誰かがプッシュをタップすると、アプリが終了したかどうかに関係なく、アプリが開きます。そして、.inactiveのケースが呼び出されています
Hamid Shahsavari

1
プッシュをタップしてアプリが開いているかどうかを検出する必要があり、それを実行しているInstagramで見たそれぞれのコンテンツに移動したい
user3804063

ローカル通知はどうですか?
Amir Shabani 2017

3

Xamarinユーザー向けにこれを投稿します。

アプリがプッシュ通知を介して起動されたかどうかを検出する鍵は、AppDelegate.FinishedLaunching(UIApplication app, NSDictionary options)メソッドと、渡されるオプションディクショナリです。

ローカル辞書の場合、オプションディクショナリには次のキーが含まれます UIApplication.LaunchOptionsLocalNotificationKey

リモート通知の場合はになりますUIApplication.LaunchOptionsRemoteNotificationKey

キーがのLaunchOptionsLocalNotificationKey場合、オブジェクトのタイプはUILocalNotificationです。次に、通知を見て、それがどの特定の通知であるかを判別できます。

プロのヒント:UILocalNotification識別子はありませんUNNotificationRequest。同じように。requestIdを含むUserInfoにディクショナリキーを配置して、をテストするときにUILocalNotification、ロジックの基礎となる特定のrequestIdを使用できるようにします。

UNUserNotificationCenterAddNotificationRequest&を使用して位置通知を作成するUNMutableNotificationContentとき、アプリが実行されていないとき(私はそれを殺した)、通知センターで通知をタップして起動されるiOS 10以降のデバイスでも、辞書にはまだ含まれていることがわかりました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;
}

2

のドキュメントから直接

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

アプリが実行中でリモート通知を受け取った場合、アプリはこのメソッドを呼び出して通知を処理します。

このメソッドの実装では、通知を使用して適切な一連のアクションを実行する必要があります。

そして少し後で

プッシュ通知が届いたときにアプリが実行されていない場合、メソッドはアプリを起動し、起動オプションディクショナリに適切な情報を提供します。

アプリはこのプッシュ通知を処理するためにこのメソッドを呼び出しません。

代わりに、

application:willFinishLaunchingWithOptions:

または

application:didFinishLaunchingWithOptions:

メソッドは、プッシュ通知ペイロードデータを取得して適切に応答する必要があります。


2

まず、自分で使用して、より正確に視覚化し、他のすべての状態を検討するために作成した状態チャートを使用し ます。 ?gid = 0&single = true

このグラフを使用すると、ほとんどすべての可能なユースケースで機能する堅牢な通知処理システムを開発するために実際に何が必要かを確認できます。

完全なソリューション↓

  • ストア通知ペイロードdidReceiveRemoteNotification
  • applicationWillEnterForegrounddidFinishLaunchingWithOptionsに保存されている通知をクリアする
  • コントロールセンター/通知センターがプルされた場合に取り組むには、フラグwillResignActiveCalledを使用して、最初にfalseに設定し、applicationWillResignActiveメソッドでこれをtrueに設定します
  • didReceiveRemoteNotificationの方法、willResignActiveCalledが偽のときにのみ通知(のUserInfo)を保存します。
  • applicationDidEnterBackgroundおよびapplicationDidBecomeActiveメソッドでwillResignActiveCalledをfalseにリセットします

注:エリックの回答のコメントでも同様の回答が提案されていますが、状態シートは、アプリで行ったように、考えられるすべてのシナリオを見つけるのに役立ちます。

以下の完全なコードを見つけて、特定のケースが処理されない場合は以下にコメントしてください。

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:これは、アプリケーションのさまざまな部分に移動するためのすべてのコードを記述し、データベース(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
    }
  }
}

これは答えではないので、コメントとしてこれを入れてください。
マディ

@Maddy提案をありがとう、すべての詳細で回答を更新
chetan anand

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

1

信頼できる方法は1つだけあり、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
    }
    ...
}

0

以下を使用できます。

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

リモートプッシュ通知を処理します。

ここでドキュメントを確認してください



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

しかし、アプリが閉じられた(終了した)場合はどうでしょうか。TwitterやInstagramのようにそれは何とかそれを検出し、アプリも閉じている場合には、新しい投稿や写真やプロフィールなど。にリダイレクト
TarvoMäesepp

0

この質問の問題は、アプリを「開く」ことが明確に定義されていないことです。アプリは、実行されていない状態からコールドローンチされるか、非アクティブな状態から再アクティブ化されます(たとえば、別のアプリからのアプリへの切り替えから)。これらの可能な状態をすべて区別するための私の解決策は次のとおりです。

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


0

ために 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)")

    }
}

0

Xcode 10 Swift 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
    }
}

0

iOS 10以降では、このメソッドを使用して、アプリの状態に関係なく、通知がいつクリックされたかを知ることができます。

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

    //Notification clicked
    completionHandler()
}

0

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
        }

-1

Swiftユーザーの場合:

プッシュなどで開くときに別のページを起動する場合は、次のようにチェックインする必要があります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

DelegateにはメンバーnavigationControllerがありません
Pablo Cegarra

1
AppDelegate.hファイルにナビゲーションコントローラを作成します。それを使用していて、うまくいきます!
AAA、

-1

迅速に:

プッシュ通知を実行しています(バックグラウンドでフェッチしています)。アプリがバックグラウンドでプッシュ通知を受信すると、appDelegateのdidReceiveRemoteNotificationが2回呼び出されることがわかりました。1回は通知を受信したとき、もう1回はユーザーが通知アラートをクリックしたときです。

通知アラートがクリックされたかどうかを検出するには、appDelegateのdidReceiveRemoteNotification内のapplicationState raw値== 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
    }
}

これがお役に立てば幸いです。


-1

アプリがシャネガオとしてバックグラウンドにあるときに使用できます

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

しかし、アプリケーションを起動する場合、およびアプリケーションが閉じられ、アプリケーションをデバッグする場合は、スキームの編集に移動し、左側のメニューで[ 実行 ]を選択してから、[起動]で[ 実行可能ファイルの起動を待機 ]を選択し、アプリケーションの起動時にプッシュ通知をクリック

スキームの編集>実行>実行可能ファイルの起動を待機

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.