Furyu
[フリュー公式]

Tech Blog

フリュー株式会社の技術ブログです

2016年07月19日

morioka

Firebase Dynamic Linksでディープリンク

みなさんこんにちは、コンテンツ・メディア第1事業部の盛岡です。久々の投稿です。

今回のエントリは、関西モバイルアプリ研究会#15 で発表した内容を整理して掲載します。

今回は少し見難い画像もあるかもしれませんが、研究会で利用したものをそのまま利用してライブ感を持ってお届けします!

 

Firebase Dynamic Linksとは

公式ドキュメント

https://firebase.google.com/docs/dynamic-links/

 

概要

Firebase Dynamic Links(以下 FDL)とは、Android / iOSに対応したディープリンクを行うURLを生成するサービスです。

ディープリンクとは主にスマートフォン端末において、ネイティブアプリの特定のコンテンツへ直接リンクするようなものを指します。

さらにFDLの便利な機能として、「リンク時にアプリがインストールされてない場合、アプリインストール後に指定したリンク先へ戻すことが可能」という機能があります。強力な機能であり、是非活用したいですね。

 

スクリーンショット 2016-07-15 21.21.33

FDLの利用は無料であり、生成したURLを短くするいわゆる”短縮URL”としての機能もあります。

 

FDLの想定される用途

ドキュメントにも記載されてますが、用途としてはEメール/SNSなど検索エンジン外からのネイティブアプリへの誘導利用を想定されてます。
Firebaseではその他、検索エンジンからの誘導に「App Indexes」、ユーザー間での招待には「Invites」が用意されてます。

 

スクリーンショット 2016-07-11 13.39.38

 

各プラットフォームのディープリンク基礎知識

アプリケーションにFDLを対応させるために、以下のような技術について知識が必要です。

  • Android : App Links
  • iOS : URLScheme & Universal Links

 

以下で簡単に説明しますが、公式ドキュメントの一読をおすすめします。

 

App Links

公式ドキュメント

Handling App Links 

 

Androidにて、URLスキームに対応するのアプリケーションを起動するための仕組みです。

“AndroidManifest.xml”にURLとマッピングするActivityを指定します。

また、アプリケーションの証明書フィンガープリントを利用することで、起動スキームとアプリケーションを1対1で紐付けることも可能です。

 

Universal Links

公式ドキュメント

Support Universal Links

 

iOS9以降のiOSアプリケーションにて、http/https URLとアプリケーションをマッピングし、該当アプリケーションを起動するための仕組みです。

アプリケーション実装時に、”Associated Domains”を登録することで動作させます。(XCodeにて設定)

 

スクリーンショット 2016-07-15 21.26.01

 

また、マッピング対象のWebサイトルートに、”apple-app-site-association”ファイルを設置することでアプリケーションを起動するための認証を取ります。

