Adjust Deeplink + react-native-i

2024-02-21  本文已影响0人  Y_B_T

Adjust Deeplink

Adjust 它的核心功能是 跟踪和分析、归因分析、深度链接、广告花费追踪、防欺诈工具、实时数据等等,它是非常强大也是市面上比较热门营销工具,本次主要介绍深度链接。Adjust 的 SDK 包里已经包含了深度链接的功能,所以不需要再额外下载依赖,只需要在 Adjust 的后台增加一些设定和微改原生代码即可。

React-Native 配置深度链接

深度链接的配置,需要更改「IOS」和「Android」的原生代码,以及使用 Adjust 提供的「深度链接生成器」生成出深度链接。下面会具体讲述更改原生代码和使用深度链接生成器,生出深度链接。也可以查看官网 React-Native 配置。

IOS 通用链接设定

IOS 的通用链接:

  1. 打开 adjust 登入后台地址
  2. 找到你需要设定的应用,然后点击应用下的 灰色三角形(^) --> 「所有设置」
  3. 完成上面的点击流程,右边会出现侧边栏菜单,请点击「平台」--> 「应用类型请选择 IOS」--> 「默认设备选择通用」--> 「点击通用链接(Universal Linking)」
  4. 应用前缀(APP PREFIX),需要前往 Apple Developer 账户找到
  5. 应用方案(APP SCHEME), 这个可以自定义即可,但必须是唯一性的
  6. 点击保存之后,就可以得到一个原始通用链接,类似 xxxx.adj.st 这样的

如果遇到不明白的地方,可以查看官网的 IOS 通用链接配置 截图流程,会比较详细

启用 Associated Domain(比较重要,能否开启 app,就看它了)

  1. 打开 Xcode 打开项目
  2. 点击左上角的文件夹 icon --> 点击项目名称 --> 进入到「Signing & Capabilities」--> 点击下方的 「all」--> 找到「Associated Domain」--> 点击 「+」然后输入 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];
}

<!-- 这段很重要,如果不加它的话,用户通过点击深度链接,把app从背景呼叫到前景时,拿不到深度链接到参数 -->
- (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 执行 pod install,然后再重新 build 到真机上测试,请不要使用模拟器

具体详细说明可以查看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 的内容,可以根据自己的需求设定,但必须是唯一性的。请于上面配置 ios 的通用链接中的 「APP SCHEME」保持一致
具体详细说明可以查看 深度链接 的文档

Adjust 深度链接生成器

  1. 打开adjust 登入后台地址
  2. 登入之后点击左侧菜单选择「深度链接生成器」,如果你的后台没有出现的话,可能是权限不够,需要增加权限
  3. PLATFORM 请选择 【Multiplatform】(多平台)
  4. AD ENVIRONMENT 请选择 【Other】
  5. FORMAT 请选择 【ulink】(如果不选 ulink 的话,下面选项中就不会出现 RAW UNIVERSAL LINK)
  6. APP 请选择 你的项目
  7. TRACKER 请选择 【Dynamic Link】(这些都可以自定义的,建议选择相关的跟踪途径。另外提醒一下在设定链接的时候,请注意「用户目的位置」这一项的子项中深度链接配置,"已安装应用的用户跳转到哪里?",请一定选择「应用内界面」,否则用户打开 app 之后,会跳转到商店,这个很关键。如果遇到打开 app 之后会跳转到商店时,也请检查这一项设定)
  8. RAW UNIVERSAL LINK 请填写 通用链接例如 xxx.adj.st(还可以设定自定义品牌链接,这个会在最后详细说明)
  9. ANDROID APP SCHEME 请填写 你项目中的 scheme,例如 myapp://
  10. IOS UNIVERSAL LINK PATH 和 ANDROID DEEPLINK PATH 请填写一样的路径参数 例如 navigate?pageName=Dame
  11. FALLBACK URL(optional) 这一项非必填,目前使用的地方是,在非移动端的设备点击深度链接时,跳转到指定的网页,例如:https://www.testdemo.com/
  12. REDIRECT MACOS URL(optional) 对 ios 和 macos 有效,这一项非必填,目前使用的地方是,在非移动端的设备点击深度链接时,跳转到指定的网页,例如:https://www.testdemo.com/
  13. 点击底部的 Generate Deeplink,等待完成之后,就会创建出一个深度链接,出现在右侧,这个时候可以复制它去尝试 app 的设定是否有效了

完整的深度链接例如: 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

当把 IOS 和 Android 的需要调整的地方都调整时,在 build 到真机后,点击深度链接不出意外的话,就可以顺利开启 app 了,但想要获取参数,还需要进一步更改 js 代码

注意:在填写 FALLBACK URL(optional) 和 REDIRECT MACOS URL(optional) 请一定要把跳转网站后增加 “/”,不然 IOS 收不到任何参数,范例格式:https://www.testdemo.com/

JS 代码调整

以下代码功能如下

  1. 接收深度链接的参数进行格式化处理
  2. 把处理好的参数和事件存入 state 中
  3. 处理导页的函数监听 state 改变,并符合导页的条件后进行导页

代码仅供参考,可以根据自己的业务需求修改

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轉為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: 動態連結導頁 */
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);

    // 當navigateItem改變時觸發導頁的hook
    useRedirect.redirectByUrlObj({
        navigationRef,
        urlObj: navigateItem,
        onFinish: () => {
            shiftTask();
        },
    });

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

