Device Token: 動作の仕組み、APNSトークンの取得と更新

著者: IT Sectr 公開日: 2026-03-21 読了時間: 11 分

Device Tokenは、APNSがプッシュ通知をルーティングするために各iOSデバイスに割り当てる一意の識別子です。トークンはアプリが通知を受信するために登録する際にシステムによって生成され、このデバイスにプッシュを送信するためにサーバーに送信される必要があります。Apple Developer Documentation、2026年によると、Device Tokenはアプリの再インストール、バックアップからのデバイス復元、またはiOSのアップデート時に変更される可能性があるため、サーバーは配信を確実にするために定期的にトークンを更新する必要があります。

重要ポイント

  • 一意性 — Device Tokenは特定のAPNS環境(sandbox/production)において、アプリとデバイスの組み合わせごとに一意です。
  • 非永続性 — アプリの再インストール、バックアップからの復元、またはiOSのアップデート時にトークンが変更される可能性があります。サーバー側に更新メカニズムが必要です。
  • 登録 — アプリはUNUserNotificationCenterを介して通知の許可をリクエストし、その後システムがAppDelegateでDevice Tokenを返します。
  • APNS Sandbox vs Production — 開発には個別の証明書を持つAPNSサンドボックス環境が使用されます。本番トークンは異なり、本番APNSのみが受け入れます。
  • トークンの形式 — 32バイトの16進文字列で、サーバーに送信され、プッシュ通知送信時にapns-topicヘッダーで使用されます。

Device Tokenとは

Device Token(デバイストークン)は、APNS(Apple Push Notification Service)がiOSデバイス上の各アプリに対して生成する、16進文字列形式の一意の識別子です。トークンはサーバーが特定のデバイスにプッシュ通知を送信するための鍵です。有効なDevice Tokenがないと、サーバーはプッシュ通知を配信できません。APNSは400 BadRequestエラーでリクエストを拒否します。

トークンの生成方法

Device Tokenは、インストール後にアプリが初めてAPNSに接続する際にiOSシステムによって作成されます。生成プロセスには、アプリのバンドルIDとデバイスの一意の識別子(UID)への暗号学的なバインドが含まれ、その後APNSはアプリに16進形式(64文字)の32バイトトークンを返します。トークンは永続的ではありません。システムは特定の条件下で新しいトークンを生成する場合があります。

プッシュ通知配信におけるトークンの役割

サーバーがプッシュ通知を送信する際、APNSへのHTTP/2リクエストにDevice Tokenを含めます。APNSはトークンを検証します。トークンが別の環境(本番環境ではなくサンドボックス)のものである場合、期限切れの場合、または失効している場合、Appleサーバーは410 Goneまたは400 BadRequestエラーを返します。トークンの検証が成功した後にのみ、APNSはデバイスへの通知の配信を開始します。

Device Tokenと他の識別子の違い

Device Tokenは、IDFA(広告主識別子)、IDFV(ベンダー識別子)、またはUID(一意のデバイス識別子)と混同しないでください。IDFAとIDFVは広告や分析に使用され、UIDはハードウェアのシリアル番号です。Device Tokenはプッシュ通知専用に存在し、APNSの外部でユーザーやデバイスに関する情報を開示しません。

識別子目的永続性
Device TokenAPNSプッシュ通知のルーティング変更される可能性あり
IDFA広告とトラッキングユーザーがリセット可能
IDFVベンダー識別(分析)同じ開発者のアプリで永続的
Bundle IDアプリの一意の識別子永続的

デバイスがトークンを取得して登録する方法

Device Tokenを取得するプロセスは、ユーザーに許可を求めることからサーバーにトークンを送信することまで、いくつかの必須ステップで構成されています。各ステップは重要です。いずれかをスキップすると、デバイスへのプッシュ通知の送信が不可能になります。

通知許可のリクエスト

最初のステップは、アプリがUNUserNotificationCenter.current().requestAuthorizationを介してユーザーに通知の許可を求めることです。ユーザーは同意する、拒否する、またはオプションのオプション(アラート、バッジ、サウンド)を選択できます。明示的なユーザーの同意がないと、アプリがregisterForRemoteNotificationsを呼び出しても、システムはDevice Tokenを発行しません。許可を取得した後、アプリはUIApplication.shared.registerForRemoteNotifications()を呼び出し、APNSへの登録プロセスを開始します。

