iOSプッシュ通知:アプリがバックグラウンドにあるときにユーザーが通知をタップしたかどうかを検出する方法は?


116

このトピックに関しては、stackoverflowスレッドがたくさんありますが、それでも良い解決策は見つかりませんでした。

アプリがバックグラウンドにない場合は、通知から開いたかどうかを確認するためlaunchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]application:didFinishLaunchingWithOptions:通話をチェックインできます。

アプリがバックグラウンドにある場合、すべての投稿でapplication:didReceiveRemoteNotification:、アプリの状態を使用して確認することをお勧めします。しかし、実験的に(このAPIの名前からもわかるように)、このメソッドは、通知を受信したときにタップされずに呼び出されます。

したがって、問題は、アプリが起動されてバックグラウンドで実行され、通知が受信されたことがわかっているapplication:didReceiveNotificationapplication:didFinishLaunchWithOptions:現時点ではトリガーされない)場合、ユーザーが通知をタップするか、単にアプリアイコン?ユーザーが通知をタップした場合、その通知に記載されているページを開くことが期待されているためです。それ以外の場合は必要ありません。

handleActionWithIdentifierカスタムアクション通知に使用できますが、これはカスタムアクションボタンがタップされたときにのみトリガーされ、ユーザーが通知の本体をタップしたときにトリガーされません。

ありがとう。

編集:

以下の回答を1つ読んだ後、このようにして質問を明確にできると思いました。

これらの2つのシナリオをどのように区別できますか?

(A)1.アプリがバックグラウンドに移行します。2.通知を受け取りました。3.ユーザーは通知をタップします。4.アプリが前面に表示される

(B)1.アプリがバックグラウンドに移行します。2.通知を受け取りました。3.ユーザーは通知を無視し、後でアプリアイコンをタップします。4.アプリが前面に表示される

application:didReceiveRemoteNotification:どちらの場合もステップ2でトリガーされるため。

または、application:didReceiveRemoteNotification:(A)の場合のみステップ3でトリガーする必要がありますが、どういうわけかアプリを誤って構成したため、ステップ2で表示されますか?


ペイロードにカスタムディクショナリ値を使用し、それに応じて動作します。ものすごく単純。
15

ペイロード内の@soulshined辞書は、ユーザーが通知をタップしたかどうかを表すことができますよね?たとえば、友達Aが記事Bを投稿した場合、アプリがバックグラウンドにあり、didReceiveRemoteNotificationを取得しながら、ペイロードで{user:A、article:B}と言うことができます。アプリが再開したとき、記事を表示する必要があるかどうかはどのようにしてわかりますか?
Bao Lei

2
@soulshined私はドキュメントを読んだか、didReceiveRemoteNotificationが何をするかについて自分自身を教育しました。実際に私の質問を読みましたか?Appleの公式ドキュメントdidReceiveRemoteNotificationは、「実行中のアプリがリモート通知を受け取ったことをデリゲートに伝えます」。ユーザーが通知をタップしたかどうかを確認するための良い方法は何ですか。あなたが言及したSOリンクは、アプリが最初から起動しているときのものです。アプリがバックグラウンドにあるときのシナリオを尋ねます。
Bao Lei


1
@soulshined OK多分私はそれを十分に明確に述べなかった。つまり、アプリがバックグラウンドではなく完全に終了した場合、はいdidFinishLaunchingが呼び出されます。ただし、アプリを起動し、アプリをバックグラウンドにすると、通知が届き、ユーザーが通知をタップすると、didFinishLaunchingが再度呼び出されなくなります。代わりに、applicationWillEnterForegroundおよびapplicationDidBecomeActiveが呼び出されます。ユーザーが通知またはアプリのアイコンをタップしたために、アプリがフォアグラウンドに入っていることをどのように確認できますか?
Bao Lei

回答:


102

はい、やっとわかりました。

ターゲット設定➝機能タブ➝バックグラウンドモードで、[リモート通知]をオンにapplication:didReceiveRemoteNotification:すると、通知が到着するとすぐにトリガーされ(アプリがバックグラウンドにある限り)、その場合、ユーザーは通知をタップします。

このチェックボックスをオフにapplication:didReceiveRemoteNotification:すると、通知をタップしたときにのみトリガーされます。

このボックスをチェックすると、アプリのデリゲートメソッドの1つがどのように動作するかが変わるのは少し奇妙です。そのボックスがチェックされていると、Appleは通知の受信と通知のタップに2つの異なるデリゲートメソッドを使用します。ほとんどの開発者は、通知がタップされているかどうかを常に知りたいと思います。

うまくいけば、これはこの問題に遭遇した他の誰にとっても役立つでしょう。Appleもここに明確に文書化していないため、理解するのにしばらく時間がかかりました。

ここに画像の説明を入力してください


6
バックグラウンドモードを完全に「オフ」に設定していますが、バックグラウンドモードのアプリで通知が届いたときにも通知が届きます。
ゴットフリート

