LoginSignup
42
38

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-12-10

はじめに

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

42
38
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
38