(例:https://pictlink.comとアプリを連携させる場合、https://pictlink.com/apple-app-site-association を設置する)

 

iOS9ではアプリケーションがインストールされてない場合にAppStoreへの遷移を促す場合には、Universal Linksを利用するくらいしか手がないためにFDLでも利用しています。

 

Firebase Dynamic Linksコンソールにおけるドメインの払い出し

ここからは、Firebase側での処理を確認して行きます。

FDLを利用し始めるとドメインが払い出されます。

ここでは黒塗りしますが、  abcde.app.goo.gl  のような(abcdeはサンプル)ドメインが各Firebaseプロジェクト毎に出来上がります。

 

スクリーンショット 2016-07-11 11.11.34

 

上記の払い出された “app.goo.gl”は何に利用されるのでしょうか?

これは、FDLのリンクのドメイン部分として記述され、リダイレクタとして利用するイメージです。

 

また、Universal Linksの設定において、登録するドメインにもなります。

(app.goo.glとサービス側のドメインの2つをAssociated Domainsに登録する必要があります)

 

では、Universal Linksで利用するapple-app-site-associationは、”app.goo.gl”ではどうしているのでしょうか?

実際にiOSアプリケーションをFirebaseに登録後、app.goo.glを掘ってみました。

 

スクリーンショット 2016-07-11 11.18.26

app.goo.glにて動的に生成されてますね。

動的に生成されるapple-app-site-associationには、Firebaseプロジェクトに複数のiOSアプリケーションがあっても、全て含めてくれます。

 

アプリケーションへの組み込みについての補足

仕組みの解説は一旦終わり、実際の組み込みについてです。

Firebase自体の利用方法から、アプリケーションの登録、自社アプリへの組み込みまで公式ドキュメントの実装どおりに行えば問題無いと思います。

ただし、何点か補足があるので説明します。

 

補足1:Firebaseに登録したアプリケーションの項目設定

Firebaseに登録しているネイティブアプリケーションの設定項目を埋めるという作業がありますので忘れずにやっておきましょう。

以下の項目が、オプショナル扱いのものです。

アプリ種別 設定項目
Android 証明書フィンガープリント(SHA-1)
iOS App Store ID
iOS  チームID

 

App LinksやUniversal Linksにちゃんと対応するために必要です。

 

補足2:Universal Linksのデバッグ

iOS9対応のためにネイティブアプリケーション側でUniversal Linksの設定も必須となりますが、Universal Linksの設定はデバッグが難しいため注意が必要です。

そのため、私は以下のようなツールを活用していました。

 

App Search API Validation Tool – Apple Developer

34 iOS 9 Apps That Support Universal Links (updated 11-19) — Jack’s Place

 

あとは、Webサーバのアクセスログを確認などして地道に動作確認を実施していきました。

 

補足3:Androidの実装

Androidにおいて、アプリケーションインストール後のリンクを再取得する処理で注意が必要です。

以下にアプリケーション内で記述するサンプルソースを示します。DeepLinkを取得した後、処理をresultCallBack内に記載(下記9行目)しないとダメであり、ブロック外には制御は戻ってきません。

 

 

動作確認

実際のリンクサンプルと、動作確認を行った結果を示していきます。

 

パラメータ内容 値(サンプル)
FDL配布ドメイン abcde.app.goo.gl
コンテンツURL https://pictlink.com/myPage
Androidパッケージ名 jp.furyu.pictlink.android
iOSバンドルID jp.furyu.pictlink.ios
アプリScheme pictlink
AppStore ID 000000001

 

リンク

https://abcde.app.goo.gl/?link=https://pictlink.com/myPage&apn=jp.furyu.pictlink.android

&ibi=jp.furyu.pictlink.ios&ius=pictlink&isi=00000001

 

利用するパラメータを元に、公式ドキュメントに従ってリンクを組み立てましょう。

このようなリンク一つで、Android / iOSのアプリケーションの起動を制御出来るはずです。

(さらに、コンテンツURLに対応するWebサイトがれば、PCブラウザからはWebサイトへ遷移させることも可能です!)

 

動作確認結果

上記のパラメータを用いて動作確認を行った結果、以下の機能が対象OSにて動作しました。

 

 動作 Android iOS8 iOS9
アプリインストール時:リンククリック後アプリ起動
アプリ未インストール時:リンククリック後、アプリストアへ遷移
アプリインストール後:初回起動時にリンクアドレス再取得

 

まとめ

Firebase Dynamic Linksを利用することで、サービス運営者からネイティブアプリケーションへの誘導がうまく出来るようになります。

これまではリダイレクタを自作したり、複雑なjsを用意したり、”あまり触れたくない”ノウハウの塊のような箇所をFirebase側でソリューションとして提供してもらっているイメージです。

 

利用にあたり、アプリケーションの入り口となるコンテンツやページの設計には注意が必要です。アプリケーションとマッピングするサイトURLを丁寧に設計すれば「サイト→ネイティブアプリ」のシームレスな連携が可能になるでしょう。

 

また、導入方法自体はそれほど困難ではないのですが、FDLの動作とアプリケーションの動作を理解していないと、想定した動きにならないことが多いので時間が取られることもあるかもしれません。

個人的には、ディープリンクと言えばFirebase Dynamic Linksの利用が第一候補になっていくのでは、と考えます。本当に便利なものなので、みなさんも是非ご活用下さい。


2016年07月6日

maeda

AppStore自動更新購読のレシートについて

こんにちは、コンテンツ・メディア第1事業部の前田です。

業務で自動更新購読型のAppStore課金を取り入れたのですが、AppStoreから返却される自動更新購読レシートの中身がよく分からず行き詰まることがありました。今回は自動更新購読レシートを調べた中で分かった仕様や消耗型・非消耗型レシートとの違い、ユーザの課金状態によってレシートの内容はどう変化するかについて書いていきます。

AppStore自動更新購読のざっくりとした流れ

MjPZWUULH3UMZYQP-24407

上図が購入から完了までの流れになります。今回はレシートの内容についてなので詳細には触れません。

この図中にあるAppStoreAPIから返却された検証結果レシートの内容について詳しく見ていきます。

レシート仕様

AppStoreから返却されるレシート例を以下に示します。

レシートパラメータの各値は伏せ字にしておきます。見難いかと思いますがご了承下さい。

※レシートデータの内容はiOSのバージョン毎に異なりますので注意して下さい。

各パラメータ内容

重要なパラメータのみ説明します。

プロパティ 子プロパティ 内容
status レシートが正しければ0、異常であれば対応したエラーコードとなる。なお購読の有効期限が切れても0が返る。
receipt in_app latest_receiptの詳細となる。下記「in_app~消耗型・非消耗型プロダクトとの違い~」で詳しく説明。
latest_receipt_info 今まで購入した自動更新のレシートがすべて入る。下記「latest_receiptについて」で詳しく説明。
product_id なんの商品(たとえば1ヶ月購読と半年購読があったりした場合)を判別できるもの。
transaction_id 購入または更新に対するID。latest_receipt_infoの配列毎に値は異なる。
original_transaction_id product_idを購読購入したということに対するID。購読購入→一度やめる→また1年後に購入とした場合でも値は同じとなる。下記「original_transaction_idの検証で詳しく説明」
purchase_date transaction_idに対応した購読開始日時。
original_purchase_date transaction_idに対応した購読購入した日、または更新した日時。更新というのはApple側が更新をかけた日時であって、購読更新日(この日からまた購読)という日時ではない。
expires_date transaction_idに対応した購読期限。
cancellation_date Appleを通してキャンセルされた場合に入る。設定から自動更新オフした場合とかではない。ここに値が入っている場合は有効期限内であっても購入はキャンセルされているので注意。
latest_receipt 自動更新購読型にのみ存在する。アプリから渡され、レシートデータとしてAppStoreAPIへ渡す。ある購読情報をBase64エンコードしたもの。

in_appについて~消耗型・非消耗型プロダクトとの違い~

自動更新購読のレシート構造は消耗型・非消耗型プロダクト(ゲームなどによくあるアイテム課金等)のレシート構造といくつか違いがあります。非消耗型プロダクトのレシートは、in_appの中に課金したアイテムの情報が入ってきます。ですのでそのとき購入した情報はin_appを見れば分かるのですが、自動更新購読レシートはそうとは限りません。自動更新購読のin_appにはlatest_receiptに紐付く購入情報が入ってきます。latest_receiptが一番最新の購入情報であればin_appには最新の購入情報が入りますが、古いlatest_receiptであればin_appには古い購入情報が入ってきます。

具体的には下図のようになります。下図では自動更新購読の内容を「一ヶ月の定期購読課金」としています。

MjPZWUULH3UMZYQP-F3A95

 

 latest_receipt_infoについて

latest_receipt_infoは一見すると最新のレシートのみが入ってくるようにみえるのですが、ここにはアプリ内で購入した自動更新のレシート情報が全て入ってきます。一度更新をやめてしばらく経ってから再度購読を開始した場合でも、以前の購読レシートは一緒になって返ってきます。また、アプリ内にプロダクトが複数あり(300円コース、1000円コース等)、かつ両方で課金したことがある場合には両方の情報が入ってきます(下図参照)。

MjPZWUULH3UMZYQP-BA574 (1)

original_transaction_idの検証

以下図にある3つの状態でレシートを取得した際、original_transaction_idの内容について検証した結果をまとめます。

ここでは、自動更新購読の内容を「一ヶ月の定期購読課金」としています。

 

①1月1日に購読を開始し、2月、3月も購読を更新している場合

MjPZWUULH3UMZYQP-AB86F

latest_receipt_infoには3ヶ月分の購読情報が入ってくる。また、この3つのoriginal_transaction_idは全て同じものである。

 

②1月1日に購読を開始。1月5日に自動更新を解除したが、1月10日に更新解除をやめ、2月、3月と購読した場合

MjPZWUULH3UMZYQP-6EE2D

latest_receipt_infoには3ヶ月分の購読情報が入ってくる。また、この3つのoriginal_transaction_idは全て同じものである。

 

③1月1日に購読を開始し、1月5日に自動更新を解除。3月1日に購読を開始した場合。

MjPZWUULH3UMZYQP-7E69C

latest_receipt_infoには1月、3月の購読情報が入ってくる。また、この2つのoriginal_transaction_idは全て同じものである。

 

つまり、あるアプリ内で自動購読を開始すると、途中で更新解除→再度課金してもoriginal_transaction_idは全て同じとなります。じゃあどこで月々の購読情報を見分けるの?と言うと、transaction_idで見分けることができます。パラメータ内容にも書きましたが、transaction_idには購読が更新される毎に違う値が入ってくるからです。

感想

初めはレシートの中身がややこしすぎて全く分からない…と焦っていたのですが、実際に取得したSandboxのレシートを見てみることによって仕組みを理解することができました。今後自動更新購読を実装する際に参考になればと思います。

参考

In-App Purchaseプログラミングガイド

レシート検証プログラミングガイド

自動購読課金について【iOS編】- サイバーエージェント 公式エンジニアブログ

商標について

AppStore、In-App Purchaseは、Apple Inc.の商標です。


2016年07月5日

araki

モバイルアプリABテストの手法比較:GTM&GA vs Firebase Remote Config

コンテンツ・メディア第1事業部の荒木です。ピクトリンクというアプリのAndroid版を開発しています。今回は、Google I/O 2016 で新しく生まれ変わったFirebaseを使ったABテストと、従来の方法であるGoogle Tag Manager (GTM)とGoogle Analytics (GA)を連携させて行うABテストの違いを見ることで、新しいFirebaseの強みと弱みを考えてみたいと思います。

ちなみに、この記事はumeda.apk #1でLT発表した内容をもとに書かれております。発表スライドは以下です。また、記事の最後にumeda.apkの様子についても書かせていただきます。

https://speakerdeck.com/takuaraki/b-testing-gtm-and-ga-vs-firebase

ABテストの流れ

GTM&GAでもFirebaseでもABテストの流れは、以下の三つのステップに分けられます。

  1. ABを出し分けるためのWebコンソールでの設定
  2. ABを受け取るためのアプリの実装
  3. テスト結果の解析

今回は、上記の三つのステップについてGTM&GAとFirebase Remote Configを比較したいと思います。

1. Webコンソールでの設定

GTM&GA

GTMのWebコンソールで「Google アナリティクスのウェブテスト」という変数を設定することで、ABの出し分けをすることができます(詳しく知りたい方は、 Google Tag Manager でAndroidアプリのABテスト -ABの出し分け- をご覧ください)。変数の設定画面は以下のようになっています。

GTM設定画面1

まだまだあります。

GTM設定画面2

結構長いですね。具体的には、GAとの連携部分やテストの詳細設定が項目数を増やしています。

Firebase Remote Config

FirebaseでABの出し分けをする際は、Remote Configを利用します。Remote Configとは、特定のキーに対する値をWeb上で自由に設定して、アプリに渡すことができるサービスです。アプリのアップデートをせずにWeb上で値を変えるだけで、ユーザーに見せる文言を変更したり、ゲームの難易度を調整したりできます。また、Remote Configには、ユーザーごとに違う値を渡す機能があります。ABテストではこの機能を利用してABの出し分けを行います。Remote Configの設定画面は以下のようになっています。

5. 条件の値を入力

先ほどと比べると、非常にシンプルな印象を受けるのではないでしょうか。Webコンソールで設定する項目を説明します。

パラメータ

パラメータとは、キーと値のペアのことです。たとえば、キーに”hoge”を指定したら値として”fuga”がもらえるという設定ができます。今回は、キー値”pattern”でデフォルト値”A”がもらえる設定を行います。

条件

条件とはパラメータにつけることができるもので、特定の条件を満たしたときだけ”hoge”キーで値として”piyo”がもらえるという設定ができます。たとえば、キー値”pattern”でデフォルトでは値として”A”を渡すが、半分のユーザーには”B”を渡したい場合、以下のように条件を追加してパラメータに追加し、条件達成時の値を”B”としてやれば、ABの出し分けができます。

2. 条件の追加

2. AB受け取りの実装

各手法の初期化とABの値の受け取りをJavaで実装します。

GTM&GA

初期化の流れは、

  • TagManagerインスタンスの生成
  • コンテナID(GTMのWebコンソールで取得)とデフォルト値(リモートからの値取得失敗時の値)の設定
  • リモートからの値取得完了時のコールバック設定

となっています。また、ABの値の取得にはContainer#getString(String key)が利用されています。

Firebase Remote Config

初期化の流れはGTM&GAとかなり似ています。

  • FirebaseRemoteConfigインスタンスの生成
  • デフォルト値(リモートからの値取得失敗時の値)の設定
  • リモートからの値取得完了時のコールバック設定

違う点は、GTMにおけるコンテナIDの設定に相当する部分がないことです。

また、ABの値の取得はFirebaseRemoteConfig#getString(String key)で行っています。この点もGTM&GAに似ていますが、GTMではリモートからの値取得完了時にContainerHolderのインスタンスを自作のシングルトンクラス(ContainerHolderSingleton)に保存しておく手間があるので、若干Firebaseの方がシンプルになっています。

3. テスト結果の解析

GTM&GA

GTMとGAを連携させた場合は、イベント送信時に自動的にそのイベントのセッションがどのパターンであるか(AであるかBであるか)の情報を付与してくれます。また、コンバージョン率やBのコンバージョンがAを上回る確率も計算して、GAのコンソールに表示してくれます。以下は、GAの「ウェブテスト」から見られる画面の例です。

GAテスト結果表示

Firebase Remote Config

Firebase Remote ConfigはAかBかの値をアプリに渡すだけなので、あるユーザーがAを受け取ったのかBを受け取ったのかの情報はイベント送信時に送る必要があります。Firebase Analyticsで送信する場合は、以下のようにカスタムパラメータを付与してイベント送信する必要があると思われます。

また、コンバージョン率の計算や統計的な解析なども自力で行う必要があります。私なら、Firebase AnalyticsとBigQueryを連携させて解析する方法をとると思います。

比較のまとめ

ここまで、ABテストの流れに沿ってGTM&GAとFirebase Remote Configを比較してきました。比較の結果をまとめると、

  1. Webコンソールの設定:Firebaseの方がシンプルである
  2. AB受け取りの実装:FirebaseはGTM&GAと似ている(Firebaseの方が若干シンプルである)
  3. テスト結果の解析:Firebaseは自前でやる必要がある

となりました。Firebaseの強みは、とにかくシンプルであることだと感じました。逆に、シンプルであるがゆえ、高度なことをするときは自分たちで考える必要がある点は抑えておきたいと考えました。

おまけ umeda.apk #1 について

突然ですが、京都はとても住みやすいところです。自転車でどこにでもいけるし、よいお店がたくさんあるし、観光地なので見るところもたくさんあります。そんな京都で私は働いているのですが、一つ困っていることがあります。それは、Android開発者の集まる勉強会が少ないことです。これは京都に限らず関西全体の話です。関西モバイルアプリ研究会という素晴らしい勉強会が京都を中心に開かれていていますが、こちらはiOSとAndroidの両方を対象にしているので、純粋にAndroidアプリ開発者の集まりとなるとなかなか見つかりません。そんな状況の中、umeda.apkという勉強会が6月17日にサイバーエージェントさんの大阪支社で開催されました。

 

この勉強会は、shibuya.apkという渋谷で開催されているAndroidアプリ開発者の勉強会を関西でもやろうということで開催されたそうです。第一回なので、どのような勉強会になるか分かりませんでしたが、日本有数のAndroidアプリ開発者の方が登壇されると知り、すぐに参加を決めました。#1のメインテーマは Google I/O 2016 の報告で、Building for Billions、Firebase、Android in Car、Awareness API、Project Tango、Google I/O セッションまとめ、設計の話(Bento vs Burrito)などの発表がありました。

 

発表を聞いた印象として、どの発表も非常に分かりやすかったです。参加前には、自分が理解できない高度な発表かもしれないと不安を抱いていましたが、Android開発をやっていて最新情報にも多少興味をもっている人なら十分ついていける内容でした。次回は8月に開催予定らしいので、また参加したいと思います。関西でAndroidアプリ開発をされている方は、是非参加してみてください。