1. 集成神策分析 SDK RN 模块

对于 React Native 开发的应用,可以使用 npm 方式集成神策分析 SDK RN 模块

1.1. 安装神策分析 SDK RN 模块

npm install sensorsdata-analytics-react-native
CODE

1.2. 链接神策分析 SDK RN 模块

注意:React Native 0.60 及以上版本会 autolinking,不需要执行下边的 react-native link 命令。

react-native link sensorsdata-analytics-react-native
CODE

1.3. 配置 package.json

在 React Native 项目里的 package.json 文件的 script 模块里增加如下配置

"scripts": {
      "postinstall": "node node_modules/sensorsdata-analytics-react-native/SensorsDataRNHook.js -run"
}
CODE

示意图如下:

1.4. 执行 npm  命令

npm run-script postinstall
CODE


2. iOS 端

2.1. 集成神策分析 iOS SDK

React Native 0.60 及以上版本使用以下方式引入 RNSensorsAnalyticsModule 组件以及 SensorsAnalyticsSDK

2.1.1. 使用 CocoaPods  集成

在项目目录下执行:

 cd ios && pod install && cd .. 
CODE

React native 0.60 以下版本使用以下方式集成 SensorsAnalyticsSDK

2.1.2. 使用源码集成

  1. 从 GitHub 上获取 iOS SDK 的源码,并将解压后的源码放入 React Native 项目的 ios 文件夹中;
  2. 打开 React Native 项目的 iOS 工程,将 SensorsAnalyticsSDK.xcodeproj 添加到 iOS 工程里 Libraries  文件夹里;
  3. SensorsAnalyticsSDK.framwwork 添加到 "General" → "Framwworks,Libraries,Embedded Content" 中;
  4. 项目设置 "Build Phase" → "Link Binary With Libraries" 中添加依赖库:libicucorelibsqlite3libz
  5. 添加不同模块的代码:
    1. Core 文件夹是 SDK 的核心文件,默认添加的;
    2. Location 文件夹是采集定位信息的,如果不需要采集定位信息,可以从项目中移除这个文件夹;
    3. 对于打通 H5,SDK 默认支持的是 WKWebView 的新版打通方案。如果想使用老版打通方案,可以引入 WKWebView 文件夹;如果使用的是 UIWebView,可以引入 WebView 文件夹;

2.2. 初始化神策分析 SDK

2.2.1. 获取项目数据接收地址

  • 每个项目都有单独的数据接收地址
  • 请使用管理员账号获取响应项目的数据接收地址

2.2.2. 初始化 SDK

在 AppDelegate 的 -application:didFinishLaunchingWithOptions: 中添加初始化代码:

//引入神策分析 SDK
#import <SensorsAnalyticsSDK/SensorsAnalyticsSDK.h>

// 初始化配置
  SAConfigOptions *options = [[SAConfigOptions alloc] initWithServerURL:<#数据接收地址#> launchOptions:launchOptions];

  // 开启全埋点,可根据需求进行组合
  options.autoTrackEventType = SensorsAnalyticsEventTypeAppStart |
                 SensorsAnalyticsEventTypeAppEnd |
                 SensorsAnalyticsEventTypeAppClick |
                 SensorsAnalyticsEventTypeAppViewScreen;
#ifdef DEBUG
  // SDK 开启 Log
  options.enableLog = YES;
#endif

  /**
   * 其他配置
   */
  // 初始化 SDK
  [SensorsAnalyticsSDK startWithConfigOptions:options];
CODE

2.3. 配置 Scheme

2.3.1. 获取项目 Scheme

  • 项目的 Scheme 需要管理员账户进行获取
  • App 工程可以同时配置多个项目的 Scheme

同获取数据接收地址的地方一致,在基本设置→ 数据接入→复制 scheme

2.3.2. App 中添加 Scheme

在 React Native 项目的 ios 工程中选择 Target → Info → URL Types,点击加号(+),将上一步获取的 Scheme 配置到 URL Types 中:

2.3.3. 处理传入的 URL

在 AppDalegate 的 -application:openURL:options: 方法中调用 -handleSchemeUrl: 对神策分析 Scheme 进行处理

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
  if ([[SensorsAnalyticsSDK sharedInstance] canHandleURL:url]) {
    return [[SensorsAnalyticsSDK sharedInstance] handleSchemeUrl:url];
  }
  return NO;
}
CODE

