段田です。
最近、PHPからiphone端末にPUSH通知を送る機能の開発に携わりました。PHPでプログラムを実装する場合、フルスクラッチとライブラリを使用するケースがあるのですが、各ケースでのポイントを忘れないよう書きたいと思います。
なおPUSH通知の概要、証明証の作成については省略します。概要などは下記の記事がわかりやすく、参考になりました。
Apple Push Notification サービス(APNs) の実装方法
フルスクラッチのケース
フルスクラッチでやる場合、こちらのはてなの記事が参考になりました。
https://irss.hatenablog.com/entry/20111026/1319632548
しかし、試しに作成すると送信はできるのですが、下記の様な制約があることを知ります。
- 1つのメッセージで256バイトを超えてはいけない
- 1回の通信で全パケットが5000〜7000バイトを超えるとAPNSから切断される
1に関してはApple公式ドキュメントに記載があるのですが、
2に関しては記述がありません。
(色んな人に聞いたりして判明しました。)
実際に複数送信をした場合、一定送信件数を超えるとAPNSから切断されます。あの世まで行ってジョブズに焼き土下座させたい気分なのですが、ここはグッと堪えます。
対応策としては
- 5000〜7000Byte毎にsleepした後に再接続をする(今回は5000Byte)
- APNSからエラーが返却された場合はsleepした後に再接続をする
という処理をいれてやると解決できます。sleepは1秒ぐらいで良いかと思います。
下記では入れていませんが、APNSが落ちている可能性等もありますので、
エラーが指定回数を超えたら、処理を中断するのも良いかと思います。
function connectAPSN($sslclient,$pem_path,$passphrase){
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', $pem_path);
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client($sslclient, $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp){
echo "接続エラーになったので1秒後再接続を試みます。メメタア!" . PHP_EOL;
sleep(1);
$fp = connectAPSN($sslclient,$pem_path,$passphrase);
return $fp;
}else{
echo "APNS接続できたぞおおおWRYYYYYYYYYYYYYYY" . PHP_EOL;
return $fp;
}
}
//送信処理
$passphrase = 'password';
$pem_path = '/xxx/xxx.pem';
$sslclient = 'ssl://gateway.sandbox.push.apple.com:2195';
$fp = connectAPSN($sslclient,$pem_path,$passphrase);
//PUSH内容設定
$body['aps'] = array(
'alert' => "PUSHメッセージ送信します",//20文字以内で
'sound' => 'default',
'badge'=> 1,
);
//PUSH内容をJSON化
$payload = json_encode($body);
$json_size = strlen($payload);//json化したメッセージのサイズ確認
$size = 0;
foreach ($device_Token_array as $deviceToken){
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken["device_token"]) . pack('n', $json_size) . $payload;
$msg_size = strlen($msg);
$result = fwrite($fp, $msg, $msg_size);
if (!$result){
echo '送信できなかったガッデム!' . PHP_EOL;
}else{
echo '送信できたわよー' . PHP_EOL;
}
$size += $msg_size;
if($size >= 5120){
echo '通信容量超えたので再接続します。ジョブズマジ許さねえ。' . PHP_EOL;
fclose($fp);
sleep(1);
$fp = connectAPSN($sslclient,$pem_path,$passphrase);
echo '再接続しました。ジョブズとりあえずファンタ買ってこい。' . PHP_EOL;
$size = 0;
}
}
fclose($fp);
ライブラリのケース
ライブラリはApnsPHPがお勧めです。
apns-php送信に使用するsend()メソッド内でエラー時の再接続処理を実装されているので、フルスクラッチで書いた対応策を別途実装する必要はありません。apns-phpのサイトに記載のサンプルスクリプトで大体、実装できます。
注意点
複数送信する際ですが、何万件、何十万件をPUSH送信する場合、一気にアプリへのアクセスが予想されます。外部サーバーへのデータ連携やWEBVIEWによるサイト表示をしている場合、負荷が高まる可能性がありますので、負荷対策を考えたほうが良いでしょう。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。