Firebase Dynamic LinksをReact Nativeアプリに組み込むために調査したDeep Links(ディープリンク)の歴史を記事にしました。
はじめに
こんにちは。KitchHikeインターンエンジニアのタクです。
スマートフォンでリンクをタップすると、アプリが起動してアプリ内のコンテンツへ遷移したことはありませんか?
メールやWebサイトのリンクからアプリを起動させて画面遷移させる技術を Deep Linking (ディープリンキング) といい、実現するリンクのことを Deep Links (ディープリンク)といいます。アプリの普及と共にディープリンクは広く使われるようになりましたが、実装には煩雑な手順と設定が残っており、開発者にとって悩みの種になっているかもしれません。
Firebase Dynamic Linksを導入すると、ディープリンクを実現する上でのURL発行や設定、リンクをタップした際の挙動を、FirebaseコンソールのGUIから簡単に実施できます。
この記事では、Firebase Dynamic Linksの導入手順と、React Nativeで開発しているアプリへ組み込む方法を紹介します。
(以降、Deep Linking・Deep Linksは読みやすさのためディープリンクに統一します。)
アプリのディープリンクをめぐる歴史
Dynamic Linksがどんなものかを知るために、まずは関連の深いディープリンクからひもといていきましょう。
ディープリンクはもともと、あるひとつのコンテンツに直接遷移するリンクのことを指していました。それが、スマートフォン・アプリの普及にともない、アプリの特定のコンテンツへ直接遷移するリンクという、アプリに限定した意味合いで用いられることが多くなりました。
Custom URL Scheme
アプリのディープリンクを実現するために最初に採用された手法が、Custom URL Scheme です。アプリ専用に登録した Scheme (例: comgooglemaps://, line://) を、ブラウザなどから開くことでアプリが起動するという仕組みです。
しかし、Custom URL Schemeには課題がありました。特に問題だったのが以下の2つです。
- アプリがインストールされていないと、エラーが表示される。
- 同じSchemeをもつアプリを複数インストールしていると、ハンドリングできない。
そこで、上記のような課題を改善するために新しく開発された2つ目の手法が、iOS だと Universal Links 、 Android だと App Links になります。
Universal Links と App Links
Universal Links、App Links共に、特定のURL(例: https://kitchhike.com ) でWebサイトにアクセスする際に、アプリをインストールしていればアプリ内の特定のコンテンツに遷移させ、インストールされていなければそのままWebサイトを表示、またはアプリストアに遷移させる仕組みです。
ただし、これらの技術にも依然として課題は残っています。iOSとAndroidで要素技術が違うので、開発者は各OSに対応して実装を行わなければなりません。
これまでのディープリンク実装手法とその課題についてまとめると、以下のようになります。
実装手法 | 課題 |
---|---|
Custom URL Scheme | アプリがインストールされていないと、エラーが表示される。同じ Scheme をもつアプリを複数インストールしていると、ハンドリングできない。 |
Universal Links と App Links | iOS と Android では要素技術が違うため、OSごとに違った実装を行わなければならない。 |
そこで登場するのが Firebase Dynamic Links です。
Firebase Dynamic Links の登場
FirebaseはGoogleが運営しているモバイルプラットフォーム(2014年後半にGoogleが買収)で、多くのアプリ用サービスを提供しています。その中の一つがDynamic Linksです。iOSとAndroidのプラットフォーム間の違いを気にせずにディープリンクを実現できます。Universal LinksやApp Linksを実装する際に必要なファイル作成・設定なども、すべてFirebaseが代行してくれます。
さらにiOSとAndroid、PCである特定のリンクを開いた時の動作をFirebaseコンソール上でコントロールすることができます。OSごとに様々な実装を行う必要がなく、全ての設定がGUIで完結します。例えば、端末がアプリをイントールしていなかった際に、Webサイトを表示させるのか、アプリストアに遷移させるのかをOSごと設定することができます。
つまりFirebase Dynamic Linksは、iOSとAndroidの差異を吸収し、実装と挙動の設定が簡潔にできる ディープリンクを提供するサービス です。 (以降、Firebase Dynamic Linksを使って実際に作成するリンクをダイナミックリンクと記述します。)
ダイナミックリンクの作り方
では、実際にダイナミックリンクを作ってみましょう。
1. Firebaseコンソールを開く。
2. 左のサイドバーにあるGrowタブを開く。
3. その中のDynamic Linksをクリックする。
4.「新しいダイナミックリンク」ボタンをクリックする。
5. 短縮URLのリンクを作成する。
- Dynamic Link Domain 以下を好きな文字列を追加する。
6. ディープリンクURLを設定する
- PCでリンクを開いた場合に遷移させたいページのURLを入力する。
7. iOS でリンクを開いた時の動作設定をする。
- ディープリンクをiOSアプリで開くにチェックする
- iOSアプリを選択する
- アプリがインストールされていない場合のユーザーの移動先として、アプリのApp Storeページが選択されていることを確認する。
8. Android でリンクを開いた時の動作設定をする。
- Androidアプリ内でディープリンクを開くにチェックする。
- Androidアプリを選択する
- アプリがインストールされていない場合のユーザーの移動先として、アプリのGoogle Play Storeページが選択されていることを確認する。
9.「ダイナミックリンクを作成」ボタンをクリックする
これで、https://{app_code}.app.goo.gl/HyxS というダイナミックリンクが作成されました。 このリンクをPCで開けば、https://kitchhike.com というWebサイトに遷移し、モバイルで開けば設定した通りの動作となります。具体的には、アプリをインストール済みなら、iOS・Android両方でアプリ内の特定コンテンツを開きます。インストールされていなかったら、App StoreもしくはGoogle Play Storeに遷移します。
遷移をまとめると以下になります。
OS | アプリのインストール状況 | 遷移先 |
---|---|---|
iOS | 未 | App Store |
iOS | 済み | アプリ内の特定コンテンツ |
Android | 未 | Google Play Store |
Android | 済み | アプリ内の特定コンテンツ |
PC(Macなど) | - | 登録したWebサイト |
ダイナミックリンクの挙動
次にダイナミックリンクの挙動について説明します。
Firebaseにプロジェクトを登録すると、ダイナミックリンク用のドメイン( {app_code}.app.goo.gl )で、Webサイトが作成されます。Webサイトにはアプリを立ち上げるための、apple-app-site-associationやassetlinks.jsonなどの情報ファイルが自動的に作成されてます。それらのファイルにアクセスすることでアプリが起動する仕組みになっています。Universal LinksとApp Linksを使用する設定をFirebaseが代行してくれています。
先ほど作成したダイナミックリンク https://{app_code}.app.goo.gl/HyxS を開くと、以下のようなURLにリダイレクトされます。
https://{app_code}.app.goo.gl/?link=https://kitchhike.com&apn=com.example.app&isi=1234567890&ibi=com.example.app
このURLのパラメータによって、ダイナミックリンクの遷移先などを決定しています。ダイナミックリンクは手動で作成することもできるので、実際に作ってみて動作を確認してみました。
iOS の場合
iOSに対応するダイナミックリンクは以下に示すような URL になります。
https://{app_code}.app.goo.gl/?link=https://kitchhike.com&ibi=com.example.app&isi=1234567890
パラメータ | 説明 |
---|---|
link | アプリで開くリンク。PCでリンクを踏んだ場合は、ここで指定した URL 先に遷移する |
ibi | リンクを開くために使う iOS アプリのバンドル ID |
isi | アプリをインストールしていないユーザが App Store に遷移するための App Store ID |
上記のダイナミックリンクを実際に開いてみると、結果は以下のようになりました。
- アプリをインストールしていない場合、App Storeに遷移
- アプリをインストールしている場合、アプリが起動
- PC の場合、https://kitchhike.com に遷移
Android の場合
Android に対応するダイナミックリンクは以下に示すような URL になります。
https://{app_code}.app.goo.gl/?link=https://kitchhike.com&apn=com.example.app
パラメータ | 説明 |
---|---|
link | アプリで開くリンク。PCでリンクを踏んだ場合は、ここで指定した URL 先に遷移する |
apn | リンクを開くために使う Android アプリのパッケージ名 |
上記のダイナミックリンクを実際に開いてみると、結果は以下のようになりました。
- アプリをインストールしていない場合、Google Play Storeに遷移
- アプリをインストールしている場合、アプリが起動
- PC の場合、https://kitchhike.com に遷移
React Nativeアプリへの組み込む方法
KitchHikeでは、React Nativeでアプリを開発しています。ここから、ダイナミックリンクをReact Nativeアプリへ組み込む方法について紹介します。
設定したディープリンクURLを受け取るには、アプリのコード修正が必要です。今回は react-native-firebase
ライブラリを使用した組み込み方法をご紹介します。
両OS共通部分
1. react-native-firebase ライブラリをインストールする
$ npm install --save react-native-firebase
2. react-native link コマンドを実行する
$ react-native link react-native-firebase
iOS
1. GoogleService-Info.plistの追加
Firebaseコンソールにアクセスし、プロジェクト選択します。ページ遷移後、左上にあるSettingsをクリックし、「プロジェクトの設定」を選択します。iOSアプリの各情報が表示されている部分に、GoogleService-Info.plistをダウンロードするボタンがあるので、クリックします。ダウンロードしたファイルをiosディレクトリのルートに追加します。
2. ios/[YOUR APP NAME]/AppDelegate.m にコードを追加
@import Firebase; #import <Firebase.h> #import "RNFirebaseLinks.h"
3. ios/[YOUR APP NAME]/AppDelegate.m ファイルにコードを追加
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
メソッド内に以下のコードを追加
[FIRApp configure];
4. Custom URL Scheme への対応するためのコードを追加
iOS8以前でもダイナミックリンクを有効にするには、Custom URL Schemeを使用する必要があります。アプリで使用しているCustom URL Schemeがある場合は、ios/[YOUR APP NAME]/AppDelegate.m ファイルの [FIRApp Configure]
よりも前で以下のコードを追加する。
[FIROptions defaultOptions].deepLinkURLScheme = CUSTOM_URL_SCHEME;
※注意: 変数 CUSTOM_URL_SCHEME
は事前に定義していてください。
例
static NSString *const CUSTOM_URL_SCHEME = @"kitchhike";
5. pod install を実行する
ios/Podfile に Firebase/Core
・ Firebase/DynamicLinks
を追加し、pod install する。
pod 'Firebase/Core' pod 'Firebase/DynamicLinks'
6. ダイナミックリンクを取得するために、以下のコードを追加する。
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString *, id> *)options { return [RNFirebaseLinks application:application openURL:url options:options]; } - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler { return [RNFirebaseLinks application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; }
7. Associated Domains の設定
Xcode の Capabilities の Associated Domains を on にし、 applinks:{app_code}.app.goo.gl を追加する。
8. URL Types の設定
Xcode の info の URL Types を以下のように追加。
identifier: dynamic link URL Schemes: com.example.app
Android
1. project レベルの build.gradle
ファイルにコードを追加
buildscript { // ... dependencies { // ... classpath 'com.google.gms:google-services:3.1.2' } }
2. android/app/build.gradle
ファイルの最終行にコードを追加
apply plugin: 'com.google.gms.google-services'
3. android/app/build.gradle
にコードを追加
Firebase モジュールを追加するための以下のコードを追加する
dependencies { // This should be here already compile(project(':react-native-firebase')) { transitive = false } // Firebase dependencies compile "com.google.android.gms:play-services-base:11.8.0" compile "com.google.firebase:firebase-core:11.8.0" ...
4. build.gradle
ファイルにコードを追加
Google PlayサービスのMavenリポジトリを更新するため、projectレベルの build.gradle
ファイルに以下のコードを追加する。
allprojects { repositories { mavenLocal() jcenter() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url "$rootDir/../node_modules/react-native/android" } // ------------------------------------------------- // Add this below the existing maven property above // ------------------------------------------------- maven { url 'https://maven.google.com' } } }
5. Firebase Dynamic Links のモジュールを追加するためのコードを追加
dependencies { // ... compile "com.google.firebase:firebase-invites:11.8.0" }
6. RNFirebase Links Package をインストールするためのコードを追加
RNFirebase Links Package をインストールするため、android/app/src/main/java/com/[app name]/MainApplication.java
ファイルに以下のコードを追加する。
// ... import io.invertase.firebase.RNFirebasePackage; import io.invertase.firebase.links.RNFirebaseLinksPackage; // <-- Add this line public class MainApplication extends Application implements ReactApplication { // ... @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new RNFirebasePackage(), new RNFirebaseLinksPackage() // <-- Add this line ); } }; // ... }
7. 新しいインテントの追加
android/app/src/main/AndroidManifest.xml
ファイルに新しいインテントを追加する
<intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <data android:host="your.dynamic.links.domain.example.com" android:scheme="http"/> <data android:host="your.dynamic.links.domain.example.com" android:scheme="https"/> </intent-filter>
react-native-firebase ライブラリのメソッド
以上のコードを追加することで、ライブラリのメソッドを使用することができるようになります。現在は4つのメソッドが提供されていますが、今回使用した2つのメソッドについて説明します。
メソッドを使う際にはライブラリのimportをします。
import firebase from 'react-native-firebase';
onLink メソッド
このメソッドは、アプリが起動している際にダイナミックリンクが開かれた時、そのダイナミックリンクのディープリンクURLを取得するリスナーを追加するメソッドです。
また追加したリスナーを削除したい場合があると思いますが、その際はonLinkメソッドの戻り値の関数をコールしてください。そうすることで、リスナーが削除されます。
コードの例
// subscribe const unsubscribe = firebase.links().onLink((url) => { // ... }); // unsubscribe unsubscribe();
getInitialLink メソッド
このメソッドは、アプリが起動していなかった際にダイナミックリンクが開かれた時、そのダイナミックリンクのディープリンクURLを取得するメソッドです。
コードの例
firebase.links() .getInitialLink() .then((url) => { if (url) { // app opened from a url } else { // app NOT opened from a url } });
ダイナミックリンクのデバッグ
Firebaseは、作成したダイナミックリンクのデバッグを簡単に行えるよう、ダイナミックリンクの動作をフローチャートでプレビューできる機能を提供しています。
作成したダイナミックリンクに d=1
というパラメータを追加することで、フローチャートを確認することができます。(例: example.page.link/suffix?d=1 ) KitchHikeでテスト用に作成したダイナミックリンクを使って実際に確認してみました。
まとめ
Firebase Dynamic Linksの説明とReact Nativeで開発しているアプリへ組み込む方法を紹介しました。この記事のポイントをまとめると以下の3つになります。
- Firebase Dynamic Linksはディープリンク提供サービスであり、iOS・Android・PC共通で使えるディープリンクURLを作成・管理できる
- Firebaseを使うことでディープリンクの導入が簡潔になり、OS間の差分を吸収してくれる
- リンクを開いた後の挙動などの設定をFirebaseコンソールからGUIで簡単に操作できる
この記事がアプリ開発者の助けになれば幸いです。
We're Hiring!
キッチハイクでは、React Nativeエンジニア・Railsエンジニア・インターンエンジニアを募集中です!