Elixir+PhoenixでAPNsを利用したPush通知を送る簡単なAPIをつくってみる

  • 42
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

Advent Calendar童貞を捨てに来ました。

前提

以前"Elixir+PhoenixでGCMのAPIを叩いてPush通知を送る簡単なAPIをつくってみた"という記事で、ElixirでAndroidアプリにPush通知するWebAPIをつくったので、その続きとしてiOSアプリにPush通知するWebAPIをつくってみます。
ですので、環境構築などは前回の記事をご覧いただければと思います。

Apns4exインストール

最初張り切って自前で実装しようとした(無謀)のですが、Apns4exというよさげなライブラリがあったので、そちらを利用させていただきました。

~mix.exsのdepsとapplicationの箇所にApns4exの設定を追加します。

mix.exs
defp deps do
    [{:phoenix, "~> 1.0.3"},
     {:phoenix_ecto, "~> 1.1"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.1"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:cowboy, "~> 1.0"},
     {:httpoison, "~> 0.7.2"},
     {:apns, "== 0.0.10"}]
end
mix.exs
def application do
    [mod: {PushApp, []},
     applications: [:phoenix, :phoenix_html, :cowboy, :logger,
                    :phoenix_ecto, :postgrex, :httpoison, :apns]]
end

そして、mixコマンドでダウンロード!

$ mix deps.get

ルーター設定

GET /push_apns/:messageというエンドポイントを追加します。

router.ex
scope "/api", PushApp do
    pipe_through :api

    get "/push_gcm/:message/", PageController, :push_gcm
    get "/push_apns/:message/", PageController, :push_apns
end

APNs設定

次に証明書やPoolingの設定をします。

config.exs
# Configure APNS
config :apns,
  # Here goes "global" config applied as default to all pools started if not overwritten by pool-specific value
  callback_module:    PushApp.PageController,
  timeout:            30,
  feedback_interval:  1200,
  reconnect_after:    1000,
  support_old_ios:    true,
  # Here are pools configs. Any value from "global" config can be overwritten in any single pool config
  pools: [
    # app1_dev_pool is the pool_name
    app_prod_pool: [
      env: :prod,
      certfile: "/PATH/TO/DIR/xxxx.pem",
      pool_size: 100,
      pool_max_overflow: 50
    ],
  ]

今回はプロダクション環境向けの証明書を作成したので、env: :prodを設定しましたが、サンドボックス用の証明書は、:devを設定してください。
(話逸れますが、将来的には証明書が1つになるようです!)
また、APNsのエラーやフィードバックが発生した時用ののコールバック関数の定義場所をcallback_module: PushApp.PageControllerと設定しました。

他の設定はデフォルトのままにしています。(Pooling周りは今勉強中)

メイン処理

~web/controllers/page_controller.exにpush_apnsメソッドを以下のように追加します。

page_controller.ex
def push_apns(conn, %{"message" => alert}) do

    token = "hogehoge"

    message = APNS.Message.new
    message = message
    |> Map.put(:token, token)
    |> Map.put(:alert, alert)
    |> Map.put(:badge, 1)

    APNS.push :app_prod_pool, message

    json conn, %{status: "done"}

end

コールバック関数

先程設定ファイルで定義したコールバック用の関数を追加します。

page_controller.ex
def error(%APNS.Error{error: error, message_id: message_id}) do
    # エラー発生時の処理を書く
    Logger.error "[APNS] Error \"#{error}\" for message #{inspect message_id}"
end

def feedback(%APNS.Feedback{token: token}) do
    # フィードバック発生時の処理を書く
    Logger.info "[APNS] Feedback received for token #{token}"
end

ご存知の方も多いと思いますが、APNsはエラーハンドリングが結構厄介で、Apns4exは非同期でエラーやフィードバック時の処理できパフォーマンス的にとても優れているのですが、僕の頭では非同期で素敵なエラーハンドリングが書けず、悪戦苦闘しつつ、最終的には来年Apple様が用意してくれると言われているHTTP2ベースのAPNs APIを待つことになりました←

と言いつつたまにゴニョゴニョ頑張っているので、よい書き方があれば教えてくださいm(__)m

API実行

開発が完了したら、サーバーを起動してAPIを実行!

$ curl http://localhost:4000/api/push_apns/finalfantasy
{"status":"done"}

上手く行けば、iPhoneアプリに"finalfantasy"というPushメッセージが通知されます。
エラーの場合(デバイストークンが不正など)は、ログが出力されます。

まとめ

Elixir版gaurunつくりたい。
APNS4exのソースはElixir/Erlangを理解するのにいい勉強になりそう。
早くHTTP2ベースのAPNs APIリリースしてください!
【追記】
新しいAPIでましたキタ━━━━(゚∀゚)━━━━!!
APNs Provider API

参考サイト

iOSのPUSH通知(APNS)の特徴・ノウハウまとめ(iOS 9まで対応):
http://qiita.com/mono0926/items/df03c61adc56934e2e7a
Apple Push Notification Serviceのエラー処理について:
http://hagino3000.blogspot.jp/2014/05/apple-push-notification-service.html

この投稿は Elixir Advent Calendar 201511日目の記事です。