はじめに
Advent Calendar童貞を捨てに来ました。
前提
以前"Elixir+PhoenixでGCMのAPIを叩いてPush通知を送る簡単なAPIをつくってみた"という記事で、ElixirでAndroidアプリにPush通知するWebAPIをつくったので、その続きとしてiOSアプリにPush通知するWebAPIをつくってみます。
ですので、環境構築などは前回の記事をご覧いただければと思います。
Apns4exインストール
最初張り切って自前で実装しようとした(無謀)のですが、Apns4exというよさげなライブラリがあったので、そちらを利用させていただきました。
~mix.exsのdepsとapplicationの箇所にApns4exの設定を追加します。
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
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
というエンドポイントを追加します。
scope "/api", PushApp do
pipe_through :api
get "/push_gcm/:message/", PageController, :push_gcm
get "/push_apns/:message/", PageController, :push_apns
end
APNs設定
次に証明書やPoolingの設定をします。
# 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メソッドを以下のように追加します。
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
コールバック関数
先程設定ファイルで定義したコールバック用の関数を追加します。
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