1. 权限配置说明

SDK 共需要四个权限:

权限

用途

INTERNET必须权限,允许应用发送统计数据,SDK 发送埋点数据需要此权限
ACCESS_NETWORK_STATE必须权限,允许应用检测网络状态,SDK 会根据网络状态选择是否发送数据
READ_PHONE_STATE可选权限,允许应用获取设备 IMEI,采用 App 内推广和采集 $carrier 属性时会用到此权限
ACCESS_WIFI_STATE可选权限,允许应用获取 MAC 地址,采用 App 内推广时会用到此权限

SDK 为简化集成步骤,默认在 AndroidManifest.xml 中注册了以上四个权限。如果想要去除 SDK 注册的权限,可以使用 tools:node="remove" 配置。关于 tools:node="remove" 的详细说明可参考谷歌官方文档,配置代码参考:

<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />
XML

2. 开启屏幕方向的自动采集

v1.10.1 及以后的版本可以通过 enableTrackScreenOrientation() 方法开启屏幕方向属性的收集,屏幕方向信息记录在事件的 $screen_orientation 属性中。

SAConfigOptions saConfigOptions = new SAConfigOptions(SA_SERVER_URL);
//利用初始化的 SAConfigOptions 对象开启屏幕方向属性的收集
saConfigOptions.enableTrackScreenOrientation(true);

SensorsDataAPI.startWithConfiguration(this, saConfigOptions);
JAVA

3. 开启位置信息自动采集

v1.10.1 及以后的版本可以通过 setGPSLocation() 方法,把第三方定位获取到的经纬度信息设置给 SDK,设置之后经纬度信息记录在事件的 $longitude$latitude 属性中。

//设置经纬度
SensorsDataAPI.sharedInstance().setGPSLocation(latitude,longitude);
JAVA

4. 事件时长

可以通过计时器统计事件的持续时间。首先,在事件开始时调用(v1.10.6 及以后版本支持) trackTimerStart("Event") ,该方法并不会真正发送事件;在事件结束时,调用 trackTimerEnd("Event", properties),SDK 会触发 "Event" 事件,并自动将事件持续时间记录在事件属性 "$event_duration" 中。例如记录用户浏览商品页面的时间:

// 进入商品页面
// 调用 trackTimerStart("ViewProduct") 标记事件启动时间
SensorsDataAPI.sharedInstance().trackTimerStart("ViewProduct");

// ... 用户浏览商品

// 离开商品页
try {
  // 在属性中记录商品 ID
  JSONObject properties = new JSONObject();
  properties.put("product_id", PRODUCT_ID);
  // 调用 track,记录 ViewProduct 事件,并在属性 event_duration 中记录用户浏览商品的时间
  SensorsDataAPI.sharedInstance().trackTimerEnd("ViewProduct", properties);
} catch (JSONException e) {
  e.printStackTrace();
}
JAVA

多次调用 trackTimerStart("Event") 时,事件 "Event" 的开始时间以最后一次调用时为准。

v3.1.5 版本开始,统计事件时长支持暂停和恢复,通过调用 trackTimerPause(String eventName) 和 trackTimerResume(String eventName) 来分别实现暂停和恢复。

4.1. 同名事件交叉的时长统计

默认情况下,时长的统计以事件名作为标识,相同的事件名会自动匹配 start-end,如果两个同名事件在时间上有交叉部分,会造成错误匹配。为了解决此问题,从 v3.2.11 版本开始 SDK 支持同名事件交叉的时长统计,开发者需要保存 trackTimerStart() 的返回值,以便后续针对性地进行暂停、恢复或停止。

// 开始第一个事件计时
String timer1 = SensorsDataAPI.sharedInstance().trackTimerStart("testTimer");

// 开始第二个事件计时
String timer2 = SensorsDataAPI.sharedInstance().trackTimerStart("testTimer");

//如果需要暂停第一个事件计时
SensorsDataAPI.sharedInstance().trackTimerPause(timer1);

//如果需要恢复第一个事件计时
SensorsDataAPI.sharedInstance().trackTimerResume(timer1);

// 结束第一个事件计时
SensorsDataAPI.sharedInstance().trackTimerEnd(timer1);