APNSからトークンを取得する

登録後、APNSはAppDelegateを介してトークンを返します:application(_:didRegisterForRemoteNotificationsWithDeviceToken:)。成功した呼び出しにはトークンを含むDataオブジェクトが含まれており、サーバーに送信するために16進文字列に変換する必要があります。エラーの場合、システムは問題の説明とともにapplication(_:didFailToRegisterForRemoteNotificationsWithError:)を呼び出します:証明書の設定ミス、ネットワークの利用不可、またはプロジェクトの設定ミス。

サーバーへのトークン送信

トークンを受信した後、アプリはデータベースに保存するためにすぐにサーバーに送信する必要があります。APIリクエストには、トークン、デバイス識別子(マッピング用)、環境(sandbox/production)、オプションで追加データ(OSバージョン、デバイスモデル、言語)が含まれます。サーバーが常に最新のトークンを保持できるように、アプリの起動ごとにトークンを再送信することをお勧めします。

swift
// 許可のリクエストとAPNSへの登録
func registerForPushNotifications() {
    UNUserNotificationCenter.current()
        .requestAuthorization(options: [.alert, .sound, .badge]) {
        [weak self] granted, error in
        guard granted else {
            print("許可が得られませんでした")
            return
        }
        DispatchQueue.main.async {
            UIApplication.shared
                .registerForRemoteNotifications()
        }
    }
}

// APNSからDevice Tokenを取得
func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
    let tokenString = deviceToken
        .map { String(format: "%02.2hhx", $0) }
        .joined()
    print("Device Token: \(tokenString)")

    // サーバーにトークンを送信
    PushTokenService.shared
        .sendTokenToServer(tokenString) { success in
        if success {
            UserDefaults.standard.set(tokenString,
                forKey: "lastDeviceToken")
        }
    }
}

サーバーサイドのトークン管理

プッシュシステムのサーバー側は、Device Tokenをデータベースに保存し、ユーザーと環境に関連付ける必要があります。通知を送信する際、サーバーはAPNSへのリクエストを作成し、URLにトークンと認証用のJWTトークン(または証明書)を含めます。適切なトークン管理は、プッシュ通知の配信率に重大な影響を与えます。

トークンデータベースの構造

サーバー上のトークンテーブルには、少なくとも次のものが含まれている必要があります:Device Token(一意)、ユーザーID、環境(sandbox/production)、最終更新日、ステータス(アクティブ/非アクティブ)。送信時の高速検索のためにトークンに、ユーザーの全デバイスのリストを取得するためにユーザーにインデックスを追加することをお勧めします。多くのアプリでは、1人のユーザーが複数のデバイスを持つことができ、それぞれに独自のトークンがあります。

APNSリクエストの認証

プッシュ通知を送信するために、サーバーは2つの方法でAPNSへのリクエストを認証する必要があります。証明書ベースは、Apple Developer Consoleで生成されたSSL証明書を使用します。トークンベースは、.p8キーを持つJWT(JSON Web Token)を使用し、証明書を更新することなく最大30日間有効です。トークンベースの認証はより現代的で、新しいプロジェクトにはAppleが推奨しています。

HTTP/2 APNSリクエストの作成

APNSへのリクエストには、HTTP/2 POSTメソッド、パス/3/device/{device_token}を含むURL、認証ヘッダー、ペイロードを含むJSONボディが含まれます。apns-topicヘッダーにはアプリのバンドルIDが含まれている必要があります。apns-priorityは配信優先度を示します(5 — 即時、10 — バッテリー節約)。apns-expirationは、APNSが通知の配信を試みるエポックからの秒数を設定します。

js
// APNS HTTP/2経由でNode.jsでプッシュを送信する例
const http2 = require('http2');
const client = http2.connect('https://api.push.apple.com');

const deviceToken = 'abcdef0123456789...';
const payload = JSON.stringify({
    "aps": { "alert": "Hello!", "sound": "default" }
});

