2013年4月19日金曜日

25.Google App Engine/Java 1.7.7でiPhoneにPush通知してみた

このエントリーをはてなブックマークに追加


◯Google App Engineは1.7.7から外向きのSocke通信をサポート


Google App Engine 1.7.7から外向きのSocket通信がサポートされました。
それに伴い、
AppEngineから直接APNSサーバーと通信してiOSにPush通知を送信することもできるようになりました。


これまではAppEngineのアプリからAPNSサーバーにPush通知を送信するためには、
別の環境(EC2やElastic Beanstalkなど)に踏み台にするWebアプリを配置して、
以下のような構成にする必要がありました。

AppEngine → [httpsで通信] → 踏み台のWebアプリ →[Socket通信]→ APNSサーバー

これはAppEngineから外部サーバーに対する接続が制限されていたためで、
AppEngineから外部のサーバーに対して許可されているhttpやhttpsで通信して、
APNSサーバーとの通信はその先のWebアプリ(踏み台)から行なっていたわけです。


それが今回のアップデートにより、

AppEngine →[Socket通信]→ APNSサーバー

と、AppEngineから直接APNSサーバーと通信してPush通知を送信できるようになりました。



◯サンプルコード

public class SendPushController extends Controller {
    /**
     * Logger
     */
    private static Logger log = Logger.getLogger(SendPushController.class
        .getName());

    @Override
    public Navigation run() throws Exception {

        // 記録しておいたDeviceTokenを取得する
        String deviceToken = "**************************************************";

        // Appleのサーバーと通信するための証明書ファイルのPathを取得する
        URL url = this.getClass().getResource("/test-dev.p12");
        String certFilePath = url.getFile();
        // 証明書のパスワードを取得する
        String certPassword = "********";

        ApnsServiceBuilder serviceBuilder =
            APNS.newService().withCert(certFilePath, certPassword)
            // 注:↓を指定しないと内部でThreadを生成しようとしてコケる
                .withNoErrorDetection();

        // 接続先としてSandbox(開発用環境)を指定する場合
        serviceBuilder.withSandboxDestination();
        // 接続先として本番用環境を指定する場合
        // serviceBuilder.withProductionDestination();

        ApnsService apnsService = null;
        try {
            apnsService = serviceBuilder.build();
            PayloadBuilder payloadBuilder = APNS.newPayload();

            // alert文字列
            payloadBuilder
                .alertBody("Google App Engine/Java 1.7.7でiPhoneにPush通知してみる!");
            // 音の指定
            // payloadBuilder.sound("hoge.wav");
            // バッジの指定(アイコン右上の赤丸内の数字)
            // payloadBuilder.badge(4);

            log.info("start to send push.");

            // Push通知の送信(複数のデバイストークンをまとめて送信も可能)
            apnsService.push(deviceToken, payloadBuilder.build());

            response.getWriter().write("success to send push.");

        } catch (Exception e) {
            response.getWriter().write("failed to send push.");
            log.log(Level.SEVERE, "failed to send push.", e);

        } finally {
            // Connectionを解放
            if (apnsService != null) {
                apnsService.stop();
            }
        }
        return null;
    }
}


APNSサーバーに対してPush通知を送信するためのJava用ライブラリとして「java-apns」を使っています。

iPhoneアプリからサーバーにデバイストークンを登録する機能は別途必要ですが、
送信部分はこれだけです。

App Engine側のアプリと「踏み台のWebアプリ」とのやりとりの記述が無くなり、
「踏み台のWebアプリ」のサーバーを管理する必要もなくなるので、随分楽になるでしょう。

ローカルの開発環境からも特に問題なくPush通知を送信することができました。




◯Production環境では課金を有効にする必要がある


The Socket API will be enabled for this application once billing has been enabled in the admin console.

Production環境では課金を有効にしていない場合に上記のエラーが発生します。


Ver.1.7.7から「最低でも週$2.10課金される」という制度が廃止されたので、このタイミングなら課金設定が必須とされてもそんなに痛くはないかな?
もしかしてタイミング合わせたのでしょうか。




◯送信結果

左の画像が「アラート」の送信結果、
右の画像が「バッジ」の送信結果です。
バッジは数字の「4」をサーバーから送ったのが対象のアプリ(FortuneAstro)のアイコンの右上に表示されています。




* テストに使ったiPhoneアプリの作成とPush通知の受信確認はもーりさんを通じてあゆたのSさんにお願いしました。
お二人ともありがとうございましたヽ(´▽`)ノ



◯参考リンク

iPhoneアプリにPush通知機能を実装する方法のまとめ - もとまか日記
iPhoneプッシュ通知まとめ - webネタ
notnoop/java-apns · GitHub

◯Pythonで試した方のブログ

Google App EngineからiOSアプリへPush通知が送れるようになりました - laiso





このエントリーをはてなブックマークに追加