/** 启动监听深度链接 */
const startListenerDeepLinking = () => {
    const handleLink = (link: any, isInit: boolean) => {
        try {
            if (!link.url) return;
            const url = link.url;
            // DynamicLinks挾帶的params參數物件
            const querys = urlQueryParser(url);
            // 定義應處理的event範圍
            const eventRange = [DynamicLinkEventEnum.navigate];
            if (isInit) {
                eventRange.push(DynamicLinkEventEnum.init_app);
            } else {
                eventRange.push(DynamicLinkEventEnum.foreground);
                eventRange.push(DynamicLinkEventEnum.oauth_bind);
            }
            // 屬於DynamicLinkEventEnum定義範圍者才可放入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();
        // 添加深度链接监听器
        const subscription = Linking.addEventListener("url", (event: any) => {
            handleLink(event, false);
        });

        // 清除监听器,避免内存泄漏
        return () => {
            subscription.remove();
        };
    }, []);
};

export default {
    startListenerDeepLinking,
    navigateByDynamicLink,
};

自定义品牌域名

Adjust 提供的域名都是不够人性化的,很多时候想要使用自己的域名来做深度链接,Adjust 也考虑到了这一点,所以它提供了自定义域名功能,操作如下;

  1. 打开adjust 登入后台地址
  2. 选择你需要配置的应用 app,并点击 app 应用模块最下面的(^)
  3. 点击所有设置 --> 自定义链接 例如域名为 testdemo
  4. 输入唯一的子域以注册点击 URL 和深层链接中使用的子域
  5. 选择保存
  6. 选择 ✓(勾号图标)以确认您已输入正确的子域
  7. 把得到的自定义域名 例如:testdemo.go.link,去更改 Associated Domains
    1. 打开 Xcode 打开项目
    2. 点击左上角的文件夹 icon --> 点击项目名称 --> 进入到「Signing & Capabilities」--> 点击下方的 「all」--> 找到「Associated Domain」--> 双击之前配置的通用链接,然后替换成自定义域名,例如:testdemo.go.link
    3. 输入好之后,按下键盘回车键(Enter)即可
  8. 回到 adjust 的 「深度链接生成器」,按照「Adjust 深度链接生成器」的设定,重新生成一遍,自定义域名会自动生成到 RAW UNIVERSAL LINK。当填写完之后,点击最下面的 Generate Deeplink 就可以使用自定义域名的深度链接,进行开启 app 了;

具体详细说明可以查看 深度链接的文档

解决 InAppBrowser 打开深度链接会直接开启商店

使用了 react-native-inappbrowser-reborn 在 app 内部开启浏览器进行第三方绑定认证,等待完成之后的 redirect,开启深度链接时,会自动打开商店,而不是开启重新返回 app;

这个时候需要做 2 个步骤:

  1. react-native-inappbrowser-reborn 改用 openAuth,它分三个参数,第一个参数是原本的 url,第二个参数是 scheme 例如 my-app://,第三个参数就是关于浏览器的对象配置
  2. 进入 adjust 后台,打开「深度链接生成器」, 然后重新按照之前的配置重新配置一条深度链接,但在选择 FORMAT 但时候,请选择 jsr,简单描述一下 jsr 的类型,它通用链接会在这种情况下中断并将所有用户发送到商店,即使他们安装了该应用程序也是如此。关于jsr可以看这里
  3. 如果原本使用了自定义域名 xxx.go.link,这个时候会消失,打开链接会是 404,这个时候把它换成原本的「通用链接」xxx.adj.st 就可以了,当然也可以自己进行组合,格式如下
`https://app.adjust.com/jsr?url=${encodeURIComponent(https://xxx.adj.st?adj_t=xxxx&adjust_deeplink_js=1&${'其他的参数'}`)}`
  1. 当再次使用 InAppBrowser.openAuth 的时候,就可以在.then 的回调函数中,拿到{type: 'success', url: 'my-app://?xxxx'}的内容,然后就可以根据自己的业务需求进行编码了

注意:adjust_deeplink_js=1 是必须要加的参数,不然还是会一样开启商店 详情可以查看 我的应用已经安装,但为何还是会被转到应用商店?

上一篇下一篇

猜你喜欢

热点阅读