APNsは正常に動作しているのか?

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の管理は厳密ですね。

USBTypeC変換ハブを買う。そして、買いなおす。

2022年10月13日

開発環境
OS:macOS Monterey
SDK:Xcode14.1

概要

Mac Bookでの初めてのアプリ開発。

まずは最初にすること、それは、TypeC変換です。

USBTypeC変換ハブは必須

iPhoneアプリの開発依頼を受け、Mac Bookが家に届きました。

初めてのMac Book。

まず戸惑ったのが、

USBポートがTypeCしかない。

マウスにしろ、デバッグ用ケーブルにしろ、手持ちのデバイスは全てUSB TypeA。

Mac Bookにはそのまま使えないのか。。。

早速、近くの電気屋に行って、USB変換ハブを買いました。

まず手に取ったのがこちら。

Digio2 STIX(UH-C2482)シリーズ

購入価格(税込み)1233円

デザインはシンプルでスタイリッシュ、そのうえ、安い!

いい買い物したね、と思いながら、早速、使ったみたところ。。。

カッチカチ。

USBの挿し口がかなりきつく、差し込みにしろ、抜くにしろ、とてつもなく固い。

1度差してそのままずっと使うなら良いのですが、そうはいかない。

買いなおしです。。。

そして、次に買ったのがこちら。

ELECOM U3HC-A429Bシリーズ

購入価格(税込み)2545円

ケーブルの長さが微妙ですが、さすがELECOM。

USBの抜き差しは問題なし。

経験上、耐久性はあれですが、使いやすさは間違いないですね。

これでやっとアプリ開発が始められます。