// 结束第二个事件计时
SensorsDataAPI.sharedInstance().trackTimerEnd(timer2);
JAVA

5. 获取预置属性

v1.8.17 及以后的版本可以调用 getPresetProperties() 方法获取预置属性。
服务端埋点需要 App 端的一些预置属性时,可以通过此方法获取 App 端的预置属性,再传给服务端。

//获取预置属性
JSONObject presetProperties=SensorsDataAPI.sharedInstance().getPresetProperties();
JAVA

6. 设置动态公共属性

Android SDK v2.0.1 及以后的版本可以通过 registerDynamicSuperProperties() 方法设置动态公共属性,设置之后 SDK 会自动获取 getDynamicSuperProperties() 中的属性添加到触发的事件中。

// 初始化 SDK 后,设置动态公共属性
SensorsDataAPI.sharedInstance().registerDynamicSuperProperties(new SensorsDataDynamicSuperProperties() {
    @Override
    public JSONObject getDynamicSuperProperties() {
        try {
            // 比如 isLogin() 是用于获取用户当前的登录状态,SDK 会自动获取 getDynamicSuperProperties 中的属性添加到触发的事件中。
            boolean bool = isLogin();
            return new JSONObject().put("isLogin",bool);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
});
JAVA

调用 registerDynamicSuperProperties() 方法设置的动态公共属性,不能用 unregisterSuperProperty() 方法删除

7. 获取用户 ID

神策中每个事件都会关联到一个 ID 上,用于标识该事件所对应的用户或设备信息,我们称之为 distinct_id,此值在未调用 SDK 中 login() 方法前,获取的是默认的 SDK 分配的匿名 ID(v1.10.5 及以后的版本默认使用 AndroidId 作为匿名 ID),调用 login() 方法后获取的是 login() 方法中传入的值。

您可以通过 getDistinctId() 方法获取该 ID:

//获取当前用户的distinctId
String distinctId=SensorsDataAPI.sharedInstance().getDistinctId();
JAVA

您也可以通过 getAnonymousId() 方法 获取神策分析 SDK 分配的匿名 ID:

//获取当前用户的匿名id
String AnonymousId=SensorsDataAPI.sharedInstance().getAnonymousId();
JAVA

8. 用户属性设置

8.1. 记录初次设定的用户属性

对于只在首次设置时有效的属性,我们可以使用 profileSetOnce() 记录这些属性。与 profileSet() 方法不同的是,如果被设置的用户属性已存在,则这条记录会被忽略而不会覆盖已有数据,如果属性不存在则会自动创建。因此,profileSetOnce() 适用于为用户设置首次激活时间、首次注册时间等属性。例如:

try {
    JSONObject properties = new JSONObject();
    properties.put("AdSource", "XXX Store");

    // 设定用户渠道为,"developer@sensorsdata.cn" 的 "AdSource" 属性值为 "XXX Store"
    SensorsDataAPI.sharedInstance().profileSetOnce(properties);

    JSONObject newProperties = new JSONObject();
    newProperties.put("AdSource", "Email");

    // 再次设定用户渠道,设定无效,"developer@sensorsdata.cn" 的 "AdSource" 属性值仍然是 "XXX Store"
    SensorsDataAPI.sharedInstance().profileSetOnce(newProperties);
} catch (JSONException e) {
    e.printStackTrace();
}
JAVA

8.2. 数值类型的属性

对于数值型的用户属性,可以使用 profileIncrement() 对属性值进行累加。常用于记录用户付费次数、付费额度、积分等属性。例如:

// 将用户游戏次数属性增加一次
SensorsDataAPI.sharedInstance().profileIncrement("GamePlayed", 1);

// 增加用户付费次数和积分
Map<String, Number> properties = new HashMap<String, Number>();
properties.put("UserPaid", 1);
properties.put("PointEarned", 12.5);

SensorsDataAPI.sharedInstance().profileIncrement(properties);
JAVA

8.3. 列表类型的属性

对于用户喜爱的电影、用户点评过的餐厅等属性,可以记录列表型属性,例如:

Set<String> movies = new HashSet<String>();
movies.add("Sicario");
movies.add("Love Letter");

// 设定用户观影列表属性,设定后属性 "Movies" 为: ["Sicario", "Love Letter"]
SensorsDataAPI.sharedInstance().profileAppend("Movies", movies);

// 再次设定该属性,属性 "Movies" 为: ["Sicario", "Love Letter", "Dead Poets Society"]
SensorsDataAPI.sharedInstance().profileAppend("Movies", "Dead Poets Society");
JAVA

需要注意的是,列表型属性中的元素必须为 String 类型,且元素的值会自动去重。关于列表型限制请见数据格式

9. 开启点击分析功能

版本要求

  • 神策分析 1.13+
  • 此功能依赖于全埋点中点击事件采集的开启
  • 使用此功能前,确保您的 App 中配置了当前项目的 Scheme,详细操作可参考配置 Scheme

v1.9.0+ 版本的 SDK 支持 App 点击分析功能,SDK 初始化前调用 SAConfigOptions 实例的 enableHeatMap() 方法,并且参数传入 true 即可开启 SDK 的点击分析功能:

saConfigOptions.enableHeatMap(true);
JAVA

开启 App 点击分析后,该功能默认对所有页面上的点击生效,如果您只是想部分页面进行热力图,可以通过 addHeatMapActivity()addHeatMapActivities() 方法配置:

//开启某个 Activity 的点击图
SensorsDataAPI.sharedInstance().addHeatMapActivity(Class<?> activity);
//开启多个 Activity 的点击图
SensorsDataAPI.sharedInstance().addHeatMapActivities(List<Class<?>> activitiesList);
JAVA

10. 开启调试模式动态配置功能

在神策 Android SDK (3.0.3+) 中,可以通过扫描网页二维码的方式,开启该设备的「调试模式」。调试模式的配置请参考调试模式动态配置

11. 启动事件与退出事件的详细说明

神策 SDK 为了应对多进程、强杀等场景,在 v2.0.3 版本加入了 30 秒的 session 机制,用户退出 App 到后台 30 秒的时候,才会触发退出事件,之后再启动 App,才会触发启动事件,用户如果在 30 秒内打开了 App,那么是没有对应的退出事件与启动事件的。

另外,如果在退出 App 到后台 30 秒内,进程还没有被杀掉,那么此时会触发退出事件并尝试上报,如果进程被杀掉了,那么退出事件会在下一次启动时补发。所以在查看数据时,一般退出事件比启动事件少。

12. 自定义上报策略

需要更精细地控制神策分析可以通过以下选项设置数据采集功能。

12.1. 数据采集

在每次调用 track()login()profileSet() 等方法时,神策分析 SDK 会将事件与属性保存在 App 的存储空间中,并会检查如下条件,以判断是否向服务器上传数据:

  1. 是否是WIFI/2G/3G/4G/5G网络条件
  2. 是否满足发送条件之一:
    1. 与上次发送的时间间隔是否大于 flushInterval
    2. 本地缓存日志数目是否大于 flushBulkSize
    3. 事件类型为 login() 方法触发的 $SignUp 事件

默认的 flushBulkSize 为 100 条,默认的 flushInterval 为 15 秒。满足条件后,神策分析 SDK 会将数据 gzip 压缩后,批量发送到神策分析。

如果追求数据采集的时效性,可以调用 flush() 方法,强制将数据发送到神策分析,例如:

// 记录用户登录事件
SensorsDataAPI.sharedInstance().track("UserLogin");

// 强制发送数据
SensorsDataAPI.sharedInstance().flush();
JAVA

在 App 进入后台状态时,SDK 会调用 flush() 方法,将缓存的数据发送到神策分析。

12.2. 设置同步数据时的网络策略

默认情况下,在 WIFI/3G/4G/5G 网络条件下,SDK 都会尝试去同步数据。v1.7.2 及以后的版本支持可以自定义同步数据的网络策略。
通过 setFlushNetworkPolicy() 方法来指定发送数据的网络策略。例如:

//网络模式选项
//SensorsDataAPI.NetworkType.TYPE_2G     2G网络下发送数据
//SensorsDataAPI.NetworkType.TYPE_3G     3G网络下发送数据
//SensorsDataAPI.NetworkType.TYPE_4G     4G网络下发送数据
//SensorsDataAPI.NetworkType.TYPE_5G     5G网络下发送数据
//SensorsDataAPI.NetworkType.TYPE_WIFI   WIFI网络下发送数据
//SensorsDataAPI.NetworkType.TYPE_ALL    2G/3G/4G/5G/WIFI网络下发送数据
//SensorsDataAPI.NetworkType.TYPE_NONE   所有网络下都不发送数据

//指定只在 3G/4G/WIFI 条件下发送数据。
SensorsDataAPI.sharedInstance().setFlushNetworkPolicy(SensorsDataAPI.NetworkType.TYPE_3G|SensorsDataAPI.NetworkType.TYPE_4G|SensorsDataAPI.NetworkType.TYPE_WIFI);
JAVA

12.3. 设置本地缓存上限值

SDK 本地数据库默认缓存数据的上限值为 32MB。 v1.7.4 及以后的版本支持通过 setMaxCacheSize() 方法来设定缓存数据的上限值。参数单位 byte

SAConfigOptions saConfigOptions = new SAConfigOptions(SA_SERVER_URL);
//在初始化时,利用 SAConfigOptions 设置本地数据缓存上限值为16MB
saConfigOptions.setMaxCacheSize(16 * 1024 * 1024);
JAVA

v3.1.0 及之前的版本,设置缓存方式: 

 查看示例
//设置本地数据缓存上限值为16MB
SensorsDataAPI.sharedInstance().setMaxCacheSize(16 * 1024 * 1024);
JAVA

当存储数量达到上限值,会依次丢弃老数据,保留最新的数据

12.4. 修改 SDK 配置参数

修改 app/src/main/AndroidManifest.xml,在 <application> 标签中,添加 <meta-data> 项,可以修改 SDK 的默认参数,支持的选项如下:

  • com.sensorsdata.analytics.android.FlushInterval - 设置 SDK 的 flushInterval,单位毫秒,默认值为 15 秒;
  • com.sensorsdata.analytics.android.FlushBulkSize - 设置 SDK 的 flushBulkSize,默认值为 100;
  • com.sensorsdata.analytics.android.ResourcePackageName - 设置 App 的 Package Name,默认值为 Application 对象的 Package Name,当 App 的 R.* class 的 Package Name 与 Application 不同时,需要手动填入该配置;

例如,设置神策分析 SDK 的 flushInterval 为 30 秒,flushBulkSize 为 50 条,关闭 Toast 提示:

<application>
    <meta-data
        android:name="com.sensorsdata.analytics.android.FlushInterval"
        android:value="30000" />
    <meta-data
        android:name="com.sensorsdata.analytics.android.FlushBulkSize"
        android:value="50" />
    <meta-data
        android:name="com.sensorsdata.analytics.android.ShowDebugInfoView"
        android:value="false" />
</application>
XML

也可以利用代码,修改 FlushInterval 和 FlushBulkSize

SAConfigOptions saConfigOptions = new SAConfigOptions(SA_SERVER_URL);
//在初始化时,利用 SAConfigOptions 设置相关参数
// 每缓存 50 条日志发送一次
saConfigOptions.setFlushBulkSize(50);
// 设置每 30 秒发送一次
saConfigOptions.setFlushInterval(30000);
JAVA

v3.1.0 及之前的版本,设置相关参数:

 查看示例
// 每缓存 50 条日志发送一次
SensorsDataAPI.sharedInstance().setFlushBulkSize(50);

// 设置每 30 秒发送一次
SensorsDataAPI.sharedInstance().setFlushInterval(30000);

//打开自动追踪
SensorsDataAPI.sharedInstance().enableAutoTrack();
JAVA

13. 清空本地缓存事件

v3.1.5 及以后的版本可以通过 deleteAll() 方法,删除 App 本地存储的所有事件。

如果不是特殊要求,请不要调用此方法。

//删除 App 本地存储的所有事件
SensorsDataAPI.sharedInstance().deleteAll();
JAVA

14. 设置自签证书

v3.1.2 及以后的版本可以通过 setSSLSocketFactory() 方法设置自签证书,设置自签证书后,SDK 内所有的 HTTPS 请求会进行此接口设置的证书校验。以 DER 格式的证书为例:

try {
    //构建 SSLSocketFactory 实例
    SSLSocketFactory sslSocketFactory ;
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    // 其中 R.raw.ca 是您这边自签证书的公钥
    InputStream in = getResources().openRawResource(R.raw.ca);
    Certificate ca = cf.generateCertificate(in);
    try {
        in.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    keystore.load(null, null);
    keystore.setCertificateEntry("ca", ca);
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keystore);
    // Create an SSLContext that uses our TrustManager
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), null);
    sslSocketFactory = sslContext.getSocketFactory();
    //将实例传入神策
    SensorsDataAPI.sharedInstance().setSSLSocketFactory(sslSocketFactory);
} catch (Exception e) {
    e.printStackTrace();
}
JAVA