3. Android 端

3.1. 集成和初始化神策分析 Android SDK

请参考 Android SDK 集成和初始化

3.2. 配置混淆

集成神策分析 SDK RN 模块后,如果项目中有使用到混淆,需要在混淆文件中添加如下配置:

-dontwarn com.sensorsdata.analytics.**
-keep class com.sensorsdata.analytics.** {
*;
}
CODE

3.3. 使用 Android Studio 打包集成方式

如果需要把 React Native 组件集成到 Android 应用中,需要在加载 ReactRootView 的 Activity 中添加 RNSensorsAnalyticsPackage 并实现相关回调。

代码示例:

import com.sensorsdata.analytics.RNSensorsAnalyticsPackage;
...
 
public class RNPageActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    public static ReactInstanceManager mReactInstanceManager;
    private final static String TAG = "RNPageActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setCurrentActivity(this)
                .setBundleAssetName("index.android.bundle")
                .setJSMainModulePath("index")
                .addPackage(new MainReactPackage())
                .addPackage(new RNSensorsAnalyticsPackage()) // 添加 RNSensorsAnalyticsPackage
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        // 这个"App1"名字一定要和我们在index.js中注册的名字保持一致AppRegistry.registerComponent()
        mReactRootView.startReactApplication(mReactInstanceManager, "App1", null);
 
        setContentView(mReactRootView);
    }
 
    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostResume(this, this);
            Log.d(TAG, "onResume");
        }
    }
 
    @Override
    protected void onPause() {
        super.onPause();
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostPause(this);
            Log.d(TAG, "onPause");
        }
    }
 
 
    @Override
    public void onBackPressed() {
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onBackPressed();
            Log.d(TAG, "onBackPressed");
        } else {
            super.onBackPressed();
        }
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
 
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostDestroy(this);
            Log.d(TAG, "onDestroy");
        }
        if (mReactRootView != null) {
            mReactRootView.unmountReactApplication();
        }
    }
 
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (BuildConfig.DEBUG) {
            if (keyCode == KeyEvent.KEYCODE_MENU) {//Ctrl + M 打开RN开发者菜单
                mReactInstanceManager.showDevOptionsDialog();
                return true;
            }
        }
        return super.onKeyUp(keyCode, event);
    }
}
CODE

需要在 onResume()onPause()onDestroy()  回调方法中实现 mReactInstanceManager.onHostResume(this, this)mReactInstanceManager.onHostPause(this)mReactInstanceManager.onHostDestroy(this) 方法,否则可能出现点击事件全埋点无法触发情况。

4. 在 React Native 上使用代码埋点

4.1. 在 js 文件中导入神策模块

在具体的 js 文件中导入神策模块  sensors,导入模块示例如下:

import sensors from 'sensorsdata-analytics-react-native'
CODE

4.2. 添加埋点事件

在具体的位置添加事件埋点,以按钮点击时触发事件为例:

其中对应的事件名为:RN_AddToFav对应的事件自定义属性为:ProductID  和 UserLevel;

 <Button title=" Button " 
		onPress={() => 
        sensors.track("RN_AddToFav",{"ProductID":123456,"UserLevel":"VIP"})}>
</Button>
CODE

具体操作如下图所示:

4.3. 用户登录

当用户注册成功或者登录成功时,需要调用 SDK 的 -login: 接口:

sensors.login("<#登录 ID#>");
CODE

为了准确记录登录用户的行为信息,建议在以下时机各调用一次 -login: 接口:

  • 用户在注册成功时
  • 用户登录成功时
  • 已登录用户每次启动 App 时

4.4. 获取匿名 ID

默认情况下,用户登录前 SDK 会根据设备生成的一个匿名 ID您可以通过 - getAnonymousIdPromise 接口获取当前的匿名 ID:

sensors.getAnonymousIdPromise()
CODE

4.5. 记录激活事件

激活事件,建议在原生这边调用。

4.5.1. iOS 端记录激活事件

可以在初始化 SDK 后调用 - trackAppInstall 方法记录激活事件,多次调用此方法只会在第一次调用时触发激活事件:

#warning 需要 #import <AppTrackingTransparency/AppTrackingTransparency.h>
#warning iOS 14+ 使用 IDFA 需要在 info.plist 中添加 NSUserTrackingUsageDescription 字段,详情可参考 https://developer.apple.com/documentation/apptrackingtransparency
  if(@available(iOS 14, *)){
    [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
      [[SensorsAnalyticsSDK sharedInstance] trackAppInstall];
    }];
  }else{
    [[SensorsAnalyticsSDK sharedInstance] trackAppInstall];
  
CODE

若用原记录的激活事件名不是 $AppInstall,需要使用虚拟事件将原激活事件和 $AppInstall 合并分析数据,具体咨询神策技术支持

4.5.2. Android 端记录激活事件

可以调用 trackAppInstall() 方法记录激活事件,多次调用此方法只会在第一次调用时触发激活事件:

if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.M){
    if (ActivityCompat.checkSelfPermission(this, "android.permission.READ_PHONE_STATE") != PackageManager.PERMISSION_GRANTED) {
        // 6.0 以上,无权限时,先申请 READ_PHONE_STATE 权限。
        ActivityCompat.requestPermissions(this, new String[]{"android.permission.READ_PHONE_STATE"}, 100);
    } else {
        // 6.0 以上,有权限时,直接触发激活事件。
        trackAppInstall();
    }
} else {
    // 6.0 以下,无须申请权限,直接触发激活事件。
    trackAppInstall();
}
JAVA

在权限回调的 onRequestPermissionsResult() 方法中,申请权限结果回调无论申请权限成功失败,都要调用 trackAppInstall():

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 100) {
        // 申请权限结果回调时(无论申请权限成功失败),都需要触发激活事件。
        trackAppInstall();
    }
}


/**
 * 记录激活事件
 */
