web-dev-qa-db-ja.com

サイレントプッシュ通知は、デバイスが充電中またはアプリがフォアグラウンドの場合にのみ配信されます

サイレントプッシュ通知を実装しましたが、奇妙な動作に気付きました。サイレントプッシュ通知は、次の方法で処理されます。

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

サイレントプッシュメッセージは、デバイスが充電されている(ケーブルが接続されている)場合や、アプリがフォアグラウンドの場合にのみ受信されるようです。

デバイスを充電器(またはMac)から切断すると、サイレントプッシュ通知は受信されなくなりますnlessアプリはフォアグラウンドになります。

どちらの場合も、通常、非サイレントプッシュ通知を受け取ります。

USBケーブルを再度接続すると、アプリがフォアグラウンドであるかバックグラウンドであるかに関係なく、予期した動作が得られ、サイレントプッシュ通知が受信されます。

UILocalNotificationを使用しているので、受信内容を把握しています。

接続されたデバイスですべて正常に動作するという事実は、私のサイレントプッシュ通知が正しく構成されており、アプリがplistなどで設定された正しいバックグラウンドモードを持っていることを示唆しています.

この動作は、iPhone 5s、6、およびiPad 2でIOS 8または8.1。

他の誰かがこれを経験しましたか?簡単に再現できるはずです。デバイスを充電器に接続するだけで、サイレントプッシュ通知を受信する機能が変わるのはなぜですか?

54
user1024447

私たちは同じ振る舞いを経験し、iOSが他の通知ではなく一部の通知を配信することにした理由を理解しようとしました。

これまでに取り組んできたのは次のとおりです。

  • WiFiよりも携帯電話のデータの場合、メッセージはバックグラウンドでより確実に受信されます。実際、セルラーネットワーク(3g/4g)で信号強度が十分でない場合、iOSはプッシュメッセージを受信しますが、アプリを起動しません。 Appleそれに関するフォーラムをここに投稿しました: https://devforums.Apple.com/message/1069814#1069814 。また、サポートチケットを開きました。サポートチームからバグ報告として提出するように指示がありました。これは数週間前に行ったもので、まだ返事を待っています。

  • プッシュメッセージを受信したら、できるだけ早くfetchCompletionHandlerを呼び出す必要があります。技術的には30秒のバックグラウンド処理を実行できますが、iOSには、プッシュメッセージをより頻繁に送信し、アプリをサスペンド状態に戻す前にそれらのメッセージの処理に費やす時間に応じて、iOSが量を減らす式が用意されています将来、アプリが起動されることがあります。

こちらをご覧ください Apple didReceiveRemoteNotification:fetchCompletionHandler: documentation:

通知の処理が完了したらすぐに、ハンドラーパラメーターでブロックを呼び出す必要があります。そうしないと、アプリが終了します。アプリには、通知を処理し、指定された完了ハンドラーブロックを呼び出すための最大30秒の実時間があります。実際には、通知の処理が完了したらすぐにハンドラーブロックを呼び出す必要があります。システムは、アプリのバックグラウンドダウンロードの経過時間、電力使用量、データコストを追跡します。プッシュ通知の処理時に大量の電力を使用するアプリは、将来の通知を処理するために必ずしも早期に起動されるとは限りません。

テストでは、アプリに頻繁にサイレントプッシュ通知を送信しています(10〜30秒ごと)。そして、アプリはスリープ状態に戻るまで約3秒間起動しています。 iOSが15分から30分ごとにのみアプリを起動するようになるまで、アプリが起動される頻度の低下に時間の経過とともに確実に気づきました。そのため、ある種の減衰/調整式が用意されているようですが、正確に機能する方法についてのドキュメントは見つかりません。この式と変数をAppleからサポートリクエストとしてリクエストしましたが、「リクエストしている情報は公開されていません」と言って、再度バグレポートを提出するよう依頼しました。

それで、うまくいけば、これは役に立ちますか?私たちはまだ自分自身をもっと学ぼうとしているので、この質問を見つけました:)

60
Kevin D.

IOS8バックグラウンドでは、アプリへのプッシュ配信が変更されました。バックグラウンドプッシュは、特定の状況下でのみアプリに配信されるようになりました。 Appleこれらの状況が何であるかを明確に述べていませんが、私の広範な実験から、基本的には電話が充電されているかどうかに帰着します。 、デバイスの種類、Wi-Fiが有効になっています)が、Pushの到着時にデバイスが充電されているかどうかが主要な主要な要因です。

電話が直接主電源を介して、またはUSBによってコンピューターに接続されて間接的に充電されている場合、バックグラウンドプッシュはほとんどの時間アプリに配信されます。ただし、電話機を電源またはUSBから切断すると、電話機のバッテリーの充電が100%であっても、バックグラウンドプッシュはほとんどアプリに配信されません。

電話の充電中とそうでないときのプッシュを送信するだけで、これを自分で簡単にテストできます。ただし、開発ビルドでのバックグラウンドプッシュおよびサンドボックス環境の使用は、本番ビルドおよび本番環境でのバックグラウンドプッシュと同じように動作しないことを考慮する必要があります。実際、バックグラウンドプッシュは開発中のアプリに配信される可能性が高くなりますその後、実稼働環境にあるため、実稼働ビルドとAppleの実稼働環境を使用してテストし、実際の結果を確認することが重要です。

プッシュ配信には2つのステップがあることに注意してください。1つ目は電話自体に配信する必要があり、2つ目は電話が取得したらOSからアプリに配信する必要があることです。 iOS7では、Wifiのチューリングなどにより、プッシュが電話に届く可能性が高くなりました。ただし、iOS8では、プッシュが電話に正常に配信されていても、電話が充電されていない場合、OSはプッシュをバックグラウンドアプリに転送しません。これは、電話が充電されていない場合にアプリに転送する前に、電話が通知を取得し、時には数時間保持することを意味します。

9
Gruntcakes

私は同じ問題を経験していましたが、アプリが充電されていないときにプッシュ通知を受け取らない理由は、低電力モードがSettings > Battery無効にしますbackground-fetchすべてのアプリケーションの機能。

デバイスがプッシュ通知を受信できなくなります。

このリンクは役に立つかもしれません。 Appleドキュメント

8
Manan Devani

私も同じことに気づき、理解するのに時間を浪費しました。 https://stackoverflow.com/a/31237889/172476 を参照してください

Bg App Refreshをオフにすると、サイレントリモートプッシュはサイレントにドロップされます(皮肉)。

ただし、ケーブルを介してXcodeに接続すると、何らかの理由でBgアプリの更新設定が無視され、アプリのすべてのサイレントプッシュが機能するというのが私の観察です。

これは文書化されていない機能であると非常に疑っています。充電すると、Bg App Refresh設定が無視されます。

5
Mave

Plistで間違ったバックグラウンドモードを有効にしているため、機能していません。フェッチではなく、remote-notificationタグ(アプリはプッシュ通知に応じてコンテンツをダウンロードします)を有効にする必要があります。フェッチは他の目的に使用されます。また、JSONペイロードでコンテンツ利用可能なキーを使用する必要がある場合があります。

{
   "aps": {
      "content-available": 1
    },
    "yourdatakey":{data}
}
2
jrlocke

[〜#〜] apns [〜#〜]を使用して、"CONSERVE_POWER" (5)として優先度を設定し、"IMMEDIATE" (10)として変更してください。

1
Mohamed yaseen

アプリがIS VoIPではない場合、この回答に従うことはできません[アプリは拒否されます]

PushKit Framework を使用して私のために働いている別のソリューションを見つけました

VoIPプッシュは、ユーザーに通知を表示する前にプッシュのオンデマンド処理を実行するためにVoIPアプリに必要な標準プッシュに加えて追加機能を提供します

VoIPプッシュを送信すると、アプリケーションの状態に関係なくアプリが起動し、任意の操作を実行できます

DidFinishLaunchingWithOptionsでVOIP PushNotificationに登録する

 PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];


- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
if([credentials.token length] == 0) {
    NSLog(@"voip token NULL");
    return;
}

NSString *originalToken=[NSString stringWithFormat:@"%@",credentials.token];
NSString *token = [originalToken stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"<>"]];
token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"PushCredentials: %@",token);}

vOIP PushNotificationを受け取ったら、この関数でバックグラウンドフェッチを処理できます

-(void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type

注:VoIPサービス証明書を有効にする証明書を使用する必要があります

enter image description here

0
khaled

私はしばらくの間この問題を経験してきましたが、この質問と@Kevin D.が彼らの理解を共有してくれたことにとても感謝しています。 https://stackoverflow.com/a/30834566/1449799https://developer.Apple.com/library/ios/documentation/NetworkingInternet/ Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html#// Apple_ref/doc/uid/TP40008194-CH101-SW4 (いずれかの表のpriorityを参照)は、アプリに問題がある理由を説明しています。

content-availableキーのみを含むプッシュにこの優先度を使用するとエラーになります。

通知を送信するために、私は node-apn を使用しています。デフォルト(これも必要です)は、優先度を最大に設定することです(10 [注意、それは105は、現時点では正しい値です])、しかしsilent通知が欲しかったので、alertがありません、badge、またはsoundセット。

0
Michael