关于 SSL 的更多内容可以参考谷歌使用文档

15. 追踪并进行渠道匹配和回传

v3.2.8 开始 SDK 支持追踪自定义事件时进行渠道匹配,可以调用 SensorsDataAPI.sharedInstance().trackChannelEvent() 方法对匹配的事件进行追踪,后台匹配到渠道信息后会将结果回传到渠道商。

15.1. 使用方法:

JSONObject properties = new JSONObject(); //自定义属性,如没有则忽略
SensorsDataAPI.sharedInstance().trackChannelEvent("事件名", properties);
JAVA

15.2. 效果:

触发后事件属性会增加 $is_channel_callback_event 和 $channel_device_info 属性 ,如下:

其中:

  • 当次安装首次触发回传事件,记录事件并进行渠道匹配和回传。
  • 当次安装再次触发回传事件,记录事件并进行渠道匹配,匹配结果不进行回传。
  • 卸载重装首次触发回传事件,记录事件并进行渠道匹配和回传。

p.s. 上述规则适用于同名事件,不同事件之间不相互影响。

首次触发事件(事件名存入 SharedPreference 中)$is_channel_callback_event 为 true,否则为 false。

16. 入库前修改事件信息

v3.2.10 及以后版本,SDK 可以通过 setTrackEventCallBack() 方法过滤埋点的事件数据。

