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 的通用鏈接:
- 打開 adjust 登入后臺(tái)地址
- 找到你需要設(shè)定的應(yīng)用,然后點(diǎn)擊應(yīng)用下的 灰色三角形(^) --> 「所有設(shè)置」
- 完成上面的點(diǎn)擊流程耸峭,右邊會(huì)出現(xiàn)側(cè)邊欄菜單桩蓉,請點(diǎn)擊「平臺(tái)」--> 「應(yīng)用類型請選擇 IOS」--> 「默認(rèn)設(shè)備選擇通用」--> 「點(diǎn)擊通用鏈接(Universal Linking)」
- 應(yīng)用前綴(APP PREFIX),需要前往 Apple Developer 賬戶找到
- 應(yīng)用方案(APP SCHEME), 這個(gè)可以自定義即可劳闹,但必須是唯一性的
- 點(diǎn)擊保存之后院究,就可以得到一個(gè)原始通用鏈接,類似 xxxx.adj.st 這樣的
如果遇到不明白的地方本涕,可以查看官網(wǎng)的 IOS 通用鏈接配置 截圖流程业汰,會(huì)比較詳細(xì)
啟用 Associated Domain(比較重要,能否開啟 app菩颖,就看它了)
- 打開 Xcode 打開項(xiàng)目
- 點(diǎn)擊左上角的文件夾 icon --> 點(diǎn)擊項(xiàng)目名稱 --> 進(jìn)入到「Signing & Capabilities」--> 點(diǎn)擊下方的 「all」--> 找到「Associated Domain」--> 點(diǎn)擊 「+」然后輸入 applinks:你的通用鏈接样漆,例如 applinks:xxxx.adj.st。(前綴必須是 applinks:)
- 輸入好之后位他,按下鍵盤回車鍵(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 深度鏈接生成器
- 打開adjust 登入后臺(tái)地址
- 登入之后點(diǎn)擊左側(cè)菜單選擇「深度鏈接生成器」仰挣,如果你的后臺(tái)沒有出現(xiàn)的話伴逸,可能是權(quán)限不夠,需要增加權(quán)限
- PLATFORM 請選擇 【Multiplatform】(多平臺(tái))
- AD ENVIRONMENT 請選擇 【Other】
- FORMAT 請選擇 【ulink】(如果不選 ulink 的話膘壶,下面選項(xiàng)中就不會(huì)出現(xiàn) RAW UNIVERSAL LINK)
- APP 請選擇 你的項(xiàng)目
- 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è)定)
- RAW UNIVERSAL LINK 請?zhí)顚?通用鏈接例如 xxx.adj.st(還可以設(shè)定自定義品牌鏈接,這個(gè)會(huì)在最后詳細(xì)說明)
- ANDROID APP SCHEME 請?zhí)顚?你項(xiàng)目中的 scheme床玻,例如 myapp://
- IOS UNIVERSAL LINK PATH 和 ANDROID DEEPLINK PATH 請?zhí)顚懸粯拥穆窂絽?shù) 例如 navigate?pageName=Dame
- FALLBACK URL(optional) 這一項(xiàng)非必填良狈,目前使用的地方是,在非移動(dòng)端的設(shè)備點(diǎn)擊深度鏈接時(shí)笨枯,跳轉(zhuǎn)到指定的網(wǎng)頁,例如:https://www.testdemo.com/
- REDIRECT MACOS URL(optional) 對 ios 和 macos 有效遇西,這一項(xiàng)非必填馅精,目前使用的地方是,在非移動(dòng)端的設(shè)備點(diǎn)擊深度鏈接時(shí)粱檀,跳轉(zhuǎn)到指定的網(wǎng)頁洲敢,例如:https://www.testdemo.com/
- 點(diǎn)擊底部的 Generate Deeplink,等待完成之后茄蚯,就會(huì)創(chuàng)建出一個(gè)深度鏈接压彭,出現(xiàn)在右側(cè)睦优,這個(gè)時(shí)候可以復(fù)制它去嘗試 app 的設(shè)定是否有效了
當(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)整
以下代碼功能如下
- 接收深度鏈接的參數(shù)進(jìn)行格式化處理
- 把處理好的參數(shù)和事件存入 state 中
- 處理導(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)嫡锌,所以它提供了自定義域名功能虑稼,操作如下;
- 打開adjust 登入后臺(tái)地址
- 選擇你需要配置的應(yīng)用 app,并點(diǎn)擊 app 應(yīng)用模塊最下面的(^)
- 點(diǎn)擊所有設(shè)置 --> 自定義鏈接 例如域名為 testdemo
- 輸入唯一的子域以注冊點(diǎn)擊 URL 和深層鏈接中使用的子域
- 選擇保存
- 選擇 ?(勾號(hào)圖標(biāo))以確認(rèn)您已輸入正確的子域
- 把得到的自定義域名 例如:testdemo.go.link世舰,去更改 Associated Domains
- 打開 Xcode 打開項(xiàng)目
- 點(diǎn)擊左上角的文件夾 icon --> 點(diǎn)擊項(xiàng)目名稱 --> 進(jìn)入到「Signing & Capabilities」--> 點(diǎn)擊下方的 「all」--> 找到「Associated Domain」--> 雙擊之前配置的通用鏈接动雹,然后替換成自定義域名,例如:testdemo.go.link
- 輸入好之后跟压,按下鍵盤回車鍵(Enter)即可
- 回到 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è)步驟:
- react-native-inappbrowser-reborn 改用 openAuth菌仁,它分三個(gè)參數(shù),第一個(gè)參數(shù)是原本的 url静暂,第二個(gè)參數(shù)是 scheme 例如 my-app://济丘,第三個(gè)參數(shù)就是關(guān)于瀏覽器的對象配置
- 進(jìn)入 adjust 后臺(tái),打開「深度鏈接生成器」, 然后重新按照之前的配置重新配置一條深度鏈接,但在選擇 FORMAT 但時(shí)候摹迷,請選擇 jsr疟赊,簡單描述一下 jsr 的類型,它通用鏈接會(huì)在這種情況下中斷并將所有用戶發(fā)送到商店峡碉,即使他們安裝了該應(yīng)用程序也是如此近哟。關(guān)于jsr可以看這里
- 如果原本使用了自定義域名 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ù)'}`)}`
- 當(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)用商店?