Adjust Deeplink + react-native-inappbrowser-reborn 深度鏈接的踩坑之路

Adjust Deeplink

Adjust 它的核心功能是 跟蹤和分析瞬沦、歸因分析太伊、深度鏈接、廣告花費(fèi)追蹤蛙埂、防欺詐工具倦畅、實(shí)時(shí)數(shù)據(jù)等等,它是非常強(qiáng)大也是市面上比較熱門營銷工具绣的,本次主要介紹深度鏈接叠赐。Adjust 的 SDK 包里已經(jīng)包含了深度鏈接的功能,所以不需要再額外下載依賴屡江,只需要在 Adjust 的后臺(tái)增加一些設(shè)定和微改原生代碼即可芭概。

React-Native 配置深度鏈接

深度鏈接的配置,需要更改「IOS」和「Android」的原生代碼惩嘉,以及使用 Adjust 提供的「深度鏈接生成器」生成出深度鏈接罢洲。下面會(huì)具體講述更改原生代碼和使用深度鏈接生成器,生出深度鏈接文黎。也可以查看官網(wǎng) React-Native 配置惹苗。

IOS 通用鏈接設(shè)定

IOS 的通用鏈接:

  1. 打開 adjust 登入后臺(tái)地址
  2. 找到你需要設(shè)定的應(yīng)用,然后點(diǎn)擊應(yīng)用下的 灰色三角形(^) --> 「所有設(shè)置」
  3. 完成上面的點(diǎn)擊流程耸峭,右邊會(huì)出現(xiàn)側(cè)邊欄菜單桩蓉,請點(diǎn)擊「平臺(tái)」--> 「應(yīng)用類型請選擇 IOS」--> 「默認(rèn)設(shè)備選擇通用」--> 「點(diǎn)擊通用鏈接(Universal Linking)」
  4. 應(yīng)用前綴(APP PREFIX),需要前往 Apple Developer 賬戶找到
  5. 應(yīng)用方案(APP SCHEME), 這個(gè)可以自定義即可劳闹,但必須是唯一性的
  6. 點(diǎn)擊保存之后院究,就可以得到一個(gè)原始通用鏈接,類似 xxxx.adj.st 這樣的

如果遇到不明白的地方本涕,可以查看官網(wǎng)的 IOS 通用鏈接配置 截圖流程业汰,會(huì)比較詳細(xì)

啟用 Associated Domain(比較重要,能否開啟 app菩颖,就看它了)

  1. 打開 Xcode 打開項(xiàng)目
  2. 點(diǎn)擊左上角的文件夾 icon --> 點(diǎn)擊項(xiàng)目名稱 --> 進(jìn)入到「Signing & Capabilities」--> 點(diǎn)擊下方的 「all」--> 找到「Associated Domain」--> 點(diǎn)擊 「+」然后輸入 applinks:你的通用鏈接样漆,例如 applinks:xxxx.adj.st。(前綴必須是 applinks:)
  3. 輸入好之后位他,按下鍵盤回車鍵(Enter)即可

增加 IOS 原始代碼

路徑是 ios/you_project/AppDelegate.m

增加代碼如下

#import <React/RCTLinkingManager.h>

- (BOOL)application:(UIApplication *)application
   openURL:(NSURL *)url
   options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:application openURL:url options:options];
}

<!-- 這段很重要氛濒,如果不加它的話产场,用戶通過點(diǎn)擊深度鏈接,把a(bǔ)pp從背景呼叫到前景時(shí)舞竿,拿不到深度鏈接到參數(shù) -->
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
 restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}

注意:保存代碼之后京景,請 cd /ios 執(zhí)行 pod install,然后再重新 build 到真機(jī)上測試骗奖,請不要使用模擬器

具體詳細(xì)說明可以查看React-native 的 Linking 文檔

Android 深度鏈接

需要更改的原生代碼如下

路徑:android/app/src/main/AndroidManifest.xml

<activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
    android:launchMode="singleTask" // 請選擇 singleTask 模式開啟app
    android:screenOrientation="portrait"
    android:exported="true"
    android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <!-- 主要是以下這段代碼确徙,如果深度鏈接無法開啟app,請檢查深度鏈接配置的 scheme 是否和下面代碼中的 scheme 一致-->
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="myapp"/>
    </intent-filter>
</activity>

注意:scheme 的內(nèi)容执桌,可以根據(jù)自己的需求設(shè)定鄙皇,但必須是唯一性的。請于上面配置 ios 的通用鏈接中的 「APP SCHEME」保持一致
具體詳細(xì)說明可以查看 深度鏈接 的文檔

Adjust 深度鏈接生成器

  1. 打開adjust 登入后臺(tái)地址
  2. 登入之后點(diǎn)擊左側(cè)菜單選擇「深度鏈接生成器」仰挣,如果你的后臺(tái)沒有出現(xiàn)的話伴逸,可能是權(quán)限不夠,需要增加權(quán)限
  3. PLATFORM 請選擇 【Multiplatform】(多平臺(tái))
  4. AD ENVIRONMENT 請選擇 【Other】
  5. FORMAT 請選擇 【ulink】(如果不選 ulink 的話膘壶,下面選項(xiàng)中就不會(huì)出現(xiàn) RAW UNIVERSAL LINK)
  6. APP 請選擇 你的項(xiàng)目
  7. TRACKER 請選擇 【Dynamic Link】(這些都可以自定義的错蝴,建議選擇相關(guān)的跟蹤途徑。另外提醒一下在設(shè)定鏈接的時(shí)候颓芭,請注意「用戶目的位置」這一項(xiàng)的子項(xiàng)中深度鏈接配置顷锰,"已安裝應(yīng)用的用戶跳轉(zhuǎn)到哪里?",請一定選擇「應(yīng)用內(nèi)界面」亡问,否則用戶打開 app 之后官紫,會(huì)跳轉(zhuǎn)到商店,這個(gè)很關(guān)鍵州藕。如果遇到打開 app 之后會(huì)跳轉(zhuǎn)到商店時(shí)束世,也請檢查這一項(xiàng)設(shè)定)
  8. RAW UNIVERSAL LINK 請?zhí)顚?通用鏈接例如 xxx.adj.st(還可以設(shè)定自定義品牌鏈接,這個(gè)會(huì)在最后詳細(xì)說明)
  9. ANDROID APP SCHEME 請?zhí)顚?你項(xiàng)目中的 scheme床玻,例如 myapp://
  10. IOS UNIVERSAL LINK PATH 和 ANDROID DEEPLINK PATH 請?zhí)顚懸粯拥穆窂絽?shù) 例如 navigate?pageName=Dame
  11. FALLBACK URL(optional) 這一項(xiàng)非必填良狈,目前使用的地方是,在非移動(dòng)端的設(shè)備點(diǎn)擊深度鏈接時(shí)笨枯,跳轉(zhuǎn)到指定的網(wǎng)頁,例如:https://www.testdemo.com/
  12. REDIRECT MACOS URL(optional) 對 ios 和 macos 有效遇西,這一項(xiàng)非必填馅精,目前使用的地方是,在非移動(dòng)端的設(shè)備點(diǎn)擊深度鏈接時(shí)粱檀,跳轉(zhuǎn)到指定的網(wǎng)頁洲敢,例如:https://www.testdemo.com/
  13. 點(diǎn)擊底部的 Generate Deeplink,等待完成之后茄蚯,就會(huì)創(chuàng)建出一個(gè)深度鏈接压彭,出現(xiàn)在右側(cè)睦优,這個(gè)時(shí)候可以復(fù)制它去嘗試 app 的設(shè)定是否有效了

