2022年10月17日
開発環境
OS:macOS Monterey
SDK:Xcode14.1
概要
プッシュ通知が実装されたandroidアプリとiosアプリ。
プッシュ通知の動作確認のため、androidとiphoneのデバイスでデバッグをするものの、
Firebase経由で発行したプッシュ通知がandroidには届くが、iosには届かない。
なぜiosに届かないのか調査します。
APNs
APNs(Apple Push Notification service)とは、アップルプッシュ通知サービスのこと。
プッシュ通知におけるandroidとiphoneの大きな違いはAPNsの存在。
androidの場合、Firebase → androidデバイスとプッシュ通知が配信されるのに対し、
iosの場合、Firebase → APNs → iPhoneデバイスとプッシュ通知が配信されます。
iPhoneにプッシュ通知が届かない。
しかし、Firebaseではプッシュ通知が配信されている。(androidは受信できているので)
それが確かであるなら、iphoneに届かない理由は、「APNsが正常に動作していない」からに絞られます。
そこでAPNsが正常に動作しているかどうかを確認します。
確認手段は、cURLコマンド。
curlコマンドでAPNsに直接、プッシュ通知依頼をかけ、iPhoneにプッシュ通知を配信できているかを確認します。
curlコマンド
まずはcurlコマンドを実行するためのバッチファイルを作成します。
#!/bin/bash
set -x
AUTH_KEY_FILE_PATH="xxxxxxxx.p8"
AUTH_KEY_ID="xxxxxxxx"
TEAM_ID="xxxxxxxxx"
APP_BUNDLE_INDENTIFER="com.sample.test"
DEVICE_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
API_ENDPOINT="https://api.development.push.apple.com/3/device/"
base64() {
openssl base64 -e -A | tr -- '+/' '-_' | tr -d =
}
sign() {
printf "$1"| openssl dgst -binary -sha256 -sign "${AUTH_KEY_FILE_PATH}" | base64
}
TIME=$(date +%s)
HEADER=$(printf '{ "alg": "ES256", "kid": "%s" }' "${AUTH_KEY_ID}" | base64)
CLAIMS=$(printf '{ "iss": "%s", "iat": %d }' "${TEAM_ID}" "${TIME}" | base64)
JWT="${HEADER}.${CLAIMS}.$(sign ${HEADER}.${CLAIMS})"
curl -v \
-d '{"aps":{"alert":{"title":"Test","body":"Hello from request with P8 certificates"}}}' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${JWT}" \
-H "apns-topic: ${APP_BUNDLE_INDENTIFER}" \
--http2 \
${API_ENDPOINT}${DEVICE_TOKEN}
上記内容を定義したcommandファイルを作成し、認証キー(p8ファイル)と同階層に配置します。
ちなみにバッチファイル内の可変項目は以下の5つ。
1)AUTH_KEY_FILE_PATH → Apple Developerで取得した認証キー(p8ファイル)名
2)AUTH_KEY_ID → Apple Developerで定義されたキーID
3)TEAM_ID → Apple Developerで定義されたチームID
4)APP_BUNDLE_INDENTIFER → アプリに定義したバンドルID
5)DEVICE_TOKEN → アプリから取得したAPNsデバイストークン
APNsデバイストークンはAPNsとの通信で取得するため、アプリでログ出力して取得します。
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
let token = deviceToken.map { String(format: "02.2hhx", $0)}.joined()
printf("apnsToken:%s\n",token)
}
いざ、実行
バッチファイルの準備が整ったら、実行します。
bash apns.command
そして、実行した結果が、
HTTP/2 400 BadDeviceToken
異常です。
デバイストークンが無効とのこと。
やはりAPNsが正常に動作していなかったようです。
Apple Developer再定義
Apple Developerの定義を見直します。
ここでApple Developerに詳しい方にヘルプ。
定義を確認したもらった結果、2点の間違いが発覚。
①デバッグ用デバイスの定義漏れ
②開発用定義になっていない。(Distoribution → Development)
改めて定義をしなおし、Provisioning Profileを読み直してリビルドします。
そして、再度、apns.commandを実行してみると、
結果は、HTTP/2 200となり、プッシュ通知が届きました。
実際にiPhoneによるデバッグでもプッシュ通知が届くことを確認。
なかなかにAppleの管理は厳密ですね。