IOS 11 Beta 2では、アプリの状態(バックグラウンド/フォアグラウンド)に関係なく、サイレント通知はapplication:didReceiveRemoteNotification:fetchCompletionHandler
に配信されません。
UIApplicationDelegete
メソッドapplication:didReceiveRemoteNotification:fetchCompletionHandler
を実装し、次のようなサイレントプッシュを送ります。
{
"aps": {
"content-available": 1
},
"mydata": {
"foo": "bar"
}
}
しかし、デリゲートメソッドはiOS 11では呼び出されません。
他のバージョンのiOSでは問題なく動作します。ドキュメントセクション サイレント通知の設定 では、他に何もするべきであるとは言及されていません。
これはiOS 11のバグですか?それともiOS 11の新しい機能を見逃したのですか?
サイレントプッシュを送信するために必要とされるべきではないUserNotification
フレームワークについて話したり使用したりしていないことに注意してください。
これは問題を説明する サンプルプロジェクト です(あなた自身のバンドルIDを設定する必要があります)。
サンプルプロジェクトをランチして上記のペイロードをアプリに送信すると、macOSコンソールを使用してPushがデバイスに正しく配信されるがアプリには配信されないことを確認できます。
動作はランダムであるようです。デバイスを再起動した後にペイロードが正しく配信されても、しばらくすると機能しなくなることがあります。
次のスクリーンショットでわかるように、1とマークされたプッシュはデバイスにのみ配信され、プッシュ2(デバイスの再起動後)もアプリに配信されます。
それでも同じ動作です。もう1つうまくいくはずのことではありませんが、次のとおりです。アプリケーションのスキームが「実行可能ファイルが起動されるのを待つ」に設定されている場合、サイレントプッシュはアプリを起動してバックグラウンドで起動するはずです。
それでも同じ動作で、バグレポートはAppleからのアップデートではありません。
それでも同じ問題です。私が今使っている再現の手順は次のとおりです。
didReceiveRemoteNotification: fetchCompletionHandler
にブレークポイントを追加します予期されるもの:アプリは中断状態からバックグラウンドに移行し、didReceiveRemoteNotification: fetchCompletionHandler
が呼び出されます
実際:何も起こりません
私はまだ同じバグのある行動をしています。アップルからのチケットは次の答えで更新されました:
Apple Developer Relations September 6 2017、10:42 PM Engineeringがこの問題に関して以下のフィードバックを提供しています。
サンプルアプリケーションを実行して動作をテストできました。説明されているようにこれをテストしても、問題は発生しませんでした。
バックグラウンドで実行されているときにプッシュがアプリに届くことは保証されていません。ここにあるログは、アプリが起動するのに十分に使用されているとは思わないことを示しています。
状況が良いときにプッシュを配信するのを見ます。
これは正しく機能していると考えています。
私のAppleバグレポートはクローズされ、オープンのままの33278611
の複製としてマークされました
Kam800のコメント(下記参照)のおかげで、私はより多くのテストをし、それらの観察を思いついた。
IOS 11のdasd DuetActivitySchedulerDaemon
には、データプッシュを完全に破棄するかデータプッシュ配信を遅らせる新しいデーモンがあるようです。
コンソールログ
default 13:11:47.177547 +0200 dasd DuetActivitySchedulerDaemon CANCELED: com.Apple.pushLaunch.net.tequilaapps.daylight:C03A65 <private>! lifecycle com.Apple.duetactivityscheduler
default 13:11:47.178186 +0200 dasd DuetActivitySchedulerDaemon Removing a launch request for application <private> by activity <private> default com.Apple.duetactivityscheduler
default 12:49:04.426256 +0200 dasd DuetActivitySchedulerDaemon Advancing start date for <private> by 6.5 minutes to Wed Sep 13 12:55:31 2017 default com.Apple.duetactivityscheduler
default 13:21:40.593012 +0200 dasd DuetActivitySchedulerDaemon Activity <private>: Optimal Score 0.6144 at <private> (Valid Until: <private>) scoring com.Apple.duetactivityscheduler
default 13:21:40.594528 +0200 dasd DuetActivitySchedulerDaemon Setting timer (isWaking=1, activityRequiresWaking=0) between <private> and <private> for <private> default com.Apple.duetactivityscheduler
延期された配達問題
「サイレント通知は、アプリケーションが実行されていない場合でも、アプリケーションを最新の状態に保つのに役立つため、ユーザーエクスペリエンスが向上します。」
コンソールログ
default 13:35:05.347078 +0200 dasd DuetActivitySchedulerDaemon com.Apple.pushLaunch.net.tequilaapps.daylight:C03A65:[
{name: ApplicationPolicy, policyWeight: 50.000, response: {Decision: Must Not Proceed, Score: 0.00}}
], FinalDecision: Must Not Proceed} scoring com.Apple.duetactivityscheduler
配達の問題をキャンセルしました
この場合、データPushは完全に失われ、iOS 11では正しく配信されていましたがiOS 11では配信されませんでした。
また、アプリケーションがフォアグラウンドにあり、通知がアプリに配信されない場合は、コンソールに次のログが表示されます。
default 08:28:49.354824 +0200 apsd apsd <private>: Received message for enabled topic '<private>' onInterface: NonCellular with payload '<private>' with priority 10 for device token: NO courier-oversized com.Apple.apsd
fault 08:33:18.128209 +0200 dasd Foundation <NSXPCConnection: 0x151eee460> connection from pid 55: Exception caught during decoding of received message, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
Exception: value for key 'NS.objects' was of unexpected class 'NSNull'. Allowed classes are '{(
NSArray,
NSData,
NSString,
NSNumber,
NSDictionary,
NSUUID,
_DASActivity,
NSSet,
_DASFileProtection,
NSDate,
NWParameters,
NWEndpoint
)}'. general com.Apple.foundation.xpc
だからiOS 11.1 beta 1のリリースノートは言う
iOS 11.1 Beta 1がリリースされたばかりで、「通知の解決済みの問題•サイレントプッシュ通知がより頻繁に処理されます。(33278611)
私はいくつかのテストをしました、そしてそれは確かに固定されているようです:
一時停止モードでアプリを起動してサイレントプッシュを送信すると、アプリはバックグラウンドに戻り、didReceiveRemoteNotification:fetchCompletionHandler
デリゲートが呼び出されます。
同様に、アプリケーションがフォアグラウンドにあり、サイレントプッシュが送信されると、デリゲートは期待どおりに呼び出されるようです。これは以前のiOS 11バージョンではランダムに動作していなかったので、もっとテストした後に確認します。
私もこの問題に見舞われたので、ここに私の2セントを加えたいと思いました、そして私は、Appleがこの問題に関していくつかのレーダーを閉じてそれらが再現できなかったと言って気付いた。私が見つけた興味深いことは、それがデバッガに接続されている間にアプリがバックグラウンドである場合、プッシュが配信されることです。
デバッガを終了し、電話を抜いてアプリを起動し、サイレントなプッシュペイロードを送信すると、アプリが起動しなくなります。コンソールログに、システムがアプリケーションへのペイロードの配信をキャンセルしていることがわかります。
問題を再現した小さなサンプルアプリでレーダーを送信しました。私はまた、私のチケットで作業している人が、この問題を再現するためにデバッガに接続されているアプリケーションを実行してはならないことをレーダーで明確に指摘しました。これがリンクです: https://bugreport.Apple.com/web/?problemID=34461063
うまくいけば、これはこの問題に関していくらかの進歩をもたらすでしょう。
IOS 11の新しい動作のように見えます。iOS 11 beta 10は、この問題に関するいくつかの説明的なログを提供します。
default 23:18:51.806011 +0200 dasd com.Apple.pushLaunch.com.acme.Acme:F7E7D0:[
{name: ApplicationPolicy, policyWeight: 50.000, response: {Decision: Can Proceed, Score: 0.50}}
{name: BatteryLevelPolicy, policyWeight: 1.000, response: {Decision: Can Proceed, Score: 0.87, Rationale: [{batteryLevel == 62}]}}
{name: DeviceActivityPolicy, policyWeight: 5.000, response: {Decision: Can Proceed, Score: 0.20}}
] sumScores:52.279483, denominator:81.410000, FinalDecision: Can Proceed FinalScore: 0.642175}
default 23:18:51.806386 +0200 dasd 'com.Apple.pushLaunch.com.acme.Acme:F7E7D0' has compatibility score of 1.000000 with 'com.Apple.CFNetwork-cc-111-79:E7272D'. Relaxing scores.
default 23:18:51.806855 +0200 dasd 'com.Apple.pushLaunch.com.acme.Acme:F7E7D0' CurrentScore: 0.642175, ThresholdScore: 0.738454 DecisionToRun:0
サイレントプッシュはすべてiOSに配信されるように見えますが、dasdデーモンは、サイレントプッシュをアプリに配信する必要があるかどうかを判断するために、いくつかのポリシーを使用します(バッテリレベルなど)。私は昨日の夜に1つのサイレントプッシュを受け取ることができましたが、そのとき私のiPhoneは充電器に接続されていました - おそらくBatteryLevelPolicyスコアはその1つのサイレントプッシュを受け取るのに十分に高かった。
AppleはこのiOS側の動作に関する公式な情報を提供していません。サーバ側のスロットル調整に関する情報しかありません。
サイレント通知は、アプリをバックグラウンドで起動させ続けるためのものではなく、優先度の高い更新を目的としたものでもありません。 APNはサイレント通知を低い優先順位として扱い、総数が過剰になると、配信を完全に抑制することがあります。実際の制限は動的であり、状況に応じて変わる可能性がありますが、1時間に数回を超える通知を送信しないようにしてください。
私は私のアプリを修正するので、私は私の指を交差させ、彼らはその振る舞いを変更しました:)一方、この変更は良いです - 多くのことのうちの1つ。
iOS 11.1ベータリリースノートには以下が含まれます。通知解決された問題サイレントプッシュ通知はより頻繁に処理されます。 (33278611)
Apple Developer Relationsが私のレーダーにコメントを追加しました:
この問題は最新のiOS 11.2 Betaで解決されると考えています。
最新のiOSベータ版でテストしてください。それでも問題が解決しない場合は、関連するログや調査に役立つ可能性のある情報でバグレポートを更新してください。
現在iOS 11.2ベータ版をインストールしています - サイレントプッシュ動作をテストします
iOS 11.1 Beta 2にも含まれています
Notifications
Resolved Issues
• Silent Push notifications are processed more frequently. (33278611)
リリースノートで - 今それをテストします。
「現実世界のシナリオ」で2日間アプリを使用した後、iOSのこのバージョンには実際の改善が見られます。私は慎重にこれが修正されていると信じ始めています。
iOS 11.4.1、Swift 4
私は(CloudKitから)到着していないサイレントプッシュに関する問題を抱えていました、そして私は皆がここで言及したすべてを試みました。それから私はこのように私のCKNotificationInfo()
オブジェクトに空白のalertBody
を設定することを試みることにしました:
let info = CKNotificationInfo()
info.shouldSendContentAvailable = true
info.alertBody = ""
これはプッシュがより高い優先順位で送信されるようにしました(しかしそれらはまだ静かなプッシュでした)そして私はもはやプッシュが無視されていたという私のデバイスログのエラーを得ませんでした。
それが誰かに役立つことを願っています。 :)
回避策として、 "notification"キーを追加し、 "title"の内側に値として空の文字列を追加します。これはappDelegateでdidReceiveコールバックを起こすことです。
IOS 10までプッシュ通知を受け取り、application:didReceiveRemoteNotification:fetchCompletionHandler
が正しく呼び出されるまで、私は自分のアプリで同様の問題を抱えていました。ただし、iOS 11に更新されるとプッシュ通知が機能しなくなりました。
プッシュ通知ペイロードでcontent-available:1およびmutable-content:1を使用していたにもかかわらず、コードの問題がありましたが、Background Fetchオプションがオンになっていませんでした。しかし、それはiOS 10まで完全に働いていました。
バックグラウンドフェッチ機能をオンにした後、それは今働いています
この答えを書いている時点で、私は Bill Dunayの 答えとまったく同じ問題に直面しています。
私の要件は、アプリがフォアグラウンドにあるときはサイレント通知を受け取ることであり、アプリがバックグラウンドにあるとき、または実行されていないときには何もしないことです。そして私の回避策はこれでした。バッジを使用していないので、ゼロに設定しても問題にはなりません。
{
"aps" : {
"badge" : 0,
"sound" : ""
},
"mydata": {
"foo": "bar"
}
}
私は故意に "content-available"を使用していないことに注意してください。これを設定すると、iOS最適化ロジックは通知の配信を遅延/キャンセルします。
そのため、これは確かにiOS 11のバグであり、iOS 11 beta 3で修正されました。サイレントPushがフォアグラウンドまたはバックグラウンドの両方で受信されたときに、application:didReceiveRemoteNotification:fetchCompletionHandler
が正しく呼び出されるようになりました。
UPDATE
いいえ、それは修正されておらず、iOSベータ3と4でまだ起こっています
私はいくつかの通知について同じ問題を抱えています(必ずしも黙っているわけではありません)。
すべての更新と回答を確認した後、2つの更新を追加することができます。
通知を受け取っているときにUIApplication.shared.isRegisteredForRemoteNotifications
メソッドにアクセスすると、Xcodeに何も報告せずにアプリケーションが停止することがわかりました。メソッドにアクセスする通知を受け取ったら、コードを実行しているかどうかを確認してください。 ( isRegisteredForRemoteNotificationsでUIをsemaphore_wait_trap でロックしています)。
"title-loc-args" : [3333]
が文字通り3333を受け入れず、文字列"title-loc-args" : ["3333"]
として受け入れたために、コンソールでプッシュ通知の解析エラーが発生したことを発見しました。これは私が上記のメソッドにアクセスした後に私のインターフェース全体を失速させました、それはiOS 11でのみ、それはiOS 12で動作します。私は、まったく同じコードで、iOS 12.0(16A5366a)でも問題なく動作することもわかりました。しかし、iOS 11ではそうなっています。
私の場合、サーバーサイトで仕事が行われた後にサイレント通知がuiの更新に使用されたため、関連性のないコンテンツをアプリに含めるのは面倒でした。サイレント通知のペイロードにはタイトルと本文も含まれているため、アクティブでも非アクティブでも通知を受け取るためにこれらのメソッドを実装します。課金はしません。
これを機能させるために、デリゲートを追加し、UNUserNotificationCenterDelegate
name__プロトコルとwillPresent notification
(iOS 10+)メソッドを使用して拡張機能を作成します。これは毎回正しいペイロードでトリガーされます。アプリがアクティブなときに通知を表示しないようにするには、バッジまたは音声で補完を呼び出します。私はこのようなものになった
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
// MARK: - Lifecycle
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
return true
}
//this was only method to handle notifications before
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
//process silent notification
completionHandler(UIBackgroundFetchResult.newData)
}
}
extension AppDelegate : UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
//proces notification when app is active with `notification.request.content.userInfo`
if UIApplication.shared.applicationState == .active {
completionHandler(.badge)
}else {
completionHandler(.alert)
}
}
}
アプリがバックグラウンドでサイレント通知が行われているときにこれらの状態を機能させるには、通知センターからapplicationDidBecomeActive
name__で直接通知を受け取るメソッドを呼び出しません。
UNUserNotificationCenter.current().getDeliveredNotifications { (notifications) in
debugLog(message: "unprocessed notification count: \(notifications.count)")
if notifications.count > 0 {
notifications.forEach({ (notification) in
DispatchQueue.main.async {
//handle `notification.request.content.userInfo`
}
})
}
}