SensorsDataAPI.sharedInstance().setTrackEventCallBack(new SensorsDataTrackEventCallBack() {
	/**
     * 事件回调接口
     *
     * @param eventName 事件名称
     * @param eventProperties 要修改的事件属性
     * @return true 表示事件将入库, false 表示事件将被抛弃
     */
	@Override
	public boolean onTrackEvent(String eventName, JSONObject eventProperties) {
		// 移除 BuyProduct 事件的 productID 属性
		if(eventName.equals("BuyProduct")){
			eventProperties.remove("productID");
		}	
		//
		return true;
	}
});
JAVA

17. 开启 Crash 信息的自动采集

v1.8.12 及以后的版本支持 Crash 信息收集,App Crash 时,会触发 AppCrashed 事件,堆栈信息记录在 app_crashed_reason 属性中。

SAConfigOptions saConfigOptions = new SAConfigOptions(SA_SERVER_URL);
//利用初始化的 SAConfigOptions 对象开启 crash 信息采集 
saConfigOptions.enableTrackAppCrash();
SensorsDataAPI.startWithConfiguration(this, saConfigOptions);
JAVA

v3.1.0 及之前的版本,开启 Crash 采集: 

 查看示例
//开启 crash 信息收集
SensorsDataAPI.sharedInstance().trackAppCrash();
JAVA

18. 自定义匿名 ID

默认情况下,SDK 会生成匿名 ID 并可以保证该 ID 的唯一性,如果需要替换神策默认分配的匿名 ID ,可以在初始化 SDK 之后立即调用 identify(“用户自定义匿名 ID ”) 方法进行替换。

 代码示例:
//设置自定义匿名 ID,在初始化 SDK 之后立即调用
SensorsDataAPI.sharedInstance().identify(“用户自定义匿名 ID ”);
JAVA

19. 关于 MultiDex

如果使用了 MultiDex ,请确保神策 Android SDK 的代码都指定到主 DEX 中。可以通过在 multiDexKeepProguard 里添加如下配置:

-keep class com.sensorsdata.analytics.android.** { *; }
GROOVY