const req = client.request({
    ':method': 'POST',
    ':path': `/3/device/${deviceToken}`,
    'apns-topic': 'com.example.app',
    'apns-priority': '10',
    'apns-expiration': '0',
    'authorization': `bearer ${jwtToken}`
});
req.write(payload);
req.end();
req.on('response', (headers) => {
    if (headers[':status'] === '200') {
        console.log('プッシュが正常に送信されました');
    }
});

バッチ送信とスロットリング

多数のデバイスにプッシュ通知を送信する場合は、レート制御付きのバッチ送信を使用します。APNSは接続あたり毎秒1500リクエストを超えないことを推奨しています。制限を超えると、Appleサーバーは429 Too Many Requestsエラーを返します。大規模なキャンペーンでは、複数の接続を使用し、デバイス間で負荷を均等に分散します。

トークンの更新と無効化

Device Tokenは永続的ではなく、いくつかのシナリオで変更される可能性があり、サーバー側に更新メカニズムが必要です。サーバーが古いトークンにプッシュを送信し続けると、APNSは410 Goneエラーを返し、その環境ではトークンが無効であることを示します。

トークンが変更されるタイミング

Appleは、Device Tokenが変更されるいくつかのシナリオを文書化しています:ユーザーがアプリを再インストールする、iCloudバックアップからデバイスを復元する、新しいiOSバージョンをインストールする、またはネットワークやプライバシー設定をリセットする。各ケースで、アプリは次回起動時にAPNSから新しいトークンを受け取ります。サーバーはデータベース内のトークンを更新し、古いものを削除して新しいものを保存する必要があります。

APNSからの410 Goneエラーの処理

サーバーが古いトークンにプッシュを送信すると、APNSはapns-unless-timestampヘッダーとともにHTTP 410を返します。このヘッダーは、トークンが無効になった時間を示します。サーバーはデータベース内のこのトークンを直ちに削除または無効化して、再送信を防ぐ必要があります。410エラーを無視すると、リソースが無駄になり、配信可能性率が低下します。

非アクティブなトークンの定期的なクリーンアップ

トークンデータベースを最新の状態に保つために、定期的なクリーンアップを実行することをお勧めします。クリーンアップスクリプトは、過去N日間のAPNSログを分析し、410エラーを受け取ったすべてのトークンを見つけて、データベースで無効化します。さらに、90日以上ユーザーアクティビティがないトークンは削除できます。これらはデータベースのサイズを増やすだけの無駄なレコードです。

大量送信前のトークン検証

プッシュ通知(ニュースレター、プロモーションキャンペーン)の一斉送信前に、トークンを事前検証することをお勧めします。APNSはバッチトークン検証のための直接APIを提供していないため、低優先度でテストプッシュを送信し、エラーを分析する戦略が使用されます。410エラーを返すトークンは、メインの送信から除外されます。

Device Tokenを取得するコード例

SwiftでDevice Tokenを取得する完全なサイクルを、エラー処理とサーバーへの送信を含めて見てみましょう。コードは以下をカバーしています:許可のリクエスト、APNSへの登録、Dataから16進文字列への変換、エラー処理、失敗時の再試行を含む独自サーバーへのトークン送信。

swift
import UIKit
import UserNotifications

final class PushNotificationManager: NSObject {

    static let shared = PushNotificationManager()
    private let apiClient = APIClient()
    private var currentToken: String?

    func register() {
        UNUserNotificationCenter.current()
            .requestAuthorization(
                options: [.alert, .badge, .sound]) {
            [weak self] granted, error in
            guard granted else {
                Analytics.log(
                    "Push permission denied")
                return
            }
            DispatchQueue.main.async {
                UIApplication.shared
                    .registerForRemoteNotifications()
            }
        }
    }

    func handleDeviceToken(_ tokenData: Data) {
        let token = tokenData
            .map { String(format: "%02.2hhx", $0) }
            .joined()

        guard token != currentToken else { return }
        currentToken = token
        sendTokenToServer(token)
    }

    func handleRegistrationError(_ error: Error) {
        Analytics.log(
            "Push registration failed: \(error)")

        // ネットワークエラー時の遅延後の再試行
        if let urlError = error as? URLError,
            urlError.code == .notConnectedToInternet {
            DispatchQueue.main.asyncAfter(
                deadline: .now() + 10) { [weak self] in
                self?.register()
            }
        }
    }

