web-dev-qa-db-ja.com

アプリが実行されていない場合のプッシュ通知の処理

私のアプリがnot実行中にプッシュ通知を受け取ると、その通知をクリックすると、アプリが起動します-しかし次に、セットアップしたAlert-Viewでユーザーにプロンプ​​トを表示せず、通知の内容を表示するかどうかをユーザーに確認しません。起動するだけで、そこに座っています。

アプリisの場合、プッシュ通知は機能しますperfectly実行中-アクティブアプリとして、またはバックグラウンドで実行中-ただし、アプリがnotの場合は正常に動作しませんランニング。

launchOptions NSDictionaryをapplication: didFinishLaunchingWithOptions:からログアウトして、その負荷を確認しましたが、「(null)」として表示されます。それは基本的に何も含まれていません-通知の負荷を含めるべきではない理由は意味がありませんか?

アプリが実行されていないときにプッシュ通知が届くようにする方法はありますか?

編集:これは何が何であるかを見るためにapplication: didReceiveRemoteNotificationで使用しているコードです:

if (UIApplicationStateBackground) {

    NSLog(@"===========================");
    NSLog(@"App was in BACKGROUND...");
}
else if (UIApplicationStateActive == TRUE) {
    NSLog(@"===========================");
    NSLog(@"App was ACTIVE");
}
else {
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber: 99]; 
    UIAlertView *BOOM = [[UIAlertView alloc] initWithTitle:@"BOOM"
                                                   message:@"app was INACTIVE"
                                                  delegate:self
                                         cancelButtonTitle:@"a-ha!"
                                         otherButtonTitles:nil];
    [BOOM show];
    NSLog(@"App was NOT ACTIVE");
}

したがって、これはアプリケーションのすべての状態を処理することになっていますが、そうではありません。プッシュ通知は、アプリが実行されている場合にのみ機能します-バックグラウンドまたはフォアグラウンドで...

================================================

更新/編集#2:「@dianz」の提案(下記)に従って、application: didFinishLaunchingWithOptionsのコードを変更して、以下を含めました。

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
    NSString *json = [localNotif valueForKey:@"data"]; 

    UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"appDidFinishWithOptions"
                                                  message:json   
                                                 delegate:self
                                        cancelButtonTitle:@"cool"
                                        otherButtonTitles:nil];
    [bam show];

}

これによりAlertViewボックスが表示されますが、ペイロードはないようです。AlertViewのタイトルは表示されますが( "appDidFinishWithOptions")、json NSStringは空になります...調整を続けます...

=======================

EDIT#3-現在動作中almost100%
したがって、didFinishLaunchingWithOptionsで:

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if (localNotif) {
        // Grab the pushKey:
        pushKey = [localNotif valueForKey:@"pushKey"];
        // "pushKey" is an NSString declared globally
        // The "pushKey" in the "valueForKey" statement is part of my custom JSON Push Notification pay-load.
        // The value of pushKey will always be a String, which will be the name of the 
        // screen I want the App to navigate to. So when a Notification arrives, I go
        // through an IF statement and say "if pushKey='specials' then Push the                                      
        // specialsViewController on, etc.

        // Here, I parse the "alert" portion of my JSON Push-Notification:
        NSDictionary *tempDict = [localNotif valueForKey:@"aps"];
        NSString *pushMessage = [tempDict valueForKey:@"alert"];


        // Finally, ask user if they wanna see the Push Notification or Cancel it:
        UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"(from appDidFinishWithOptions)"
                                                      message:pushMessage  
                                                     delegate:self
                                            cancelButtonTitle:@"Cancel"
                                            otherButtonTitles:@"View Info", nil];
        [bam show];

    }

次に、alertView: clickedButtonAtIndexメソッドを実装して、ユーザーがAlertViewで選択したものを確認し、それに応じて続行します。

これは、didReceiveRemoteNotificationロジックとともに完全に機能します。

しかし...アプリが実行されていないときにプッシュ通知を送信します。プッシュ通知アラートが到着したらすぐにクリックしないで、代わりにフェードアウトするのを待ちます(3 4秒)、およびthenアプリのアイコンをクリックします-これにはBADGEが1になっています-アプリは起動しますが、私はしません起動時にプッシュ通知アラートを取得します。ただそこに座っています。

次に、that順列を計算する必要があると思います...

42
sirab333

アプリが実行されていないか、強制終了されていないときにプッシュ通知をタップすると、この機能がトリガーされます。

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

このように処理する必要があります

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
    NSString *json = [localNotif valueForKey:@"data"];
    // Parse your string to dictionary
}
36
dianz

didReceiveRemoteNotificationをオーバーライドする方が良い

NSDictionary * pushNotificationPayload = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(pushNotificationPayload) {
    [self application:application didReceiveRemoteNotification:pushNotificationPayload];
}

これは再びdidReceiveRemoteNotificationメソッドとPush notificationコードは、アプリケーションの実行時に実行されるのと同じように実行されます。

11
Vaibhav Saran

@dianzの答えを試してみました。うまくいきませんでしたが、答えから助けを得ました。

私の場合;

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

NSDictionary *apnsBody = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (apnsBody) {
    // Do your code with apnsBody
}
7
drskur

私は同じ問題を抱えていましたが、Notification Service Extensionを使用して非アクティブ(実行されていない)のときにプッシュ通知を処理できました。このソリューションは、Apple Team Supportによって推奨されました。iOS10専用です。実装し、正常に動作します!リンクを残します。

https://developer.Apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ModifyingNotifications.html

これは手順です:

  1. アプリの新しい通知サービス拡張機能を作成します。プロジェクトを開き、[ファイル]-[新規]-[ターゲット]を押し​​て、iOSセクションで[通知サービス拡張]オプションを選択します。拡張機能の名前と必要な情報を入力します。その後、Xcodeは、Objective C言語の2つのファイルを追加します:.hおよび.mファイル。

注:次の3つの識別子を使用することを検討してください。1)アプリの識別子(既に持っている)2)拡張機能の識別子(作成します)3)App Groupの識別子。 (作成します)

  1. App Groupsを有効にして、アプリと拡張機能の情報を保存および読み取ることができるリソースを作成する必要があります。 [Project Navigatorの表示]をクリックします。ターゲットのリストで、メインプロジェクトを選択します。次に、[機能]をクリックして、[アプリグループ]というオプションをオンにします。 App Groupの識別子を追加して、共有リソースを識別してください。作成した拡張機能のターゲットに対して同じ手順を実行する必要があります(拡張機能のターゲットを選択-機能-「アプリグループ」でスイッチオン-アプリグループに同じ識別子を追加)

  2. 拡張機能の識別子をApple Notification Service Extensionを識別するための開発者サイトに追加する必要があります。また、新しい暫定プロファイル(開発、アドホックおよび/またはプロダクション)を作成し、関連付けます。新しい暫定プロファイル。

  3. 両方の識別子(アプリと拡張機能)でそれらを編集し、両方で「アプリグループ」サービスを有効にする必要があります。アプリグループの識別子をアプリグループサービスに追加する必要があります。

注:アプリの識別子と拡張機能の識別子には、アプリグループの同じ識別子が必要です。

  1. Xcodeで新しい暫定プロファイルをダウンロードし、Notification Service Extensionに関連付けます。すべて問題ないことを確認してください。

  2. その後、アプリと拡張機能の「機能」に「アプリグループ」セクションを開き、更新します。 3つのステップ-1)エンタイトルメントファイルにアプリグループのエンタイトルメントを追加する、2)アプリIDにアプリグループ機能を追加する、3)アプリIDにアプリグループを追加する-チェックする必要があります。

  3. Projectナビゲーターに戻り、拡張機能のフォルダーを選択します。 .mファイルを開きます。 didReceiveNotificationRequest:(UNNotificationRequest *)requestというメソッドが表示されます。この方法では、次のように、アプリグループの識別子とまったく同じSuiteNameを持つ異なるNSUserDefaultsを作成します。

    NSUserDefaults * defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName:@ "アプリグループの識別子"];

  4. この同じメソッドに、通知の本文を取得してNSMutableArrayに保存し、共有リソースに保存します。このような:

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler{
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];

    NSMutableArray *notifications = [NSMutableArray new];
    NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
    notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
    if (notifications != nil){
        [notifications addObject:self.bestAttemptContent.userInfo];
    }else{
        notifications = [NSMutableArray new];
        [notifications addObject:self.bestAttemptContent.userInfo];
    }
    [defaultsGroup setObject:notifications forKey:@"notifications"];    
}
  1. 最後に、メインプロジェクトのApp DelegateのdidFinishLaunchingWithOptionsメソッドで、次のコードを使用して配列を共有リソースに復元します。
NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
  1. 楽しめ!

各ステップで明確になることを願っています。ページに画像を使用してこのソリューションを実装するための投稿を作成します。考慮すべきもう1つの点は、サイレントプッシュ通知では機能しないことです。

3

これは回答済みですが、提供された回答はどれも実際には正しく機能しませんでした。ここに私が機能するようになった実装があります。

このコードは_application:didFinishLaunchingWithOptions:_に入ります

スイフト:

_if let options = launchOptions, notification = options[UIApplicationLaunchOptionsRemoteNotificationKey] as? [NSObject : AnyObject] {
    // NOTE: (Kyle Begeman) May 19, 2016 - There is an issue with iOS instantiating the UIWindow object. Making this call without
    // a delay will cause window to be nil, thus preventing us from constructing the application and assigning it to the window.
    Quark.runAfterDelay(seconds: 0.001, after: {
        self.application(application, didReceiveRemoteNotification: notification)
    })
}
_

目的C:

_if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
    [self application:application didReceiveRemoteNotification:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
}
_

いくつかのメモ:

  • おそらくiOSが割り当てをキューする方法が原因で、ルートUIApplication.sharedApplication().windowオブジェクトは、強制終了後にアプリケーションを起動するときにnilになります。 1ミリ秒の遅延を追加すると、この問題が修正されました。これをObjective-Cでテストしませんでした

  • 型の競合を防ぐために、[NSObject:AnyObject]へのキャストが必要でしたが、私はこれほど実験しませんでした。自分のプロジェクトに実装するときは、それを覚えておいてください。 Objective-Cではこれは必要ありません。

  • Quarkは、便利で一般的に使用される拡張機能とメソッドを含む、すべてのプロジェクトで使用する楽しい小さなライブラリです。アプリケーションのニーズに合う任意の形式の遅延を使用するだけです。

3
Kyle Begeman

didReceiveRemoteNotificationメソッドに移動して、そこで処理してみてください。そこでは、applicationStateの条件を実行することでアプリケーションの状態を確認できます。たとえば、UIApplicationStateActiveかどうかを確認できます。

1
NeonBlueHair

SwiftおよびxCode 8.3.2

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

    // Check if app was not running in background and user taps on Push Notification
    // This will perform your code in didReceiveRemoteNotification where you should handle different application states
    if let options = launchOptions, let notification = options[UIApplicationLaunchOptionsKey.remoteNotification] as? [NSObject : AnyObject] {
        self.application(application, didReceiveRemoteNotification: notification)
    }

    return true
}
0
Eugene Pavlov

これを試して

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    //register notifications
    if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) // ios 8
    {
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
        [application registerForRemoteNotifications];
    }
    else // ios 7
    {
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge];
    }

    // open app from a notification
    NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    if (notification) 
    {
        //your alert should be here
    }

    // Set icon badge number to zero
    application.applicationIconBadgeNumber = 0;

    return YES;
}
0
Cayke Prudente