APNS(Apple Push Notification Service)は、Appleのエコシステムデバイス(iPhone、iPad、Mac、Apple Watch、Apple TV)にプッシュ通知を配信するためのAppleのインフラサービスです。このサービスは、デバイスとAppleサーバー間の永続的なTLS接続を通じて、信頼性の高いメッセージ配信を保証します。Apple Developer Documentationによると、APNSはアプリケーションサーバーとの双方向通信にHTTP/2プロトコルを使用しています。
重要なポイント
Apple Push Notification Service(APNS)は、アプリケーションサーバーからユーザーデバイスにプッシュ通知をルーティングするApple独自のサービスです。FCMとは異なり、APNSはAndroidや他のプラットフォームをサポートしていません — Appleエコシステムに完全に依存しています。
このサービスは、各Appleデバイスが起動時にAPNSサーバーと確立する永続的なTLS接続を通じて動作します。この接続はバックグラウンドで維持され、最小限の遅延で通知を配信するために使用されます。
APNSは配信インフラ全体(暗号化、認証、優先順位付け、デバイスが利用不可の場合の再送信)を処理します。開発者は、適切にフォーマットされたペイロードと有効なプッシュトークンを提供するだけで済みます。
当初、APNSはポート2195~2196でバイナリプロトコルを介して動作していました。2015年以降、Appleはサービスを最新のHTTP/2プロトコルに移行しました。このプロトコルは多重化、ヘッダー圧縮、サーバープッシュ通知をサポートしています。HTTP/2は2020年6月から必須となりました。
APNSを介したプッシュ通知の配信プロセスは、デバイス登録、プッシュトークンの取得、サーバーによるリクエスト送信、APNSルーティング、デバイスへの配信の5つの段階で構成されます。
デバイスが利用不可(電源オフまたはネットワークなし)の場合、APNSはアプリごとに最新のメッセージを保存し、接続が復元されたときに配信します。最大保存期間は4週間で、その後メッセージは削除されます。
Appleは、プッシュ通知を送信する際にアプリケーションサーバーを認証するための2つの方法をサポートしています。各方法には、有効期間、管理、使いやすさに関して独自の特徴があります。
| パラメータ | トークンベース(p8) | 証明書ベース(.p12) |
|---|---|---|
| 有効期間 | 無期限(キーは期限切れなし) | 証明書の有効期限に制限(通常1年) |
| ローテーション | キーが侵害されない限り不要 | 毎年の交換必須 |
| マルチアプリ | アカウントの全アプリで1つのキー | アプリごとに個別の証明書 |
| 環境 | SandboxとProductionで1つのキー | SandboxとProductionで別々の証明書 |
トークンベース認証は、2019年からAppleが推奨する方法です。Apple Developer Consoleで1つのp8キーを作成し、サーバーにアップロードして、各APNSリクエストに署名します。キーは期限切れにならず、アカウントのすべてのアプリで機能します。
新しいプロジェクトでは、トークンベース認証が明らかに推奨されます:アカウント全体で1つのp8キー、無期限、環境に依存しません。証明書ベース(.p12)はレガシープロジェクトで依然として使用されていますが、毎年の交換とSandboxおよびProduction用の個別の証明書が必要です。CI/CDを計画する際は証明書の有効期限を考慮してください。
APNSは3種類のプッシュ通知をサポートしており、デバイス上の動作とリクエスト属性の要件が異なります。種類の選択は、UXシナリオとメッセージの緊急度によって異なります。
Background通知の場合、content-available: 1キーを指定し、優先度を5(省電力配信)に設定する必要があります。アプリがタイムリーに処理しない場合、システムはバックグラウンド通知の数を制限することがあります。
APNSは2つの優先度値をサポートしています:10(即時配信)と5(省電力)。アラート通知には10を使用します — ユーザーはすぐに受信する必要があります。バックグラウンド通知には5を使用します — システムはバッテリー節約のため配信を遅延させる場合があります。バックグラウンドに誤った優先度を設定すると、APNSが拒否することがあります。
APNSは、通常の通知では最大4 KB、VOIPでは5 KBのJSON形式のペイロードを受け入れます。ペイロードには、表示設定を含む必須のaps辞書とオプションのカスタムフィールドが含まれます。
{
"aps": {
"alert": {
"title": "新しいメッセージ",
"body": "未読のチャットが3件あります"
},
"badge": 3,
"sound": "default",
"category": "message_category",
"thread-id": "chat_room_42"
},
"customData": {
"chatId": "42"
}
}
thread-idキーは、iOS通知センターで通知をグループ化します。categoryキーは、アクションボタンを表示するために通知をUNNotificationCategoryにリンクします。これらのキーがない場合、すべての通知が個別に表示されます。
必須のaps辞書に加えて、APNSペイロードはトップレベルに任意のカスタムフィールドを含めることができます。これらのフィールドは、通知処理時にuserInfo辞書を介してアプリからアクセスできます。カスタムデータは、エンティティID、画面、リンクを渡すのに便利です。最大ペイロードサイズは4 KBであるため、プッシュ経由で大量のデータを転送しないでください。通知を開いた後にAPI経由でロードしてください。
サーバーからプッシュ通知を送信するには、適切な認証ヘッダーを付けてAPNSエンドポイントにPOSTリクエストを実行する必要があります。以下は、トークンベース認証を使用したNode.jsの例です。
const http2 = require("http2")
const fs = require("fs")
const jwt = require("jsonwebtoken")
const token = jwt.sign(
{ iss: "TEAM_ID", iat: Math.floor(Date.now() / 1000) },
fs.readFileSync("AuthKey.p8"),
{ algorithm: "ES256", keyid: "KEY_ID" }
)
const payload = JSON.stringify({
aps: { alert: { title: "こんにちは!", body: "テストプッシュ" } }
})
const client = http2.connect(
"https://api.push.apple.com"
)
const req = client.request({
":method": "POST",
":path": "/3/device/DEVICE_PUSH_TOKEN",
"authorization": "bearer " + token,
"apns-push-type": "alert",
"apns-topic": "com.example.app",
"apns-priority": "10"
})
req.end(payload)
req.on("response", (headers) => {
if (headers[":status"] === 200) {
console.log("プッシュが正常に送信されました")
}
})
送信後、APNSは配信成功時にHTTPステータス200を返し、エラー時には応答本文に説明付きのエラーコードを返します。token-unregistered(410)エラーを処理することが重要です — アプリがデバイスから削除されたため、そのようなトークンはサーバーから削除する必要があります。
APNSは各送信リクエストに対してHTTPステータスコードを返します。配信成功時はステータス200を返します。エラーには異なる処理戦略が必要です。BadDeviceToken(400)またはUnregistered(410)— デバイストークンが古くなっているため、サーバーから削除する必要があります。PayloadTooLarge(413)— 4 KBの制限を超えたため、ペイロードを削減してください。
TooManyRequests(429) — リクエスト制限を超過しました。APNSは1秒あたりの送信数にクォータを設定しています。429を受け取った場合、指数バックオフ(exponential backoff)を実装して再試行してください。HTTP/2接続あたり1秒あたり100リクエストを超えないことをお勧めします。
APNS側のエラー — 500および503(内部サーバーエラー / サービス利用不可)。これらはAppleインフラの一時的な障害です。このような場合は、1〜5秒の遅延で再試行し、3回を超えないようにしてください。完全に動作しているサーバーで永続的な5xxエラーが発生することは稀で、通常はTLS接続の問題に関連しています。
本番環境では、トークン、エラーコード、時刻を含むすべてのAPNSエラーのログ記録を必ず実装してください。これにより、証明書、クォータ、特定のデバイストークンの問題を迅速に特定できます。証明書ベースの認証を使用している場合は、定期的に証明書の有効期限を確認してください。
よくある質問
APNSはHTTP/2 API用にTCP 443(HTTPS)を介して動作します。以前は、バイナリプロトコルにポート2195と2196が使用されていました。2020年6月以降、Appleはポート443でのHTTP/2の排他的使用を要求しています。サーバーがapi.push.apple.comにアクセスできることを確認してください。
Sandboxはプッシュ通知をデバッグするためのAPNSテスト環境です。Productionは実際のユーザー向けの本番環境です。トークンベース認証では、1つのキーが両方の環境で機能します — エンドポイントが異なります:api.sandbox.push.apple.comまたはapi.push.apple.com。
プッシュトークンは以下の場合に変更される可能性があります:バックアップからのアプリ復元、アプリの再インストール、OSのアップデート、ネットワーク設定のリセット。トークンは変更されませんApp Storeを通じた通常のアプリアップデート時。サーバーはBadDeviceToken(400)エラーをトークン削除のシグナルとして処理する必要があります。
通常のalert/background通知では4 KB(4096バイト)。PushKit経由のVOIP通知では5 KB(5120バイト)。サイズを超えるとPayloadTooLarge(413)エラーが返されます。ペイロードは最小限に保ち、追加データはサーバー経由でロードすることをお勧めします。
APNSはインターネット接続のないデバイスに通知を配信できません。デバイスがオフラインの場合、APNSは28日間まで最新のメッセージ(アプリごと、デバイスごと)を保存します。接続が復元されると、メッセージは即座に配信されます。古いメッセージは保持されません。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。