    private func sendTokenToServer(_ token: String) {
        let body = PushTokenRequest(
            token: token,
            environment: Environment.current == .debug
                ? "sandbox" : "production",
            osVersion: UIDevice.current.systemVersion,
            locale: Locale.current.identifier
        )
        apiClient.sendToken(body) { [weak self] result in
            if case .success = result {
                self?.currentToken = token
            }
        }
    }
}

登録時のエラー処理

APNS登録時のエラーは、さまざまな理由で発生する可能性があります。最も一般的なものには、ネットワークの利用不可、Xcodeでの証明書の設定ミス(例:Push Notifications機能が無効)、シミュレーターの使用(プッシュをサポートしていない)、または不正なプロビジョニングプロファイルが含まれます。本番環境では、エラーをログに記録し、可能であれば次回のアプリ起動時に登録を再試行することが重要です。

シミュレーターでのDevice Tokenのテスト

iOSシミュレーターは実際のDevice Tokenの受信をサポートしていません。シミュレーターでの登録をテストするには、i386アーキテクチャチェックを使用します。デバッグビルドでは、トークンの取得をシミュレートするか、モックオブジェクトを使用したUIテストを使用できます。実際のプッシュ通知のテストは常にXcodeに接続された物理デバイスで行われます。

よくある質問

同じユーザーのDevice Tokenは変更されますか?

はい、Device Tokenはアプリの再インストール、バックアップからのデバイス復元、またはiOSのアップデート時に変更される可能性があります。サーバーはトークンの更新を処理する必要があります。既知のデバイスから新しいトークンを受信したら古いものを置き換え、410エラーが発生したらデータベースからトークンを削除します。

Device Tokenの形式は?

Device Tokenは、小文字(0–9、a–f)の64文字の32バイト16進文字列です。例:「a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2」。トークンはAPNSからDataとして渡され、アプリ側で文字列に変換されます。

サンドボックスとプロダクショントークンの違いは?

サンドボックストークンは開発プロビジョニングプロファイルでビルドされたアプリに発行され、api.sandbox.push.apple.comでのみ機能します。プロダクショントークンはApp StoreとTestFlight用で、api.push.apple.comで機能します。サーバーは環境を区別し、適切なAPNSエンドポイントにプッシュを送信する必要があります。

サーバーがAPNSから410エラーを受け取った場合の対処法は?

410 Goneエラーは、Device Tokenが無効であることを意味します。サーバーはデータベースからこのトークンを直ちに削除し、送信試行を停止する必要があります。応答のapns-unless-timestampヘッダーは、トークンが機能しなくなった時間を示します。

アプリがDevice Tokenを受信したことを確認する方法は?

AppDelegateのデリゲートメソッドapplication(_:didRegisterForRemoteNotificationsWithDeviceToken:)を確認します。メソッドが呼び出されれば、トークンは受信されています。デバッグログまたはOSLogを使用して、Xcodeコンソールにトークンを出力します。物理デバイスで、Network Link Conditionerを使用してトークンがサーバーに送信されていることを確認します。

まとめ

  • Device Token — APNSにおけるデバイスの一意の64文字の16進識別子。プッシュ通知のルーティングに必要です。
  • トークンの取得 — プロセスにはユーザー許可のリクエスト、registerForRemoteNotificationsによるAPNSへの登録、AppDelegateでの処理が含まれます。
  • トークンは永続的ではない — アプリの再インストール、バックアップからの復元、またはiOSのアップデート時に変更される可能性があります。サーバー側に更新メカニズムが必要です。
  • Sandbox vs Production — 異なるAPNS環境は異なるトークンとエンドポイントを使用します。サーバーは送信時に環境を正しく判断する必要があります。
  • サーバー管理 — トークンはユーザー、環境、ステータスに関連付けてデータベースに保存されます。410 Goneエラーはトークンの無効性を示します。
  • APNS認証 — サーバーはリクエスト認証にJWTトークンまたはSSL証明書を使用します。JWTは新しいプロジェクトにAppleが推奨しています。
  • Device Token — プッシュインフラストラクチャの基本的な構成要素であり、正しい取得と保存から各通知の配信が依存します。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください