LoginSignup
0
0

More than 1 year has passed since last update.

ExpoのManaged workflowでFirebase Dynamic Linksを実装する

Posted at

前提

・ストアにアプリがリリースされている(ストアのURLを知っている)
・firebaseに登録している
・Expoを利用している

firebaseの設定

1. ドメイン登録

firebaseコンソール > エンゲージメント > Dynamic Links

image.png

※ <yourapp>.page.linkなどのURLは無料で取得できます

2. ダイナミック リンクの設定

ディープリンクURLはWebからアクセスされた場合なので、適当にAppストアのリンクを設定します

image.png
ただし、URLのパターンを登録しておく必要があります。

3. Apple 用のリンク動作の定義

✅ ディープリンクを Apple アプリで開く
まだアプリを追加していなければ、「Apple アプリを追加」を押し
・バンドル ID
・App Store ID
・チーム ID
を追加します

アプリがインストールされていない場合のユーザーの移動先:
✅ アプリの App Store ページ

4. Android 用のリンク動作の定義

✅ Android アプリ内でディープリンクを開く
・パッケージ名
・デバッグ用の署名証明書
(Auth で Dynamic Links、Google ログイン、電話番号をサポートするために必須です)

Expoの設定

1. app.jsonの編集

以下の内容を追記します

Android向けの設定
"android": {
  "intentFilters": [
    {
      "action": "VIEW",
      "data": [
        {
          "scheme": "https",
          "host": "<登録したドメイン>",
          "pathPrefix": "/"
        },
      ],
      "category": [
        "BROWSABLE",
        "DEFAULT"
      ],
      "autoVerify": true
    }
  ]
}
iOS向けの設定
"ios": {
  "associatedDomains": ["applinks:<登録したドメイン>"]
}

2. Androidのプラグイン登録

Android 12以降で動作しないissueがあるので、ワークアラウンドのプライグインを導入します

プラグインについては、Expoのドキュメントにコードが書かれています

./plugin/withAndroidVerifiedLinksWorkaroundにファイルを追加します
./plugin/withAndroidVerifiedLinksWorkaround
const { createRunOncePlugin, withAndroidManifest } = require('@expo/config-plugins');

/**
 * @typedef {import('@expo/config-plugins').ConfigPlugin} ConfigPlugin
 * @typedef {import('@expo/config-plugins').AndroidManifest} AndroidManifest
 */

/**
 * Remove the custom Expo dev client scheme from intent filters, which are set to `autoVerify=true`.
 * The custom scheme `<data android:scheme="exp+<slug>"/>` seems to block verification for these intent filters.
 * This plugin makes sure there is no scheme in the autoVerify intent filters, that starts with `exp+`.
 *
 * @type {ConfigPlugin}
 */
const withAndroidVerifiedLinksWorkaround = config =>
  withAndroidManifest(config, config => {
    config.modResults = removeExpoSchemaFromVerifiedIntentFilters(config.modResults);
    return config;
  });

/**
 * Iterate over all `autoVerify=true` intent filters, and pull out schemes starting with `exp+`.
 *
 * @param {AndroidManifest} androidManifest
 */
function removeExpoSchemaFromVerifiedIntentFilters(androidManifest) {
  for (const application of androidManifest.manifest.application || []) {
    for (const activity of application.activity || []) {
      if (activityHasSingleTaskLaunchMode(activity)) {
        for (const intentFilter of activity['intent-filter'] || []) {
          if (intentFilterHasAutoVerification(intentFilter) && intentFilter?.data) {
            intentFilter.data = intentFilterRemoveSchemeFromData(intentFilter, scheme =>
              scheme?.startsWith('exp+')
            );
          }
        }
        break;
      }
    }
  }

  return androidManifest;
}

/**
 * Determine if the activity should contain the intent filters to clean.
 *
 */
function activityHasSingleTaskLaunchMode(activity) {
  return activity?.$?.['android:launchMode'] === 'singleTask';
}

/**
 * Determine if the intent filter has `autoVerify=true`.
 */
function intentFilterHasAutoVerification(intentFilter) {
  return intentFilter?.$?.['android:autoVerify'] === 'true';
}

/**
 * Remove schemes from the intent filter that matches the function.
 */
function intentFilterRemoveSchemeFromData(intentFilter, schemeMatcher) {
  return intentFilter?.data?.filter(entry => !schemeMatcher(entry?.$['android:scheme'] || ''));
}

module.exports = createRunOncePlugin(
  withAndroidVerifiedLinksWorkaround,
  'withAndroidVerifiedLinksWorkaround',
  '1.0.0'
);

Expoのコンフィグにこのpluginを追加します

app.json > expo > plugins
{
  "plugins": ["./plugins/withAndroidVerifiedLinksWorkaround"]
}

アプリのコード

expo-linkingをインストール
npx expo install expo-linking

Linking.useURL()の機能を使うことで、ハンドリングできます

サンプルコード
deepLinkController.tsx
import React from 'react';
import * as Linking from 'expo-linking';

export const DeepLinkController = () => {
  const url = Linking.useURL();

  React.useEffect(() => {
    (async () => {
      if (!url) return;
      const params = parseParamsFromUrl(url);
      
      // Do something
      
    })();
  }, [url]);

  return null;
};

const parseParamsFromUrl = (url: string) => {
  const parsedUrl = Linking.parse(url);
  const linkUrl = parsedUrl.queryParams?.link as string;
  if (!linkUrl) return;

  const params = Linking.parse(linkUrl).queryParams;
  return params;
};

以上です。お目汚し失礼いたしました。

0
0
0

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
0
0