归因与广告 SDK 接入实践:OpenInstall + TikTok

Created on

前言

归因与广告 SDK 的接入通常比推送更繁琐:既有深度链接、Universal Links,又有 IDFA 权限与平台差异。把这些配置沉淀为 Config Plugin,是保证工程可维护的关键。

本文以 OpenInstall + TikTok 的组合为例,拆解真实项目的接入路径与工程化策略。

目标拆解

我们需要解决的能力:

这些能力都需要同时配置原生层与 JS 层,因此最合适的方式是“插件化 + Hook 封装”。

插件入口:统一解析与配置

插件入口负责解析环境变量与参数,然后分发给 Android/iOS 子插件:

const withOpenInstall = (config, props = {}) => {
  const appKey = resolveEnvPlaceholder(
    props.appKey || process.env.EXPO_PUBLIC_OPENINSTALL_APPKEY
  );
  const scheme = resolveEnvPlaceholder(
    props.scheme || process.env.EXPO_PUBLIC_OPENINSTALL_SCHEME
  );
  const domain = resolveEnvPlaceholder(
    props.domain || process.env.EXPO_PUBLIC_OPENINSTALL_DOMAIN
  );

  return withPlugins(config, [
    [
      withOpenInstallAndroid,
      { appKey, scheme, domain, adEnabled: props.adEnabled },
    ],
    [
      withOpenInstallIOS,
      { appKey, scheme, domain, adEnabled: props.adEnabled },
    ],
  ]);
};

这一步的关键是“让配置源统一”,避免多处手工配置。

Android: manifestPlaceholders + 深度链接

OpenInstall 在 Android 侧需要写入 manifestPlaceholders,并配置 Scheme 与 App Links:

OPENINSTALL_APPKEY: project.findProperty('OPENINSTALL_APPKEY') ?: ''
mainActivity["intent-filter"].push({
  action: [{ $: { "android:name": "android.intent.action.VIEW" } }],
  category: [
    { $: { "android:name": "android.intent.category.DEFAULT" } },
    { $: { "android:name": "android.intent.category.BROWSABLE" } },
  ],
  data: [{ $: { "android:scheme": scheme } }],
});

如果启用广告统计,插件还会按需加入 READ_PHONE_STATE 权限以兼容低版本设备。

iOS: Info.plist + Entitlements

iOS 侧关键点包括:

infoPlist["com.openinstall.APP_KEY"] = props.appKey;
entitlements["com.apple.developer.associated-domains"].push(
  `applinks:${props.domain}`
);

如果开启广告统计,还需要补齐 IDFA 权限描述:

infoPlist.NSUserTrackingUsageDescription =
  props.idfaDescription ||
  "为了您可以精准获取到优质推荐内容,需要您允许使用该权限";

TikTok: iOS SKAdNetwork 列表

TikTok 在 iOS 侧需要添加 SKAdNetwork IDs,用于 iOS 14+ 广告归因。插件会批量写入:

config.modResults.SKAdNetworkItems.push({
  SKAdNetworkIdentifier: "238da6jt44.skadnetwork",
});

Android 侧目前不需要特殊配置,但保留插件入口,方便后续 SDK 升级。

JS 层封装:初始化与事件追踪

在 JS 层,通常会封装一个统一的事件 Hook,例如:

const { trackStandardEvent, trackCustomEvent, identify } = useTikTokEvents();
await trackStandardEvent("Purchase", { value: 99.9, currency: "THB" });

配合一个单例 Manager 管理 SDK 初始化,避免重复 init 造成异常。

在 app.config 中启用

[
  "@repo/attribution/plugin",
  {
    appKey: process.env.EXPO_PUBLIC_OPENINSTALL_APPKEY,
    scheme: process.env.EXPO_PUBLIC_OPENINSTALL_SCHEME,
    domain: process.env.EXPO_PUBLIC_OPENINSTALL_DOMAIN,
    adEnabled: true,
    idfaDescription: "我们需要获取您的设备标识符用于归因分析",
  },
];

TikTok 插件可按需启用:

[
  "@repo/attribution/plugin/tiktok",
  { appId: process.env.EXPO_PUBLIC_TIKTOK_APP_ID },
];

验证流程

  1. expo prebuild 后检查 AndroidManifest 与 Info.plist
  2. 真机验证深度链接与 Universal Links
  3. 推送或链接打开后校验归因参数
  4. 事件上报到 TikTok 控制台确认

小结

归因与广告 SDK 的接入核心不是“接上 SDK”,而是把原生配置变成可复用、可验证的工程化能力。通过 Config Plugin + Hook 的方式,可以让接入成本更低、升级更稳,也更适合长期维护。