Rails4でPassbookを実装してみた!

こんにちは!
13新卒エンジニアの古川です。今回で二回目の記事です!

最近、クーポンやイベントチケットを一元管理できる、iOSのPassbookという機能が注目されてきました。さらに、Railsの4.0が正式リリースされたようです。
ということで、Rails4.0でPassbookの実装をしてみたので紹介します!

実装環境

フレームワークRails 4.0
プログラミング言語Ruby 2.0.0-p195
DBMSMySQL 5.1.69

使用するライブラリ

Passbookを実装するにあたって、使用するライブラリは以下の2つです!

xl-passbook-ruby
RailsでPassbookの環境を実装するのに便利なライブラリです。ただし、プッシュ通知は別途実装する必要があります。

Grocer
Passbookのプッシュ通知に使用します。

これによって以下のことが一通り実装できます。

・Passbookのダウンロード・登録
iPhone上でのPassbook登録・削除時の通知処理
・Passbook変更時のプッシュ通知

実装に必要なもの

実装の前に、まずは以下のものを用意してください。

①Passbook用のユーザの秘密鍵電子証明書(P12ファイル)
 iOS Dev CenterでPassbookが登録されたときにダウンロードできる証明書ファイルからキーチェーンアクセスを用いて変換します。今回ファイル名はpass.test.example.p12とします。
②P12ファイルを生成したときのパスワード
 ①を生成する際に入力するパスワード
③PassbookのID
 iOS Dev Centerで登録したPassbookのIdentifier(今回はpass.test.exampleとします)
④Passbookの部署ID
 キーチェーンアクセスでインストールされたPassbook証明書の詳細で確認できます。
⑤wwdr.pem
 つぎのページで証明書ファイルをダウンロードしたあと、キーチェーンアクセスを用いて変換し、取得します。
   http://developer.apple.com/certificationauthority/AppleWWDRCA.cer

Railsプロジェクトの作成

まずRailsプロジェクトを作成し、下準備します。

(1) まずはこのコマンドで、プロジェクトを作成します。

rails new passbook_example -d mysql

(2) config/database.ymlを設定します。

development:
  adapter: mysql2
  encoding: utf8
  database: passbook_example_development
  pool: 5
  username: MySQLのユーザネーム
  password: MySQLのパスワード
  socket: /var/lib/mysql/mysql.sock

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: mysql2
  encoding: utf8
  database: passbook_example_test
  pool: 5
  username: MySQLのユーザネーム
  password: MySQLのパスワード
  socket: /var/lib/mysql/mysql.sock

production:
  adapter: mysql2
  encoding: utf8
  database: passbook_example_production
  pool: 5
  username: MySQLのユーザネーム
  password: MySQLのパスワード
  socket: /var/lib/mysql/mysql.sock

(3) Gemfileに必要なGemを追加します。(この部分はバージョン依存が強く、たびたび嵌りました)

# Rails4を動作させるためには、以下の3つのGemが必要でした。
# therubyracer・rb-readlineはバージョン指定しないとエラーがでてしまいます。
gem 'execjs'
gem 'therubyracer' , '=0.10.0'
gem 'rb-readline', '= 0.5.0', require: 'readline'

# デフォルトのxl-passbook-rubyは、Rails4のルーティングに対応していないので、以下を使用します。
gem 'passbook-ruby', git: 'https://github.com/Sjors/xl-passbook-ruby.git', branch: 'rails4'

# 現在1.0.0に更新されており、passbook-rubyが動作しなかったため0.9.9を指定しています。
gem 'rubyzip' , '=0.9.9'

# プッシュ通知に使用します
gem 'grocer'

(4)Gemfileの更新を行います。

cd passbook_example
bundle install

これで下準備は完了しました。

Passbookの実装

以下のフォルダを作成します。

mkdir data/certificates -p

上記のフォルダに、実装時に必要なもので記述した①pass.test.example.p12と⑤wwdr.pemを入れます。

あとは次のコマンドを実行するだけです。

rails g passbook:config

# ticketは任意のモデル名
# identifierは③のPassbookのID
# team_idは④Passbookの部署ID
# passbook_certification_file はpass.test.example.p12へのパス
# 今回は「data/certificates/pass.test.example.p12」と入力します。
# cert_passwordは②P12ファイルを生成したときのパスワード
rails g passbook:pkpass ticket [identifier] [team_id] [passbook_certification_file] [cert_password]

エラーがなく無事に作成されましたら、以下のコマンドでデータベースを構築します。

rake db:create
rake db:migrate

つぎに新たに作成されたapp/models/ticket.rbを次のように変更します。この変更をしなければPassbookの登録ができませんのでご注意ください。

def update_json pass_json
  pass_json['authenticationToken'] = authentication_token
  pass_json['serialNumber'] = serial_number
  #don't forget to change the URL to whatever address your server is at
  pass_json['webServiceURL'] = "ここにグローバルIPアドレスを入力します。プライベートIPアドレスは使用できません。"
  #add more customization to your passbook's JSON right here
end