5
すごい!これは私を助けました。ただし、リモート通知をオフにする必要があるのは残念です。プッシュ通知が届き、ユーザーのタップを検出したときにデータをプリフェッチしたいと思います。これを達成する方法が見つかりません。
Peter Fennema、2015年

1
バックグラウンドモードを「オン」モードに設定し、リモート通知を有効にします。それでも通知イベントを検出できません。
kalim sayyad

1
同じ問題があります。バックグラウンドモードが「オン」に設定され、リモート通知が有効になっていますが、バックグラウンドモードでアプリに通知が届いたときに通知されません
Swapnil Dhotre

@Bao-このオプションは基本的にバックグラウンドで通知に関連するコンテンツをダウンロードするために使用されるため、Appstoreで拒否が発生すると思います。したがって、コンテンツをダウンロードしていない場合、Appleはアプリを拒否することがあります。developer.apple.com/library/ios/documentation/iPhone/Conceptual/...
NIKS

69

私はあなたと同じものを探していましたが、実際にはリモート通知をオフにする必要のない解決策を見つけました。

ユーザーがタップしたかどうか、またはアプリがバックグラウンドかアクティブかどうかを確認するには、アプリケーションの状態を

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{

    if(application.applicationState == UIApplicationStateActive) {

        //app is currently active, can update badges count here

    }else if(application.applicationState == UIApplicationStateBackground){

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

    }else if(application.applicationState == UIApplicationStateInactive){

        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here

    }

詳細情報を確認するには:

UIKitフレームワークリファレンス> UIApplicationクラスリファレンス> UIApplicationState


10
アプリが画面に表示されているときにユーザーが通知センター(上からスワイプ)またはコントロールセンター(下からスワイプ)を操作した結果、アプリがUIApplicationStateInactiveになるのはどうですか。どうやら、APNSが非アクティブ状態で受信されたか、ユーザーが実際にタップしたかどうかを判断する方法はありません。
Kostia Kim 2016

1
@KostiaKimその通りですが、それはスーパーエッジケースです...それ以外は、この答えは、フォアグラウンドのアプリとユーザーのタップ...バックグラウンドのアプリを分離するという点で最も有効です
Honey

ありがとう、この種はすべてを分かりやすく説明しています。アプリがバックグラウンドで実行されているときにデリゲートメソッドを呼び出すには、プッシュ通知にcontent-availableキーを含める必要がありますが、公式ドキュメントに記載れているように、通知はサイレントにする必要があります(つまり、サウンドやバッジを含めない)。。
Nickkk 2017

1
@KostiaKim私は実際にユーザが実際にtrueに設定されているブール追加することにより、通知をタップ場合、コントロールセンターが開いていたかどうか知らないの問題解決することができたfunc applicationDidEnterBackground(_ application: UIApplication)で偽func applicationDidBecomeActive(_ application: UIApplication)私はアプリで表示することができ、これをコントロールセンターまたは通知リストのためにアプリが非アクティブになったときの通知
DatForis 2017

3
Appleが別のイベントを提示しなかった理由や、ユーザーが実際に通知を操作したことを示すためにメタデータにフラグを追加した理由に心を揺さぶられます。ユーザーがアプリケーションの状態に関する周囲の情報に基づいてアクションを実行したかどうかを「推測」する必要があることは、アプリケーションの動作に対するユーザーの期待に影響を与える重要な情報にはかなり不合理です。おそらく、行うべきことは、その情報でアプリを開くカスタムアクションを作成することだけでしょうか。
Allan Nienhuis 2017年

20

iOS / XCodeによると :通知またはクリックボードのアプリアイコンをクリックしてアプリが起動されたことを知る方法は? 次のように、didReceiveLocalNotificationでアプリケーションの状態を確認する必要があります。

if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive)
{
    // user has tapped notification
}
else
{
    // user opened app from app icon
}

私にはまったく意味がありませんが、うまくいくようです。


1
このシナリオでは機能しません。以前に試しました。そのチェックボックスがオンになっている場合(詳細については、承認された回答を参照してください)、通知が届くと、ユーザーが通知をタップしなかった(通知が届いた)にもかかわらず、コメント「//ユーザーが通知をタップしました」が入力されます。 )。
Bao Lei

3
同意しません。私はバックグラウンド機能で「リモート通知」をチェックしており、それは私の回答に記載された方法で機能します。「バックグラウンドフェッチ」もチェックしています。多分それが変化を引き起こしますか?
Werner Kratochwil、2015

私の答えを+1してもらえますか?;-)スタックオーバーフローにもっと参加するには、まだ投票が必要です。
どうも

ユペ、これが解決策です。tnx。
アフシン

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

16

誰かがSwift 3.0でそれを望んでいるなら

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
    }

Swift 4用

switch UIApplication.shared.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
}

どのトリガーでこのコードを追加する必要がありますか、didReceiveRemoteNotificationまたはdidFinishLaunchingWithOptions?
Dashrath 2017年

2
didReceiveRemoteNotificationについて
Hamid Shahsavari

