はじめに
※本記事では通常のwebなどからのディープリンクについては記載を割愛しますm(_ _)m
前回の記事に続き、今回はAndroidのFacebookアプリからディープリンクについてを記事にしたいと思います。
有料(従量課金)のツールとか使えば楽できるみたいなのですが、今回のミッションはFacebookアプリからだけなのでお金をかけずにとのことでした。
ので自前で実装することになったんですが…かなり苦戦しましたので記事にして残しておきたいと思います。
実現方法
どのように実現するか調べたらまず公式のApp Links on Androidが見つかりました。
早速導入して試したんですが、全く機能せず…色いろ調べても解決方法が見つけられず…
一旦諦めました(><)
が、ベテラン技術者の方に色々調べてもらいサーバ側にプログラムを仕組んだらできるのでは無いか?ということで試していただくことに。
導入したのは
- Chromeのintent
- App Links on Android
の2つを導入しました。
が、おそらくApp Links on Androidだけで動くと思われますのでChromeのintentは概要だけ記載します。
Chromeのintent
App Links on Android以外にもintent起動する方法があって最初はこれを実装していました。
以下が構成イメージです。meta情報を加工してリダイレクトするだけの割とシンプルな構成です。
ただ古い機種(ASUS Zenfone4:Android8)ならうまくいくんですが、比較的新しい(Android10とか)の機種ではなぜかうまくいきませんでした。原因はわからないまま…
なので次項のApp Links on Androidの導入に至りました。
App Links on Android
こちらが本題。以下のようなイメージ構成です。
iOSの時と大差無いですが、違っているのはサーバ側にプログラムを仕組んだことです。
通常のmetaデータだけだとFacebookアプリがうまくintent起動してくれないのでサーバ側でmetaデータを加工してあげることになりました。
Androidの場合は①③④をFacebookアプリがやってくれます。
サーバ側
Facebookアプリからのディープリンク【iOS編】の時と同じようにサーバ側にページを用意し
[https://hogehoge.com]
にアクセスがきたら用意したページに飛ぶようにサーバ側で設定します。
今回はmetaデータの加工が必要なのでphpファイルを準備しました。
そして、そのphpでmetaデータを加工する処理を仕組みます。
※パラメータの解説はApp Linksの技術文書を和訳してみましたが参考になりました。
<?php
// 定数定義
define('ANDROID', 0);
define('IOS', 1);
define('OTHER_OS', 999);
define('FACEBOOK', 0);
define('OTHER_BROWSER', 999);
define('APP_NAME', 'あなたのアプリの名前');
define('ANDROID_STORE', 'https://play.google.com/store/apps/details?id=あなたのアプリID');
define('ANDROID_SCHEME', 'hogehoge-app');
define('ANDROID_CUSTOM_URL_HOST', 'hogehoge-link');
define('ANDROID_PACKAGE', 'あなたのアプリのパッケージ名');
// サーバ変数からホスト、url、ユーザエージェント取得
$httpHost = $_SERVER[HTTP_HOST];
$requestUri = $_SERVER[REQUEST_URI];
$uerAgent = $_SERVER[HTTP_USER_AGENT];
header("Content-type: text/html; charset=utf-8");
$os = findOS($uerAgent);
$browser = findFacebook($uerAgent);
if($os === ANDROID || $browser === FACEBOOK) {
$host = ANDROID_CUSTOM_URL_HOST;
$scheme = ANDROID_SCHEME;
// metaデータに出力するlink
$androidDeeplink = "$scheme://$host$requestUri";
}
function findOS($uerAgent) {
if(preg_match('/Android/ui', $uerAgent)) {
return ANDROID;
} else if(preg_match('/iPhone|iPod|iPad/ui', $uerAgent)) {
return IOS;
}
return OTHER_OS;
}
function findFacebook($uerAgent) {
if(preg_match('/FB_IAB/ui', $uerAgent)) {
return FACEBOOK;
} else if(preg_match('/facebook/ui', $uerAgent)) {
return FACEBOOK;
}
return OTHER_BROWSER;
}
?>
<html>
<head>
<meta property="al:web:should_redirect" content="false" />
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta property="al:android:package" content="<?php echo ANDROID_PACKAGE ?>" />
<!-- ここで加工したlinkを出力。このmetaタグでFacebookアプリが動いてくれる -->
<meta property="al:android:url" content="<?php echo $androidDeeplink; ?>" />
<meta property="al:android:app_name" content="<?php echo APP_NAME ?>" />
<!-- キャッシュは無効にしておく(でも、多分OGP情報のキャッシュには無力と思われる) -->
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="-1" />
<meta http-equiv="expires" content="Tue, 31 May 2011 10:15:00 GMT+3" />
<meta http-equiv="pragma" content="no-cache" />
</head>
<body style="font-size: medium;">
<!-- アプリがインストールされていない場合ストアに遷移させる -->
<?php
if($os === ANDROID || $browser === FACEBOOK) {
?>
<script>
window.onload = function() {
setTimeout(function() {
window.location = "<?php echo ANDROID_STORE; ?>";
}, 3000);
};
</script>
<?php
}
?>
</body>
</html>
※自分のAndroidはPlay Storeで探しましょう。
※Androidの説明なので**iOSの記載は省略**しています。iOSも同じurlを使う場合はFacebookアプリからのディープリンク【iOS編】の処理をphpファイルに移植してください。
アプリ側
まずはintent起動できるようにAndroidManifest.xmlに追記します。
<activity android:name=".DeepLinkActivity"
android:launchMode="singleTop"
android:noHistory="true"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar">
<!-- app linkとfacebookアプリからのアプリを起動は共存できないのでapp linkは使わない。 -->
<!-- deep link for facebook app -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- dataタグのschemeとhostはphpで定義したANDROID_SCHEMEとANDROID_CUSTOM_URL_HOSTに合わせます -->
<data android:scheme="hogehoge-app" android:host="hogehoge-link" />
<!-- リンクさせるパスを追記します -->
<data android:pathPattern="/top" />
<data android:pathPattern="/setting" />
</intent-filter>
</activity>
次にディープリンクを制御するアクティビティを準備します
import android.content.ComponentName
import android.content.Intent
import android.net.Uri
import android.os.Bundle
class DeepLinkActivity {
companion object {
private const val PATH_TOP = "/top"
private const val PATH_SETTINGS = "/setting"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intentFromDeepLink = intent
/**
取れるのはこんな情報
Intent {
act=android.intent.action.VIEW
dat=hogehoge-app://hogehoge-link/top&target_url=https://hogehoge.com/top
}
**/
val newIntent = Intent(Intent.ACTION_MAIN)
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
var originalUrl: String? = null
// facebookアプリからurl情報を受け取り
intentFromDeepLink?.let { facebookIntent ->
val uri = facebookIntent.data
/**
uriはこんな情報
hogehoge-app://hogehoge-link/top&target_url=https%3A%2F%2Fhogehoge.com%2Ftop
**/
val facebookUrl = uri?.getQueryParameter("target_url")
facebookUrl?.let {
originalUrl = it
/**
originalUrlはこんな情報
https://hogehoge.com/top
**/
}
}
// urlを元に起動する画面のintentを設定する
originalUrl?.let {
val uri = Uri.parse(it)
setIntent(uri, newIntent)
}
startActivity(newIntent)
}
private fun setIntent(uri: Uri?, intent: Intent) {
if (uri == null) {
setIntentToTop(intent)
return
}
when (uri.path) {
PATH_TOP -> {
setIntentToTop(intent)
}
PATH_SETTINGS -> {
setIntentToSetting(intent)
}
else -> {
setIntentToTop(intent)
}
}
}
private fun setIntentToTop(intent: Intent) {
val cls = TopActivity::class.java
intent.component = ComponentName(packageName, cls.name)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
private fun setIntentToSetting(intent: Intent) {
val cls = SettingActivity::class.java
intent.component = ComponentName(packageName, cls.name)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
}
これでFacebookアプリからのディープリンクができるようになったと思います。
iOSと同じようにOGP情報のキャッシュがあるので、サーバ側を更新したらOGPキャッシュのクリアは必須だと思っていいです。
終わりに
私一人では解決できなかったですが、ベテラン技術者の方に協力いただいてなんとか機能させることができました。大感謝です。
Facebook公式に書いてある情報だけでは実現できないって…ちょっと不親切かな〜と思いました。
他のアプリの中身はわからないので手探り状態でしたがとってもいい経験になったと思います。
日本語の記事は見当たらなかったので誰かのお役に立てたらなと思います。