2021年3月以降にレガシーバイナリプロトコルがサポートされない旨がAppleから発表されました。
概要は以下のとおりです。
APNは、2021年3月31日以降、レガシーバイナリプロトコルをサポートしません。このページからHTTP / 2ベースのAPIにできるだけ早く更新することをお勧めします。
自分もその対応に迫られましたので対応方法を記しておきます。
【この記事でわかること/対象者】
✔ iOSプッシュ通知をHTTP2で行う方法
✔ サーバーサイドの方
iOSプッシュ通知の通信をHTTP2に変更しました
今回はサーバーサイドのエンジニアの方のためにiOSのプッシュ通知をHTTP2に変更する方法を紹介していきます。
ちなみに言語はPHPです。
環境ができていないとプッシュ通知を送ることができないので以下の条件を満たすように環境を整えてください。
- openssl 1.0.2e以上
- curl 7.46以上(+nghttp2)
- PHP 5.5.24以上
プッシュ通知の仕組み
まずはじめに簡単にiOSのプッシュ通知の仕組みを話しておきます。
iOSのプッシュ通知はAPNs(Apple Push Notification service)というものを使います。
あなたが直接ユーザーの端末に送るわけではなくて、アプリの情報をコントロールしているAPNsサーバーにプッシュ通知のデータを送り、APNsサーバーがユーザーの端末にプッシュ通知を送るという仕組みです。
あなたのサーバー(アプリサーバー)→APNsサーバー→ユーザー端末
上記の流れを把握しておきましょう。
そしてAPNsサーバーに送るときのデータ形式も決められているので守りましょう。
実際のコード
では実際のコードを紹介します。
まずはヘッダーとデータのコンテンツ部分です。
今回は画像つきプッシュ通知をする際のデータとなっています。
//$apnsTopicはアップバンドルID、$imageUrlは画像のURL(カスタムキー)、$textは文言
$headers = ["apns-topic: $apnsTopic", "apns-expiration: 30"];
$alert = '{"aps":{"alert":"' . $text . '","sound":"default","mutable-content":"1"},"image-url":"' . $imageUrl . '"}';
"image-url"のキーの部分はアプリによって変わりますので、画像プッシュを採用しているアプリの場合はアプリ側のエンジニアに問い合わせてみてください。
もし画像プッシュがないのであればここはまるまる消してOKです。
headerの「"apns-expiration: 30"」はユーザーオフライン時のプッシュの再送処理です。
30は30秒を意味します。
The date at which the notification is no longer valid. This value is a UNIX epoch expressed in seconds (UTC). If the value is nonzero, APNs stores the notification and tries to deliver it at least once, repeating the attempt as needed until the specified date. If the value is
0
, APNs attempts to deliver the notification only once and doesn’t store it.
実際にプッシュ通知を送るコードは以下のとおりです。
開発用のAPNsサーバーと本番用のAPNsサーバーではURLが変わりますので注意が必要です。
「$pemFile」にはプッシュ通知の証明書を指定します。
/**
* curlでプッシュ通知を送る。
* 開発サーバーURL "https://api.sandbox.push.apple.com/3/device/$deviceToken"
*
* @param $deviceTokens
* @param $alert
* @param $headers
* @param $pemFile
*
* @return array 失敗時は不正なトークンの配列。成功時は空の配列を返す
*/
private function __sendPushByCurl($deviceTokens, $alert, $headers, $pemFile){
$detectedTokens = [];
foreach($deviceTokens as $deviceToken){
//本番サーバー
$url = "https://api.push.apple.com/3/device/$deviceToken";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $alert);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSLCERT, $pemFile);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 400){
if($response["reason"] == "BadDeviceToken" || $response["reason"] == "MissingDeviceToken"){
array_push($detectedTokens, $deviceToken);
}
}
if($httpCode == 403){
if($response["reason"] == "ExpiredProviderToken" || $response["reason"] == "InvalidProviderToken"){
array_push($detectedTokens, $deviceToken);
}
}
if($httpCode == 410){
if($response["reason"] == "Unregistered"){
array_push($detectedTokens, $deviceToken);
}
}
}
return $detectedTokens;
}
上記コードではデバイストークンごとにプッシュ通知を行い、失敗した場合は失敗したトークンを配列に入れて返しています。
ちなみにステータスコードやレスポンスの内容に関しては以下の公式ページで公開されています。
検出したいステータスコードは好みにカスタムしてください。
ハマりそうな点
以下の点は注意しておくといいかなと思います。
・ペイロードのカスタムのキー(画像など)
・画像プッシュの場合は「"mutable-content":"1"」が必要なこと
・HTTP2通信を行うには環境は
仕組みを把握すればそんなに難しくはないのでぱぱっとやってしまおう
今回はiOSのプッシュ通知をhttp2で行う方法を紹介しました。
以前はAPNsPHPみたいなライブラリを使っていたのですがそれよりも記述量がすくなくなったのでありがたいです。
レスポンスも詳しく公式がまとめてくれているのでステータスコードによる処理の分岐も明確にできるかなと思います。
プッシュ通知の仕組みを理解すればそんなに難しくはないのでぱぱっとやってしまいましょう。
今回は以上です。