axiom-push-notifications-diag について
iOS のプッシュ通知を調査する開発者向けスキルです。ペイロードや配信を調べる前に、権限設定とトークン登録を確認する手順を示します。
主な機能
- 01権限とトークンの確認
- 02APNs ペイロードの検証
- 03通知許可状態の確認
- 04診断用デシジョンツリー
- 05Simulator と FCM の診断
活用シーン
- 01通知が届かない問題の調査
- 02開発環境と本番環境の差の分析
- 03サイレント通知やリッチ通知の診断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-push-notifications-diagインストール後、Claude Code で/axiom-push-notifications-diagを入力して読み込まれたか確認します。
詳細
プッシュ通知の診断
プッシュ通知の失敗を体系的にトラブルシューティングします。通知が届かない、トークン登録エラー、環境の不一致、サイレントプッシュのスロットリング、サービス拡張の問題に対応します。
概要
基本原則:プッシュ通知が機能しない場合、通常は次のいずれかが原因です。
- トークン/登録の失敗(未登録、形式の誤り、有効期限切れ)— 30%
- エンタイトルメント/プロビジョニングの不一致(機能が未設定、環境の誤り)— 25%
- ペイロード構造のエラー(キーの欠落、型の誤り、無効な JSON)— 15%
- 集中モード/割り込みによる抑制(iOS 15 以降のフィルタリング、仮登録認証)— 15%
- サービス拡張の失敗(タイムアウト、クラッシュ、mutable-content の欠落)— 10%
- 配信タイミング/スロットリング(サイレントプッシュの予算、APNs による集約)— 5%
ペイロードや配信ロジックをデバッグする前に、必ずエンタイトルメントとトークン登録を確認してください。
注意すべき兆候
プッシュ通知固有の問題を示す症状:
| 症状 | 考えられる原因 |
|---|---|
| 通知がまったく届かない | プッシュ通知機能またはプロビジョニングプロファイルが未設定 |
| 開発環境では動作するが、本番環境では動作しない | 本番用トークンを使ってサンドボックス APNs に送信している(またはその逆) |
| Simulator でトークン登録に失敗する | 仕様どおり — Simulator はリモート通知に登録できません |
| 通知は表示されるがサウンドが鳴らない | 認証オプションまたはペイロードに .sound がない |
| リッチ通知が通常のテキストで表示される | ペイロードに mutable-content: 1 がない |
| 通知に画像が表示されない | サービス拡張がサイレントに失敗している — serviceExtensionTimeWillExpire を確認してください |
| サイレントプッシュでアプリが起動しない | システムによるスロットリング(約 2~3 回/時間)、またはユーザーがアプリを強制終了した |
| iOS のアップデート後に通知が停止した | iOS 15 以降では集中モードがデフォルトで有効です。割り込みレベルを確認してください |
| バッジの数字が正しくない | 明示的にバッジ数をリセットせずに、複数の通知を送信している |
| アクションが表示されない | ペイロードのカテゴリ識別子と登録済みカテゴリが一致していない |
| 通知が 2 回表示される | 同じイベントに対してローカル通知とリモート通知の両方がスケジュールされている |
| FCM は Android では動作するが、iOS では動作しない | Firebase Console に APNs 認証キーがアップロードされていない |
根拠のない判断
| 根拠のない判断 | うまくいかない理由 | 時間の損失 |
|---|---|---|
| 「昨日は動いたから、エンタイトルメントは問題ない」 | 署名設定の変更時にプロビジョニングプロファイルが再生成されます。必ず再確認してください。 | プロファイルからプッシュ機能が失われた状態でコードをデバッグするのに30~60分 |
| 「サーバーはペイロードに問題ないと言っている」 | プッシュ通知の失敗の55%はクライアント側が原因です(エンタイトルメントとトークン)。curl で個別に検証してください。 | 誰かが確認するまで責任のなすり合いに1~2時間 |
| 「トークンの検証は省略します。エラーがペイロードにあるのは明らかです」 | 環境が異なるトークンは、「開発環境では動くが、本番環境では動かない」問題の最大の原因です。 | 有効なペイロードを無効なトークンに送信して、デバッグに30分以上 |
| 「集中モードは関係ありません。デフォルトの割り込みレベルを使っています」 | デフォルト(active)は集中モードによってフィルタリングされます。突破できるのはtime-sensitiveとcriticalだけです。 | ペイロード側で修正できる問題に対して、コードで回避策を追加するのに数時間 |
| 「サイレントプッシュは信頼できるので、同期に使っています」 | システムは1時間あたり約2~3回に制限し、強制終了されたアプリは無視します。これはヒントであり、保証ではありません。 | サイレントプッシュでリアルタイム同期を維持できず、アーキテクチャを再設計 |
| 「サービス拡張機能は設定済みなので、リッチ通知は動作するはずです」 | 拡張機能には、正しいバンドル ID のサフィックス、ペイロード内のmutable-content、そして30秒以内の処理完了が必要です。 | 3つの前提条件のうち1つでも欠けている場合、30分以上 |
| 「FCM がすべて処理するので、APNs を理解する必要はありません」 | FCM は APNs をラップしています。トークンタイプの混同、p8 キーのアップロード漏れ、スウィズリングの競合は、いずれも APNs 側の問題です。 | 問題が APNs の設定にあるのに、FCM のデバッグに数時間 |
| 「まず Simulator でテストします」 | Simulator はリモート通知に登録できません。APNs トークンがなければ、実際のプッシュ通知をテストできません。 | Simulator の制限に気づくまで、テストサイクルを無駄にする |
| 「通知ハンドラーを書き直します」 | プッシュ通知の失敗の80%はコードではなく、設定(エンタイトルメント、トークン、環境)が原因です。 | 設定が壊れたまま、動作しているコードを書き直すのに数時間 |
| 「iOS 17 では動いていたので、バグはコードにあるはずです」 | iOS のバージョンごとに、集中モードのデフォルト、割り込みのフィルタリング、暫定的な通知の挙動が変わります。 | 修正がペイロードや設定の変更で済むのに、コードをデバッグする |
必須の最初の手順
コードを調査する前に、次の診断を実行してください。
ステップ1:プッシュ通知のエンタイトルメントを確認する
security cms -D -i path/to/embedded.mobileprovision | grep -A1 "aps-environment"
期待される出力:
- ✅
<string>development</string>または<string>production</string>→ エンタイトルメントが存在します - ❌ aps-environment キーがない → Xcode でプッシュ通知機能が有効になっていません
プロビジョニングプロファイルの場所:
# For installed app on device
find ~/Library/Developer/Xcode/DerivedData -name "embedded.mobileprovision" -newer . 2>/dev/null | head -3
ステップ2:トークンの登録を確認する
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%02x", $0) }.joined()
print("✅ APNs token: \(token)")
print("✅ Token length: \(token.count) chars")
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("❌ Registration failed: \(error.localizedDescription)")
}
期待される出力:
- ✅ 64文字の16進数トークン → 登録に成功しました
- ❌ 「no valid aps-environment entitlement」→ 機能の設定が正しくありません
- ❌ コールバックが一切呼び出されない →
registerForRemoteNotifications()が呼び出されていません
重要:両方のコールバックはSceneDelegateではなく、AppDelegateに記述する必要があります。SwiftUI アプリでは@UIApplicationDelegateAdaptorが必要です。
ステップ3:curl でペイロードを検証する
curl -v \
--header "apns-topic: com.your.bundle.id" \
--header "apns-push-type: alert" \
--header "authorization: bearer $JWT_TOKEN" \
--data '{"aps":{"alert":{"title":"Test","body":"Hello"}}}' \
--http2 https://api.sandbox.push.apple.com/3/device/$DEVICE_TOKEN
期待される出力:
- ✅ HTTP/2 200 → APNs がペイロードを受け付けました
- ❌ 400 BadDeviceToken → トークンの形式が間違っているか、有効期限が切れています
- ❌ 403 ExpiredProviderToken → JWT の有効期限が1時間を超えています
- ❌ 403 InvalidProviderToken → キー ID、チーム ID、またはキーが間違っています
- ❌ 410 Unregistered → アプリがアンインストールされたか、トークンが無効になっています
- ❌ 413 PayloadTooLarge → 4096バイトを超えています
ステップ4:認証ステータスを確認する
let settings = await UNUserNotificationCenter.current().notificationSettings()
print("Authorization: \(settings.authorizationStatus.rawValue)")
print("Alert: \(settings.alertSetting.rawValue)")
print("Sound: \(settings.soundSetting.rawValue)")
print("Badge: \(settings.badgeSetting.rawValue)")
期待される出力:
- ✅ authorizationStatus = 2 → 許可されています
- ⚠️ authorizationStatus = 3 → 暫定的な許可です(通知センターにサイレントに表示されます)
- ❌ authorizationStatus = 1 → ユーザーに拒否されています
- ❌ authorizationStatus = 0 → 未確認です(許可をまだ要求していません)
判断ツリー
ツリー1:通知をまったく受信できない
Not receiving any notifications?
│
├─ Check Step 1 (entitlements)
│ ├─ No aps-environment key?
│ │ └─ Enable Push Notifications in Signing & Capabilities → DONE
│ └─ aps-environment present → continue
│
├─ Check Step 2 (token registration)
│ ├─ didFailToRegister called?
│ │ ├─ "no valid aps-environment" → Regenerate provisioning profile
│ │ └─ Other error → Check network, device (not Simulator)
│ ├─ Neither callback fires?
│ │ └─ Verify registerForRemoteNotifications() called after app launch
│ └─ Token received → continue
│
├─ Check Step 3 (payload delivery)
│ ├─ HTTP 200 but no notification?
│ │ └─ Check Step 4 (authorization status)
│ ├─ 400 BadDeviceToken?
│ │ └─ Token expired or wrong environment → Re-register
│ └─ 403/410 error?
│ └─ Fix auth credentials or re-register device
│
└─ Check Step 4 (user authorization)
├─ Status: denied?
│ └─ User must enable in Settings → Show settings prompt
├─ Status: notDetermined?
│ └─ Call requestAuthorization() → Was never requested
└─ Status: authorized but still no notifications?
└─ Check Focus mode, Do Not Disturb, notification grouping
ツリー2:開発環境では動くが、本番環境では動かない
Works in development, fails in production?
│
├─ APNs endpoint correct?
│ ├─ Dev: api.sandbox.push.apple.com
│ └─ Prod: api.push.apple.com
│ └─ Using sandbox endpoint with production build? → Switch endpoint
│
├─ Token environment matches?
│ ├─ Dev and production tokens are DIFFERENT
│ │ └─ Server storing dev token, sending to prod APNs? → Re-register on prod build
│ └─ Server distinguishes token environments? → Add environment flag to token storage
│
├─ Auth method correct?
│ ├─ .p8 key (token-based)?
│ │ └─ Same key works for both environments ✅
│ └─ .p12 certificate?
│ ├─ Dev cert → Only works with sandbox
│ └─ Prod cert → Only works with production
│ └─ Wrong cert for environment? → Generate correct certificate
│
└─ Using FCM?
├─ APNs auth key (.p8) uploaded to Firebase Console?
│ └─ Missing? → Upload in Project Settings > Cloud Messaging
└─ Key uploaded but wrong Team ID?
└─ Verify Team ID matches Apple Developer account
ツリー3:サイレント通知でアプリが起動しない
Silent push not waking app?
│
├─ Payload correct?
│ ├─ Has "content-available": 1 in aps?
│ │ └─ Missing? → Add to aps dictionary
│ ├─ Has NO "alert", "badge", or "sound" in aps?
│ │ └─ Has alert? → Not a silent push; system treats as visible notification
│ └─ Payload valid → continue
│
├─ Headers correct?
│ ├─ apns-push-type: background?
│ │ └─ Missing or wrong? → Must be "background" for silent push
│ └─ apns-priority: 5?
│ └─ Using 10? → Silent push MUST use priority 5
│
├─ Background mode enabled?
│ ├─ "Remote notifications" checked in Background Modes capability?
│ │ └─ Missing? → Enable in Signing & Capabilities
│ └─ application(_:didReceiveRemoteNotification:fetchCompletionHandler:) implemented?
│ └─ Missing? → Implement the delegate method
│
├─ App state?
│ ├─ Force-quit by user (swiped up)?
│ │ └─ System will NOT wake force-quit apps for silent push
│ └─ Suspended or background?
│ └─ Should wake — continue debugging
│
└─ System throttling?
├─ Budget: ~2-3 silent pushes per hour
│ └─ Exceeding? → Reduce frequency, batch updates
└─ Device in Low Power Mode?
└─ Further reduces background execution budget
ツリー4:リッチ通知にメディアが表示されない
Rich notification not showing image/video?
│
├─ Payload has mutable-content: 1?
│ └─ Missing? → Required for Notification Service Extension to fire
│
├─ Notification Service Extension target exists?
│ ├─ Missing? → File > New > Target > Notification Service Extension
│ └─ Exists → continue
│
├─ Extension bundle ID correct?
│ ├─ Must be: {app-bundle-id}.{extension-name}
│ │ Example: com.myapp.NotificationService
│ └─ Wrong prefix? → Fix bundle ID to match parent app
│
├─ Download completing in time?
│ ├─ Extension has ~30 seconds to modify notification
│ │ └─ Large file? → Use thumbnail URL, not full resolution
│ └─ serviceExtensionTimeWillExpire called?
│ └─ Must deliver bestAttemptContent with fallback text
│
├─ Attachment created correctly?
│ ├─ File written to disk before creating UNNotificationAttachment?
│ │ └─ Must write to tmp directory, then create attachment from file URL
│ └─ File type supported?
│ ├─ Images: JPEG, GIF, PNG (max 10MB)
│ ├─ Audio: AIFF, WAV, MP3, M4A (max 5MB)
│ └─ Video: MPEG, MPEG-2, MP4, AVI (max 50MB)
│
└─ App groups configured?
└─ Extension and app share data via App Groups?
└─ Missing? → Add same App Group to both targets
ツリー5:プッシュ通知経由でライブアクティビティが更新されない
Live Activity not updating from push?
│
├─ APNs topic correct?
│ ├─ Must be: {bundleID}.push-type.liveactivity
│ │ └─ Using plain bundle ID? → Append .push-type.liveactivity
│ └─ Topic correct → continue
│
├─ Push type header correct?
│ ├─ apns-push-type: liveactivity?
│ │ └─ Using "alert"? → Must be "liveactivity"
│ └─ Correct → continue
│
├─ Content-state matches ActivityAttributes.ContentState?
│ ├─ JSON keys match Swift property names exactly?
│ │ └─ Mismatch? → Decoding fails silently
│ └─ Using custom CodingKeys or JSONEncoder strategies?
│ └─ Custom strategies NOT supported — use default key encoding
│
├─ Push token being sent to server?
│ ├─ Observing pushTokenUpdates on the Activity?
│ │ └─ Missing? → Must iterate Activity.pushTokenUpdates async sequence
│ └─ Token changes when Activity restarts?
│ └─ Must handle token rotation — send updated token to server
│
└─ Rate limiting?
├─ Frequent updates: ~10-12 per hour per Activity
│ └─ Exceeding? → Batch updates, reduce frequency
└─ Alert updates (sound/vibration): ~3-4 per hour
└─ Exceeding? → Reserve alerts for critical state changes
ツリー 6:iOS のアップデート後に通知が停止した
Notifications stopped working after iOS update?
│
├─ Focus mode auto-enabled? (iOS 15+)
│ ├─ Check Settings > Focus
│ │ └─ Focus active? → App may not be in allowed list
│ └─ No Focus active → continue
│
├─ Interruption level filtering?
│ ├─ Default level is .active (may be filtered by Focus)
│ │ └─ Need to break through Focus? → Use .timeSensitive or .critical
│ ├─ .timeSensitive requires capability
│ │ └─ Missing? → Add Time Sensitive Notifications capability
│ └─ .critical requires Apple entitlement
│ └─ Only for health/safety/security apps — apply via Apple Developer
│
├─ Provisional authorization behavior changed?
│ ├─ iOS 15+ provisional notifications appear in Notification Summary
│ │ └─ User may not see them → Request full authorization
│ └─ Was relying on provisional? → Prompt for explicit permission
│
└─ Communication notifications require INSendMessageIntent?
├─ iOS 15+ communication notifications need SiriKit intent
│ └─ Missing? → Donate INSendMessageIntent before showing notification
└─ Intent donated but still filtered?
└─ Check that sender is in user's contacts
プッシュ通知コンソールのワークフロー
Apple の Push Notification Console を使えば、サーバーなしでテストできます。
コンソールを開く
- https://icloud.developer.apple.com/dashboard を開きます
- サイドバーから「Push Notifications」を選択します
- アプリのバンドル ID を選択します
テスト通知を送信する
- デバイストークンを入力します(ステップ 2 の診断で取得)
- 環境(Sandbox/Production)を選択します
- ペイロードを作成するか、テンプレートを使用します
- 送信して配信状況を確認します
配信ログを確認する
- プッシュリクエストのレスポンスヘッダーから
apns-idをコピーします - Push Notification Console で
apns-idを指定して配信状況を検索します - 状況には、受理、配信済み、破棄(理由付き)が表示されます
コンソールでよく確認される内容
| 状況 | 意味 | 対処方法 |
|---|---|---|
| Delivered | APNs からデバイスに配信済み | 問題はデバイス側(認証、集中モード、エクステンション)にあります |
| Dropped: Unregistered | トークンが無効です | デバイスを再登録します |
| Dropped: DeviceTokenNotForTopic | バンドル ID が一致しません | apns-topic ヘッダーを修正します |
| Stored | デバイスがオフラインのため、後で配信されます | 待つか、デバイスの接続状況を確認します |
simctl を使ったシミュレーターでのテスト
シミュレーターはリモート通知に登録できませんが、通知の処理はテストできます。
cat > test-push.apns << 'EOF'
{
"Simulator Target Bundle": "com.your.bundle.id",
"aps": {
"alert": {
"title": "Test",
"body": "Hello from simctl"
},
"sound": "default",
"mutable-content": 1
}
}
EOF
xcrun simctl push booted com.your.bundle.id test-push.apns
シミュレーターの制限
- ✅ 通知の表示と内容
- ✅ Notification Service Extension の処理
- ✅ Notification Content Extension(カスタム UI)
- ✅ アクションの処理とカテゴリ
- ❌ APNs トークンの登録(常に失敗します)
- ❌ サイレントプッシュによるアプリの正確な起動
- ❌ Live Activity のプッシュ更新
ドラッグ&ドロップによる代替方法
.apns ファイルを Simulator ウィンドウに直接ドラッグすると、通知を配信できます。ペイロードに "Simulator Target Bundle" キーが必要です。
FCM の一般的な診断
スウィズリングの競合
症状:Firebase でトークンのコールバックが呼び出されません
原因:メソッドのスウィズリングが無効になっている一方、手動での転送が実装されていません
診断:
// Check Info.plist
// FirebaseAppDelegateProxyEnabled = NO means YOU must forward tokens
修正方法(スウィズリングが無効な場合):
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
トークンの不一致
症状:サーバーに FCM トークンがあるのに、APNs 配信に失敗します
原因:FCM トークンと APNs トークンは異なります。FCM は APNs トークンをラップします。
診断:
// FCM token (send this to YOUR server)
Messaging.messaging().token { token, error in
print("FCM token: \(token ?? "nil")")
}
// APNs token (FCM handles this internally)
// Do NOT send raw APNs token to your server when using FCM
Firebase Console に APNs キーがない
症状:Android では FCM が動作するのに、iOS では通知が届きません
修正方法:
- Firebase Console → Project Settings → Cloud Messaging
- APNs 認証キー(.p8)をアップロードします
- Key ID と Team ID を入力します
- バンドル ID がアプリと一致することを確認します
クイックリファレンス表
| 症状 | 確認項目 | 修正方法 |
|---|---|---|
| 通知がまったく届かない | ステップ 1:エンタイトルメント | Push Notification 機能を有効にして、プロファイルを再生成します |
| トークン登録に失敗する | ステップ 2:コールバック | AppDelegate に両方のデリゲートメソッドを実装します |
| 400 BadDeviceToken | トークン形式 | 再登録します。16 進数のエンコードを確認します(スペースと山括弧がないこと) |
| 403 InvalidProviderToken | JWT/証明書 | JWT を再生成し、キー ID、チーム ID、バンドル ID を確認します |
| 410 Unregistered | デバイスの状態 | アプリがアンインストールされたか、トークンが更新されています。サーバーから削除します |
| 開発環境では動作するが、本番環境では動作しない | ステップ 3:両方に curl を実行 | APNs エンドポイントを切り替えます。トークンは環境ごとに異なります |
| サイレントプッシュが無視される | ペイロードとヘッダー | content-available: 1、push-type: background、priority: 5 |
| リッチメディアが表示されない | エクステンション | mutable-content: 1 を追加し、エクステンションのバンドル ID とタイムアウトを確認します |
| Live Activity が更新されない | トピックの形式 | {bundleID}.push-type.liveactivity トピックを使用します |
| 集中モードによるフィルタリング | 割り込みレベル | 重要な通知には .timeSensitive を使用します |
| FCM が iOS で失敗する | Firebase Console | 正しい Key ID と Team ID を指定して .p8 キーをアップロードします |
| アクションが表示されない | カテゴリ ID | ペイロードのカテゴリ識別子を登録済みのカテゴリに一致させます |
プレッシャーのかかる状況
シナリオ 1:「サーバーチームは問題が iOS 側にあると言っています」
状況:プッシュ通知が機能しなくなりました。バックエンドチームはペイロードに問題はなく、アプリ側に原因があるはずだと言っています。
プレッシャー:クライアント側の診断を省略し、サーバー側の主張を前提にします。通知処理コードの書き換えに取りかかります。
実情:プッシュ通知の失敗の 55% は、コードのバグではなく、権限やトークンの問題です(ステップ 1~2)。サーバーが誤った環境に送信しているか、有効期限切れのトークンを使っている可能性があります。
適切な対応:コードに触れる前に、必須の診断手順を 4 つすべて実行します。curl テスト(ステップ 3)の結果をサーバーチームと共有してください。どちら側に問題があるのかを客観的に証明できます。
押し返すためのテンプレート:「まずクライアント側の一連の処理を確認させてください。5 分以内に curl の結果を共有できるので、問題がどこにあるか双方で正確に把握できます。」
シナリオ 2:「iOS のアップデート後に通知が止まりました。今日中に修正をリリースしてください」
状況:新しい iOS バージョンにアップデートした後、通知が機能しなくなったとユーザーから報告されています。経営陣は今日中の緊急修正を求めています。
プレッシャー:すぐに通知コードのデバッグを始めます。Apple が何かを壊したと決めつけます。
実情:新しい iOS バージョンでは、デフォルトで集中モードが有効になったり、中断レベルのフィルタリングが変更されたりすることがよくあります。プッシュ通知の失敗の 15% は、集中モードや中断による抑制が原因です。こちら側でコードを変更する必要はありません。
適切な対応:ツリー 6(「iOS のアップデート後に通知が止まった」)を確認します。コードを変更する前に、テスト端末の集中モード設定を確認してください。集中モードによるフィルタリングが原因なら、修正すべきなのはペイロードの interruption-level の設定であり、通知処理の書き換えではありません。
押し返すためのテンプレート:「iOS のアップデートでは、集中モードのデフォルト設定が変わることがよくあります。まず中断レベルを確認させてください。原因であれば、コードを書き換えるのではなく、ペイロードを 1 行変更するだけで修正できます。」
シナリオ 3:「先週までサイレントプッシュは機能していました。何も変えていません」
状況:サイレントプッシュによるバックグラウンドのコンテンツ同期が機能しなくなりました。「何も変更していません。」
プレッシャー:バックグラウンド実行コードを詳しく調べます。リグレッションが起きたと決めつけます。
実情:サイレントプッシュには、システムによって制限される使用枠があります(1 時間あたり約 2~3 回)。使用量が増えた場合や、ユーザーがアプリを強制終了した場合、コードの品質にかかわらずサイレントプッシュは機能しなくなります。また、プッシュ通知のエンタイトルメントがない状態でプロビジョニングプロファイルが再生成された可能性もあります。
適切な対応:ツリー 3(「サイレント通知でアプリが起動しない」)に従います。コードをデバッグする前に、使用枠、強制終了の状態、エンタイトルメントを確認してください。
押し返すためのテンプレート:「サイレントプッシュにはシステムによる使用制限があります。使用枠を超えていないこと、テスト端末でアプリが強制終了されていないことを確認させてください。これらは最もよくある 2 つの原因です。」
チェックリスト
プッシュ通知の問題をエスカレーションする前に、次の項目を確認してください。
- Xcode で Push Notification ケイパビリティが有効になっている(ステップ 1)
- プロビジョニングプロファイルに aps-environment が含まれている(ステップ 1)
- トークン登録コールバックが発火し、64 文字の 16 進数トークンが取得される(ステップ 2)
- APNs への curl が HTTP/2 200 を返す(ステップ 3)
- ユーザーが通知を許可しており、ステータスが 2 になっている(ステップ 4)
- APNs の環境がビルドの種類(sandbox/production)と一致している
- テスト端末で集中モードによる通知のフィルタリングが行われていない
- 実機でテストした(トークン登録には Simulator を使用していない)
- FCM の場合:APNs 認証キーが Firebase Console にアップロードされている
- サイレントプッシュの場合:バックグラウンドモードが有効で、優先度が 5 であり、alert キーが含まれていない
リソース
WWDC:2021-10091、2023-10025、2023-10185
ドキュメント:/usernotifications、/usernotifications/testing-notifications-using-the-push-notification-console
スキル:axiom-push-notifications、axiom-push-notifications-ref、axiom-extensions-widgets