この時点でプッシュ通知以外は実装されました<(`・ω・´)

プッシュ通知の実装

今回はすぐに試したいということで、以前編集長が紹介していましたGrocerを用いて実装しました。

まずはコントローラを作成します。

rails g controller passbook_user push_notification

①pass.test.example.p12からpass.test.example.pemを作成します。

cd data/certificates
openssl pkcs12 -in pass.test.example.p12 -clcerts -nokeys -out pass.test.example.pem

作成時にパスワードが要求されますので、②P12ファイルを生成したときのパスワードを入力します。

/app/controllers/passbook_user.rbに対して以下の実装を行います。

def push_notification
   require 'grocer'
 
   pusher = Grocer.pusher(
     certificate: Rails.root.to_s + "/data/certifications/pass.test.example.pem",
     passphrase:  '②P12ファイルを生成したときのパスワード',
     gateway:     "gateway.push.apple.com",
     port:        2195,
     retries:     3
   )
   tokens =  Passbook::Registration.all
   
   tokens.each do |token|
     notification = Grocer::PassbookNotification.new(
       device_token: token.push_token,
     )
     
     #update ticket
     Ticket.where({serial_number: token.serial_number}).first().touch

     pusher.push(notification)
   end
 end

念のため、/app/views/user_passbook/push_notification.html.erbを以下のように変更します。

<h1>プッシュ通知完了</h1>

これでPassbookに必要な環境全て整いました!お疲れ様でした!!

動作確認

まず、/data/templates/pass.test.example/pass.jsonを以下のように修正します。

 ・・・
  "barcode" : {
    "message" : "34534636",
    "format" : "PKBarcodeFormatPDF417",
    "messageEncoding" : "iso-8859-1"
  },
  "organizationName" : "1234ABCD",
  "description" : "テストPassbookです。",
  "logoText" : "AdwaysExample",
  "foregroundColor" : "rgb(0, 0, 0)",
  "backgroundColor" : "rgb(255,255,255)",
  "eventTicket" : {
    "headerFields" : [

    ],
    "primaryFields" : [
      {
        "key" : "title",
        "label" : "",
        "value" : "Hoge Foobar"
      }
    ],
    "secondaryFields" : [
      {
        "label" : "更新日",
        "key" : "update_time",
        "value" : "2013/08/19",
        "changeMessage" : " 更新日が変更されました %@"
      }
    ],
    "auxiliaryFields" : [],
    "backFields" : [
        {
            "key" : "description",
            "label" : "概要説明",
            "value" : " これはサンプルです!"
        }
    ]
  }
}

以下のコマンドでrailsのサーバーを起動します。(このコマンドはスーパーユーザしか実行できませんのでご注意を)

rails s -p 80

通常Passbookとの通信はHTTPSだけに制限されていますが、動作確認のためHTTPでも通信できるようにiPhoneの設定を変更します。

設定方法は次のとおりです。

(1)まずiPhoneMacにつなげて接続し、Xcodeを立ち上げます。

(2)Organizerに切り替え、接続しているiPhoneを選択します。

(3)メイン画面にある「Use for development」ボタンをクリックします。

(4)iPhoneの設定に「デベロッパ」が表示されます。「デベロッパ」を選択すると表示される「Allow HTTP Services」をオンに切り替えます。

ここで、実際にダウンロードを行ってみます。

http://実装したwebサーバのIPアドレス/v1/passes/ticket

表示されました!!

Passbookダウンロード時(表)


つぎに「追加」ボタンを押してみましょう。うまくいけば以下のような感じでアニメーションが表示されます。こうならなければ、設定にミスがあります。部署名やWebServiceの項目に誤りがないか、HTTP通信の許可をとっているかどうか確認してください。(ちなみにこれを解決するのに数時間とられたのは内緒です)


Passbook追加時


つぎにプッシュ通知を行ってみます。

まずは/data/templates/pass.test.example/pass.jsonをいじっておきます。

 ・・・
  "barcode" : {
    "message" : "34534636",
    "format" : "PKBarcodeFormatPDF417",
    "messageEncoding" : "iso-8859-1"
  },
  "organizationName" : "1234ABCD",
  "description" : "テストPassbookです。",
  "logoText" : "AdwaysExample",
  "foregroundColor" : "rgb(0, 0, 0)",
  "backgroundColor" : "rgb(255,255,255)",
  "eventTicket" : {
    "headerFields" : [

    ],
    "primaryFields" : [
      {
        "key" : "title",
        "label" : "",
        "value" : "Hoge Foobar"
      }
    ],
    "secondaryFields" : [
      {
        "label" : "更新日",
        "key" : "update_time",
        "value" : "2013/08/21",
        "changeMessage" : " 更新日が変更されました %@"
      }
    ],
    "auxiliaryFields" : [],
    "backFields" : [
        {
            "key" : "description",
            "label" : "概要説明",
            "value" : " これはサンプルです!"
        }
    ]
  }
}

以下の URL にアクセスして、実際にプッシュ通知を行ってみましょう。

http://実装したwebサーバのIPアドレス/user_passbook/push_notification

うまくいけば、こんな感じに更新されます。


Passbook更新時


これでPassbookの一通りの機能が実装したことを確認できました。

振り返り

passbook-rubyによる実装はそこまで難しくないです。

ただ、
Passbookの証明書云々を用意するのと、Mac環境の用意が面倒でした。。。
(Mac環境用意するのに1ヶ月ほどかかった自分がいます(´・ω・`)

あとはWebServiceグローバルIPで公開するのと、HTTP通信を許可するためにiPhoneデベロッパー設定を変える部分に注意が必要です。(これに気づくのに数時間かかりました。。。

逆にそれらさえ気をつければ、手軽に実装できます。

一度は試してみてはいかかでしょうか?

以上です。今回は実装手順が長いため、長文になってしまいました(´・ω・`)