完整的深度鏈接例如: https://testdemo.go.link/navigate?pageName=Dame&adj_t=19c9dyt6&adj_fallback=https%3A%2F%2Fwww.testdemo.com%2F&adj_redirect_macos=https%3A%2F%2Fwww.testdemo.com%2F

當(dāng)把 IOS 和 Android 的需要調(diào)整的地方都調(diào)整時(shí),在 build 到真機(jī)后壮不,點(diǎn)擊深度鏈接不出意外的話汗盘,就可以順利開啟 app 了,但想要獲取參數(shù)询一,還需要進(jìn)一步更改 js 代碼

注意:在填寫 FALLBACK URL(optional) 和 REDIRECT MACOS URL(optional) 請一定要把跳轉(zhuǎn)網(wǎng)站后增加 “/”隐孽,不然 IOS 收不到任何參數(shù),范例格式:https://www.testdemo.com/

JS 代碼調(diào)整

以下代碼功能如下

  1. 接收深度鏈接的參數(shù)進(jìn)行格式化處理
  2. 把處理好的參數(shù)和事件存入 state 中
  3. 處理導(dǎo)頁的函數(shù)監(jiān)聽 state 改變健蕊,并符合導(dǎo)頁的條件后進(jìn)行導(dǎo)頁

代碼僅供參考菱阵,可以根據(jù)自己的業(yè)務(wù)需求修改

import { useState, useEffect } from "react";
import { Linking } from "react-native";
import { useSelector } from "react-redux";
import { NavigationContainerRefWithCurrent } from "@react-navigation/native";
import { RootState, DynamicLinkEventEnum, RedirectUrlType } from "@tcg/xoso_web_core";
import useRedirect from "~/hooks/useRedirect";
import useDynamicLinkStore, { pushTask, shiftTask } from "~/store/useDynamicLinkStore";