private void trackAppInstall() {
    try {
        JSONObject properties = new JSONObject();
		//这里的 DownloadChannel 负责记录下载商店的渠道,值应传入具体应用商店包的标记。如果没有为不同商店打多渠道包,则可以忽略该属性的代码示例。
        properties.put("DownloadChannel", "XXX");
        // 触发激活事件
        SensorsDataAPI.sharedInstance().trackAppInstall(properties);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
JAVA

若用原记录的激活事件名不是 $AppInstall,需要使用虚拟事件将原激活事件和 $AppInstall 合并分析数据,具体咨询神策技术支持

4.6. 设置事件公共属性

对于所有事件都需要添加的属性,初始化 SDK 后,可以使用 -registerSuperProperties: 方法将属性注册为公共属性:

sensors.registerSuperProperties({"AppName":"RNDemo"});
CODE

公共属性会保存在 App 本地缓存中,可以通过 - unregisterSuperProperties: 删除一个或多个公共属性;或使用 - clearSuperProperties: 删除所有已经设置的事件公共属性。

4.7. 设置页面自定义属性

在通过 Navigation  跳转时,可以在 params 中添加自定义属性,SDK 会自动使用 params 中的设置值对 App 页面浏览事件的属性进行补充或覆盖。

<Button
	title="Go to PersonCenter"
	onPress={() => 
		this.props.navigation.navigate('PersonCenter',{
			sensorsdataparams:{
			$title: 'title',
			param1: 'param1',
			param2: 'param2',
		},
	})
}></Button>
CODE

4.8. 设置组件自定义属性

4.8.1. 普通组件

<Button
  onPress={() => {}}
  title="button"
  sensorsdataparams={{ name: 'button', ignore: true }}
/>
CODE

4.8.2. Touchable 或  Pressable

<TouchableHighlight
  onPress={() => {}}
  sensorsdataparams={{ name: 'TouchableHighlight', ignore: true }}
>
 <Text style={{ fontSize: 20, padding: 10 }}>TouchableHighlight</Text>
 </TouchableHighlight>
CODE

5. 全埋点支持版本

  • App  元素点击事件支持 React Native 0.23 ~ 0.64.2;
  • App 页面浏览事件支持 React Navigation ^2.0 ~ ^5.0;
  • App 可视化全埋点要求 React Native 0.46 ~ 0.64.2。

6. 全埋点配置

6.1. 忽略全埋点采集

如果您想忽略 RN 页面的全埋点事件,在项目 package.json 中增加 sensorsData 配置:


{
  "name": "reactNativeDemo",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios --simulator='iPhone 8'",
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "test": "jest"
  },
  //...
  "sensorsData": {
    "ignoreScreen": true ,
    "ignoreClick": true
  }
}
CODE

配置完成后执行:

node node_modules/sensorsdata-analytics-react-native/SensorsDataRNHook.js -run
CODE

6.2. 忽略单个页面全埋点事件

目前忽略 $AppViewScreen 事件有两种方式:

6.2.1. 方式 一

在 params 中添加 sensorsdataparams 属性,当其中包含 SAIgnoreViewScreen 属性且值为 true 时会忽略该页面浏览事件,但该页面的点击事件仍然为该页面 $screen_name 。

createBottomTabNavigator(
  {
    Component: {
      screen: Tab1,
      params: {
        sensorsdataparams: {
          $screen_name: "screen",
          $title: "title",
          SAIgnoreViewScreen:true
        },
      },
    },
    API: {
      screen: Tab2,
    },
    Other: {
      screen: Tab3,
    },
  }
)
CODE

6.2.2. 方式二

在通过 navigate、pop、goBack、push 等方式进行导航时,在 params 中添加 sensorsdataparams 属性,当其中包含 SAIgnoreViewScreen 属性且值为 true 时会忽略该页面浏览事件,但该页面的点击事件仍然为该页面 $screen_name 。

this.props.navigation.navigate(‘RouteName’, {
  sensorsdataparams: {
    $screen_name: "screen",
    $title: "title",
    SAIgnoreViewScreen : true
  },
})
CODE

6.3. 忽略组件采集

在 sensorsdataparams 中包含 ignore 属性且值为 true 时忽略该组件的点击事件。

<Slider
  sensorsdataparams={{ name: 'Slider', ignore: true }}
  onSlidingComplete={() => {}}
/>
CODE

7. 注意事项

如果项目中之前使用过神策分析 SDK RN 模块 1.1.8 及更早版本并开启了全埋点,那么在升级到最新版本后,请关闭掉之前开启的全埋点相关内容,否则会造成同一 App 元素点击事件被采集到两次的问题。

  1. Android 需要 :
    • 删除对 enableReactNativeAutoTrack() 方法的调用
  2. iOS 端需要:
    • 对于直接集成源代码的开发者,需要在编译选项 Preprocessor Macros 中删掉 SENSORS_ANALYTICS_REACT_NATIVE=1
      (对于直接集成 SDK 工程的项目,需要在 SDK 对应的 project 中修改编译选项,在 Preprocessor Macros中删掉 SENSORS_ANALYTICS_REACT_NATIVE=1)。


    • 对于使用 Cocoapods 集成神策分析 SDK 的开发者,在 pod 'SensorsAnalyticsSDK' 后删掉 :subspecs => ['ENABLE_REACT_NATIVE_APPCLICK']