@Hamid sh ,,,,すべての状態でプッシュ通知を受け取りました。つまり、アプリがフォアグラウンド、バックグラウンド、クローズ(終了)の場合です。しかし、私の問題は、アプリがバックグラウンド状態でクローズ(終了)状態のときにバッジカウントをインクリメントする方法ですか???? 方法を詳しく教えてください...?アプリのバッジ数が増えるのは、アプリがフォアグラウンド状態にあるときだけです。できれば簡単に教えてください……!
キランジャダブ2017

8

[バックグラウンドモード]> [リモート通知]がオンになっている場合==はい、通知イベントをタップすると次の場所に到着します:

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

それは私を助けました。楽しんでください :)


Appleがこれを追加したのを見たが、この方法で通知のカスタムペイロードを取得する方法を理解できなかった。
sudo

これは、アプリがバックグラウンド状態でアクティブになったとき、およびアプリが
強制終了

@NikhilMuskurは、「リモート通知」が有効になっている場合のみですか。
Zorayr

正しい@Zorayrうん
Nikhil Muskur

8

私もこの問題に遭遇しました—しかし、新しいUserNotificationsフレームワークを備えたiOS 11で。

ここで私にとっては次のようになります:

  • 新発売: application:didFinishLaunchingWithOptions:
  • 終了状態から受信: application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
  • フォアグラウンドで受信: userNotificationCenter(_:willPresent:withCompletionHandler:)
  • バックグラウンドで受信: userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:

これは、iOS 11以降で実行する方法です
OhadM

これはとても複雑です🤦‍♂️
Zorayr

4

私の場合、バックグラウンドモードをオフにしても違いはありませんでした。ただし、アプリが一時停止され、ユーザーが通知をタップすると、このコールバックメソッドでケースを処理できます。

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

}

これはアップルが言う公式な方法です。Appleのドキュメントによれば、ユーザーがプッシュ通知UIを操作するたびに呼び出されます。アプリがバックグラウンドにない場合、アプリはバックグラウンドモードで起動し、このメソッドを呼び出します。
Ryan

3

iOS 10以降の場合、これをAppDelegateに入れて、通知がタップされたことを確認します(アプリが閉じていても開いていても機能します)

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
print("notification tapped here")
}

1
これはiOS 10以降の正解です。ここの別のスレッドで提供された完全な説明:stackoverflow.com/a/41783666/1761357
dead_can_dance

2

PushNotificationManagerクラス内で受信したPushNotificationのハンドルには2つのFuncsがあります。

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate{

}

通知が到着したらすぐに最初のトリガーをテストしたので

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

    completionHandler(UNNotificationPresentationOptions.alert)

    //OnReceive Notification
    let userInfo = notification.request.content.userInfo
    for key in userInfo.keys {
         Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler([])

}

通知をタップしたときの2つ目:

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

    //OnTap Notification
    let userInfo = response.notification.request.content.userInfo
    for key in userInfo.keys {
        Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler()
}

また、リモート通知のオンとオフの両方の状態でテストしました(バックグラウンドモード)。


1

SWIFT 5.1

UIApplication.State アプリで指紋(モーダルが表示されます)を読み取ると、通知も上部バーにスローされ、ユーザーがクリックする必要があるため、私にとっては機能しませんでした。

作成しました

public static var isNotificationFromApp: Bool = false

AppDelegate、私はそれtrueを私の開始時に設定し、viewController次に私の通知に設定しますstoryboard/ viewController私はそれをチェックします:)

重宝すると思います


-7

application:didReceiveRemoteNotification:fetchCompletionHandler:アプリがバックグラウンドにあるときにアプリのデリゲートのメソッドを呼び出すようにプッシュ通知のペイロードを構成できます。ここにフラグを設定して、ユーザーが次回アプリケーションを起動したときに操作を実行できるようにすることができます。

アップルのドキュメントから、このメソッドを使用してプッシュ通知に関連する新しいコンテンツをダウンロードする必要があります。また、このために仕事に、あなたがバックグラウンドモードからリモート通知を有効にすると、あなたのプッシュ通知ペイロードが含まれている必要があります持っているcontent-availableより多くの情報から1にその値が設定されたキーをリンゴのドキュメントからダウンロードセクションを開始するために、プッシュ通知の使用を参照してくださいここに

別の方法は、プッシュ通知ペイロードにバッジカウントを含めることです。したがって、次にアプリケーションを起動するときに、アプリケーションバッジの数を確認できます。ゼロより大きい場合は、操作を実行し、サーバーからゼロ/バッジのカウントをクリアします。

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


@bhusan私の質問の詳細を読んだことがありますか?通知が到着したとき(ユーザーがタップする前)にdidReceiveRemoteNotificationが呼び出されるのがわかります。ユーザーがそれをタップしたかどうかを確認したいと思いました。
Bao Lei

あなたはOPの質問に答えませんでした。彼は単に通知があったことを知りたいだけではありません。彼は、ユーザーがそのリモート通知をタップしてアプリを開いたかどうかを知りたいと考えています。
Joe C
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.