/** method: 將url params轉(zhuǎn)為key value物件 */
const urlQueryParser = (url: string): { [key: string]: string } => {
    const regex = /[?&]([^=#]+)=([^&#]*)/g;
    const params: any = {};
    let match;
    while ((match = regex.exec(url))) {
        params[match[1]] = match[2];
    }
    return params;
};

/** method: 動(dòng)態(tài)連結(jié)導(dǎo)頁 */
const navigateByDynamicLink = ({ navigationRef }: { navigationRef: NavigationContainerRefWithCurrent<ReactNavigation.RootParamList> }) => {
    const systemInitialized = useSelector((state: RootState) => state.system.initialized);
    const hasProfile = useSelector((state: RootState) => !!state.auth.userProfile);
    const dynamicLinkTasks = useDynamicLinkStore((state) => state.dynamicLinkTasks);
    const [navigateItem, setNavigateItem] = useState<RedirectUrlType | undefined>(undefined);

    // 當(dāng)navigateItem改變時(shí)觸發(fā)導(dǎo)頁的hook
    useRedirect.redirectByUrlObj({
        navigationRef,
        urlObj: navigateItem,
        onFinish: () => {
            shiftTask();
        },
    });

    useEffect(() => {
        if (!systemInitialized || !dynamicLinkTasks || !navigationRef || !hasProfile) return; // 若尚未開啟完app或無推播資料就不繼續(xù)
        // 當(dāng)推播資料有夾帶導(dǎo)頁資訊時(shí)進(jìn)行處理
        const oauthBindTask = Object.assign({}, dynamicLinkTasks[0]);
        if (oauthBindTask.event === DynamicLinkEventEnum.navigate && oauthBindTask.querys.pageName) {
            // 動(dòng)態(tài)連結(jié)會(huì)將導(dǎo)頁目標(biāo)及參數(shù)全放在querys,因此轉(zhuǎn)換過程需將
            const cloneQuery = Object.assign({}, oauthBindTask.querys);
            delete cloneQuery.pageName;
            const urlObj = {
                page: oauthBindTask.querys.pageName,
                params: cloneQuery,
            };
            setNavigateItem(urlObj);
        }
    }, [navigationRef, systemInitialized, dynamicLinkTasks, hasProfile]);
};

/** 啟動(dòng)監(jiān)聽深度鏈接 */
const startListenerDeepLinking = () => {
    const handleLink = (link: any, isInit: boolean) => {
        try {
            if (!link.url) return;
            const url = link.url;
            // DynamicLinks挾帶的params參數(shù)物件
            const querys = urlQueryParser(url);
            // 定義應(yīng)處理的event範(fàn)圍
            const eventRange = [DynamicLinkEventEnum.navigate];
            if (isInit) {
                eventRange.push(DynamicLinkEventEnum.init_app);
            } else {
                eventRange.push(DynamicLinkEventEnum.foreground);
                eventRange.push(DynamicLinkEventEnum.oauth_bind);
            }
            // 屬於DynamicLinkEventEnum定義範(fàn)圍者才可放入task
            eventRange.forEach((event) => {
                if (url.includes(`${event}`)) {
                    pushTask({ event, querys });
                }
            });
        } catch (error) {
            console.log("handleLink error", error);
        }
    };

    // 獲取初始化深度鏈接
    const handleInitDynamicLinks = async () => {
        const url = await Linking.getInitialURL();
        handleLink({ url }, true);
    };

    useEffect(() => {
        handleInitDynamicLinks();
        // 添加深度鏈接監(jiān)聽器
        const subscription = Linking.addEventListener("url", (event: any) => {
            handleLink(event, false);
        });

        // 清除監(jiān)聽器缩功,避免內(nèi)存泄漏
        return () => {
            subscription.remove();
        };
    }, []);
};

export default {
    startListenerDeepLinking,
    navigateByDynamicLink,
};

自定義品牌域名

Adjust 提供的域名都是不夠人性化的晴及,很多時(shí)候想要使用自己的域名來做深度鏈接,Adjust 也考慮到了這一點(diǎn)嫡锌,所以它提供了自定義域名功能虑稼,操作如下;

  1. 打開adjust 登入后臺(tái)地址
  2. 選擇你需要配置的應(yīng)用 app,并點(diǎn)擊 app 應(yīng)用模塊最下面的(^)
  3. 點(diǎn)擊所有設(shè)置 --> 自定義鏈接 例如域名為 testdemo
  4. 輸入唯一的子域以注冊點(diǎn)擊 URL 和深層鏈接中使用的子域
  5. 選擇保存
  6. 選擇 ?(勾號(hào)圖標(biāo))以確認(rèn)您已輸入正確的子域
  7. 把得到的自定義域名 例如:testdemo.go.link世舰,去更改 Associated Domains
    1. 打開 Xcode 打開項(xiàng)目
    2. 點(diǎn)擊左上角的文件夾 icon --> 點(diǎn)擊項(xiàng)目名稱 --> 進(jìn)入到「Signing & Capabilities」--> 點(diǎn)擊下方的 「all」--> 找到「Associated Domain」--> 雙擊之前配置的通用鏈接动雹,然后替換成自定義域名,例如:testdemo.go.link
    3. 輸入好之后跟压,按下鍵盤回車鍵(Enter)即可
  8. 回到 adjust 的 「深度鏈接生成器」胰蝠,按照「Adjust 深度鏈接生成器」的設(shè)定,重新生成一遍震蒋,自定義域名會(huì)自動(dòng)生成到 RAW UNIVERSAL LINK茸塞。當(dāng)填寫完之后,點(diǎn)擊最下面的 Generate Deeplink 就可以使用自定義域名的深度鏈接查剖,進(jìn)行開啟 app 了钾虐;

具體詳細(xì)說明可以查看 深度鏈接的文檔

解決 InAppBrowser 打開深度鏈接會(huì)直接開啟商店

使用了 react-native-inappbrowser-reborn 在 app 內(nèi)部開啟瀏覽器進(jìn)行第三方綁定認(rèn)證,等待完成之后的 redirect笋庄,開啟深度鏈接時(shí)效扫,會(huì)自動(dòng)打開商店,而不是開啟重新返回 app直砂;

這個(gè)時(shí)候需要做 2 個(gè)步驟:

  1. react-native-inappbrowser-reborn 改用 openAuth菌仁,它分三個(gè)參數(shù),第一個(gè)參數(shù)是原本的 url静暂,第二個(gè)參數(shù)是 scheme 例如 my-app://济丘,第三個(gè)參數(shù)就是關(guān)于瀏覽器的對象配置
  2. 進(jìn)入 adjust 后臺(tái),打開「深度鏈接生成器」, 然后重新按照之前的配置重新配置一條深度鏈接,但在選擇 FORMAT 但時(shí)候摹迷,請選擇 jsr疟赊,簡單描述一下 jsr 的類型,它通用鏈接會(huì)在這種情況下中斷并將所有用戶發(fā)送到商店峡碉,即使他們安裝了該應(yīng)用程序也是如此近哟。關(guān)于jsr可以看這里
  3. 如果原本使用了自定義域名 xxx.go.link,這個(gè)時(shí)候會(huì)消失,打開鏈接會(huì)是 404异赫,這個(gè)時(shí)候把它換成原本的「通用鏈接」xxx.adj.st 就可以了椅挣,當(dāng)然也可以自己進(jìn)行組合,格式如下
`https://app.adjust.com/jsr?url=${encodeURIComponent(https://xxx.adj.st?adj_t=xxxx&adjust_deeplink_js=1&${'其他的參數(shù)'}`)}`
  1. 當(dāng)再次使用 InAppBrowser.openAuth 的時(shí)候塔拳,就可以在.then 的回調(diào)函數(shù)中鼠证,拿到{type: 'success', url: 'my-app://?xxxx'}的內(nèi)容,然后就可以根據(jù)自己的業(yè)務(wù)需求進(jìn)行編碼了

注意:adjust_deeplink_js=1 是必須要加的參數(shù)靠抑,不然還是會(huì)一樣開啟商店 詳情可以查看 我的應(yīng)用已經(jīng)安裝量九,但為何還是會(huì)被轉(zhuǎn)到應(yīng)用商店?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末颂碧,一起剝皮案震驚了整個(gè)濱河市荠列,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌载城,老刑警劉巖肌似,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诉瓦,居然都是意外死亡川队,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門睬澡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來固额,“玉大人,你說我怎么就攤上這事煞聪《孵铮” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵昔脯,是天一觀的道長啄糙。 經(jīng)常有香客問我,道長云稚,這世上最難降的妖魔是什么迈套? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮碱鳞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘踱蛀。我一直安慰自己窿给,他們只是感情好贵白,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著崩泡,像睡著了一般禁荒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上角撞,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天呛伴,我揣著相機(jī)與錄音,去河邊找鬼谒所。 笑死热康,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的劣领。 我是一名探鬼主播姐军,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼尖淘!你這毒婦竟也來了奕锌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤村生,失蹤者是張志新(化名)和其女友劉穎惊暴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體趁桃,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辽话,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镇辉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屡穗。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖忽肛,靈堂內(nèi)的尸體忽然破棺而出村砂,到底是詐尸還是另有隱情,我是刑警寧澤屹逛,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布础废,位于F島的核電站,受9級(jí)特大地震影響罕模,放射性物質(zhì)發(fā)生泄漏评腺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一淑掌、第九天 我趴在偏房一處隱蔽的房頂上張望蒿讥。 院中可真熱鬧,春花似錦、人聲如沸芋绸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摔敛。三九已至廷蓉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間马昙,已是汗流浹背桃犬。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留行楞,地道東北人攒暇。 一個(gè)月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像敢伸,于是被迫代替她去往敵國和親扯饶。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容