Android SDK 使用文档

1. 权限

需要许可如下权限(添加到 AndroidManifest.xml 文件中)

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>

若App中开启了定位权限(Android 6.0及以上需动态授权),sdk将自动获取定位数据

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

2. 导入 SDK

2.1. Gradle

我们已将SDK同步至Jcenter仓库,开发人员可通过Gradle命令集成。

appbuild.grade中添加下列语句。其中请将 x.x 替换为版本号。当前最新版为2.2.5。

compile 'com.netease.da:hubbledata-sdk-android:x.x.x'

2.2. AAR导入

将下载好的aar文件放到libs目录下, 在app的build.gradle增加如下repo

      flatDir {
        dirs 'libs'
      }

然后使用下面的方式引入

compile 'com.netease.da:hubbledata-sdk-android:x.x.x'

2.3. JAR导入(新版本已废弃, 请任选上面的一种方式)

~~ 将下载包里面的 mobidroid.jar 放入 App 项目 libs 目录中 ~~

然后在appbuild.grade中添加下列语句

// 数据埋点
compile files("libs/mobidroid.jar")

3. 配置

appbuild.gradle 中添加下列语句

    android {
        defaultConfig {
            resValue("string", "hubble_app_key", "您的 app key")
        }
    }

4. 启用

4.1. Android 4.0 及以上版本(新接口)

  • 自定义Application,并在onCreate()方法中添加如下代码,开启统计功能

      DATracker.enable(this);
    
  • 如果需要配置参数,可参考下面常用接口

      DATracker.enableWithConfiguration(this, new DAConfiguration()
                      .setAppChannel("demo") // 默认 null
                      .setAppVersion("1.0") // 默认取 versionName
                      .enableLog(true) // 默认 false
                      .enableLocationAccess(true) // 默认 false          
              );
    
  • 全部参数接口概览

接口名称 参数类型 参数默认值 参数含义
setAppChannel String Null 应用渠道名称
setAppVersion String PackageInfoversionName 应用版本号
enableLog Boolean false 是否输出控制台日志
enableAutoUpload Boolean true 是否自动上传数据
enableSendOnWifi Boolean false 是否仅在wifi下上传数据
enablePageTrack Boolean true 是否开启自动页面统计
enableLocationAccess Boolean false 是否读取位置信息
enableABTest Boolean false 是否使用 A/B Test
enableABVisualization Boolean false 是否使用 A/B Test 可视化调试
enableCodelessTrack Boolean false 是否开启自动埋点
enableCodelessCircle Boolean false 是否使用自动埋点可视化圈选
enableMultiProcess Boolean false 是否支持多进程
setFlushBulkSize Integer 100 本地数据库缓存的最大记录数
setFlushInterval Long 15000(ms) 两次数据发送的最小时间间隔
setClient DAClient Http Client,默认使用HttpURLConnection进行数据上报。自定义的方法请参考文档后面的详细说明

4.2. Android 4.0 及以上版本(老接口,已废弃,但不影响使用)

自定义Application,并在onCreate()方法中添加如下代码,开启统计功能。注意:SDK 目前不支持多进程,初始化前要判断进程,避免重复初始化

    DATracker.enableTracker(getApplicationContext(), "demo", "1.0", "Google Play", true, false);

参数依次为,当前 Context 实例、程序的 app key、版本和来源渠道、是否允许 SDK 在会话开始和进入后台时自动上传数据、是否只在 wifi 环境下发送数据

设置为只在 WIFI 下发送数据,会导致服务器接收数据延迟,对统计系统结果的及时性会产生影响,不建议使用

App Key 可从移动分析系统网站获取,不得使用为空值或者 null, 多次调用参数请确保一致

例如,定义MyApplication继承Application

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        DATracker.enableTracker(getApplicationContext(), "demo", "1.0", "Google Play", true, false);
    }
}

并在AndroidManifest.xml注册

<application
    android:name=".MyApplication"
    ...>
    ...
</application>

4.3. Android 4.0 以下版本

在 App 中所有的 Activity onCreate 方法中调用如下代码,开启统计功能

参数依次为,当前 Activity 实例、程序的 app key、版本和来源渠道

DATracker.enableTracker(this, "demo", "1.0", "Google Play");

如需要禁用 SDK 自动上传数据功能,调用

DATracker.enableTracker(this, "demo", "1.0", "Google Play", false);

如需要设置只在 wifi 环境下发送数据,调用

DATracker.enableTracker(this, "demo", "1.0", "Google Play", true, true);

Android 4.0以下版本必须在 App 中所有的 Activity onResume 方法中调用如下方法,标识用户会话开始。Android 4.0及以上版本无需调用。

DATracker.getInstance().resume();

Android 4.0以下版本必须在 App 中所有 Activity onPause 方法添加调用,标识用户会话结束。Android 4.0及以上版本无需调用。

DATracker.getInstance().close();

如果应用中包含 Activitiy 类继承于自定义 Activity 衍生类,则只需在该类加入上述代码即可,即 onResume 中添加 resumeonPause 中添加 close 方法,如果 Main Activity 也继承于该类,则还需在 onCreate 中添加 enableTracker,其子类不需要添加。但其他非集成于此类的 Activitiy 类必须按上述规则添加代码。

5. A/B测试编程模式

5.1. 开启A/B测试

  • 接口定义
/**
 * 打开ab test
 *
 * @param abEnabled
 */
public DATracker enableABTest(boolean abEnabled)
  • 示例调用
DATracker.getInstance()
        .enableLog(true)
        .enableABTest(true);

5.2. 获取“实验变量”

“实验变量”的值控制展示的内容或程序的逻辑。一般情况下,不同实验版本应有不同的变量值。实验变量值应由相关人员在后台提前录入,如下图所示:

配置实验变量

SDK提供两个接口获取“实验变量”:同步获取和异步获取。

(1) 同步获取:从缓存获取,若命中,则返回缓存的变量值;否则,返回默认值。

  • 接口定义
public <V> V getVariable(String variableName, V defaultValue)
  • 示例调用
// 获取Boolean类型的试验变量isNewHome的值,第二个参数为设定默认值
if (DATracker.getInstance().getVariable("isNewHome", false)) {
    // 跳转至新首页
} else {
    // 跳转至旧首页
}

(2) 异步获取:从网络获取,若网络请求成功,则返回最新的变量值并更新缓存;否则,返回默认值。

  • 接口定义
/**
 * @param variableName 实验变量名
 * @param defaultValue 默认值
 * @param listener 异步回调
 * @param <V>
 */
public <V> void asyncGetVariable(final String variableName, final V defaultValue, final OnVariableReceived<V> listener)
  • 示例调用
DATracker.getInstance().asyncGetVariable("isNewHome", false, new OnVariableReceived<Boolean>() {
    @Override
    public void onReceived(Boolean value) {
        if (value) {
            // 跳转至新首页
        } else {
            // 跳转至旧首页
        }
    }
});

6. 云端配置

配置说明

名称 含义 可选值 是否支持
autoLog 是否开启全埋点 true,false 不支持
pageLog 是否开启pageView事件 true,false 支持
enableABTest 是否开启AB Test true,false 支持
abTestInterval 实验数据更新频率 time(h) 支持
updateInterval 云端配置更新频率 time(h) 支持

7. 远程Debug模式

使用Debug可以实时远程查看上传的debug数据,便于测试;web端开关可控制debug数据是否写入线上数据库。

8. 可插装Client

SDK默认使用HttpURLConnection进行数据上报,开发人员如果希望自定义数据上报操作(比如实现免流量功能),可在初始化SDK时,多传入一个DAClient实例,示例代码如下:

DATracker.enableTracker(getApplicationContext(), "MA-809E-F83D9C323504", "1.0", "Google Play", true, false, new MyClient());

DAClient定义如下:

public interface DAClient {
    android.util.Pair<Integer, String> execute(String endpointUrl, Map<String, String> headers, byte[] dataEncrypted);
}

其中,endpointUrl为数据上报服务器;headers为http/https请求头部参数,包括数据编码、加密的必要参数,开发人员构造http/https请求时,必须添加这些头部参数;dataEncrypted为加密后的数据。

DAClient实例示例代码如下:

public class MyClient implements DAClient {
    private String TAG = "MyClient";
    private SSLSocketFactory mFoundSSLFactory;

    public MyClient() {
        // By default, we use a clean, FACTORY default SSLSocket. In general this is the right
        // thing to do.
        try {
            final SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, null, null);
            mFoundSSLFactory = sslContext.getSocketFactory();
        } catch (final GeneralSecurityException e) {
            Log.i("TAG", "System has no SSL support. Built-in events editor will not be available", e);
            mFoundSSLFactory = null;
        }
    }

    @Override
    public Pair<Integer, String> execute(String endpointUrl, Map<String, String> headers, byte[] dataEncrypted) {
        byte[] response = performRequest(endpointUrl, headers, dataEncrypted);
        if (response == null) {
            Log.d(TAG, "the response is null, abort");
            return null;
        }
        try {
            JSONObject json = new JSONObject(new String(response));
            int code = json.optInt("code");
            if (code == 200) {
                Log.d(TAG, "Finish uploading: " + code);
                return new Pair<Integer, String>(code, "Finish uploading");
            } else {
                Log.d(TAG, "Failed to upload, resonse code: " + code);
                return new Pair<Integer, String>(code, "Failed to upload");
            }
        } catch (JSONException e) {
            Log.d(TAG, "Failed to transfer response from the internet to JsonObject: " + e.getLocalizedMessage());
            return new Pair<Integer, String>(4004, "Failed to transfer response from the internet to JsonObject");
        }
    }

    public byte[] performRequest(String endpointUrl, Map<String, String> headers, byte[] dataEncrypted) {
        Log.v(TAG, "Attempting request to " + endpointUrl);
        byte[] response = null;

        // the while(retries) loop is a workaround for a bug in some Android HttpURLConnection
        // libraries- The underlying library will attempt to reuse stale connections,
        // meaning the second (or every other) attempt to connect fails with an EOFException.
        // Apparently this nasty retry logic is the current state of the workaround art.
        int retries = 0;
        boolean succeeded = false;
        while (retries < 3 && !succeeded) {
            InputStream in = null;
            OutputStream out = null;
            BufferedOutputStream bout = null;
            HttpURLConnection connection = null;

            try {
                final URL url = new URL(endpointUrl);
                connection = (HttpURLConnection) url.openConnection();
                if (null != mFoundSSLFactory && connection instanceof HttpsURLConnection) {
                    ((HttpsURLConnection) connection).setSSLSocketFactory(mFoundSSLFactory)
                    ;
                }
                connection.setConnectTimeout(2000);
                connection.setReadTimeout(10000);
                if (headers != null) {
                    for (String key : headers.keySet()) {
                        connection.setRequestProperty(key, headers.get(key));
                    }
                }
                connection.setFixedLengthStreamingMode(dataEncrypted.length);
                connection.setDoOutput(true);
                connection.setRequestMethod("POST");
                out = connection.getOutputStream();
                bout = new BufferedOutputStream(out);
                bout.write(dataEncrypted);
                bout.flush();
                bout.close();
                bout = null;
                out.close();
                out = null;
                in = connection.getInputStream();
                response = slurp(in);
                in.close();
                in = null;
                succeeded = true;
            } catch (final Exception e) {
                Log.d(TAG, "Error occured during data sending, abort reason: " + e.getMessage());
                retries = retries + 1;
            } finally {
                if (null != bout)
                    try {
                        bout.close();
                    } catch (final IOException e) {
                        ;
                    }
                if (null != out)
                    try {
                        out.close();
                    } catch (final IOException e) {
                        ;
                    }
                if (null != in)
                    try {
                        in.close();
                    } catch (final IOException e) {
                        ;
                    }
                if (null != connection)
                    connection.disconnect();
            }
        }
        if (retries >= 3) {
            Log.v(TAG, "Could not connect to DATracker service after three retries.");
        }
        return response;
    }

    private static byte[] slurp(final InputStream inputStream)
            throws IOException {
        final ByteArrayOutputStream buffer = new ByteArrayOutputStream();

        int nRead;
        byte[] data = new byte[8192];

        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }

        buffer.flush();
        return buffer.toByteArray();
    }
}

9. 控制台日志输出

如果App开发人员需要查看SDK内部日志,可通过该接口打开日志。默认关闭。

开启控制台日志。建议在自定义Application的 onCreate 中调用。

DATracker.getInstance().enableLog(true);

关闭控制台日志。建议在自定义Application的 onCreate 中调用。

DATracker.getInstance().enableLog(false);

10. 是否读取定位

当app具备定位权限且该接口设置为true时,读取定位数据。否则,不读取。默认为false。

DATracker.getInstance().enableLocationAccess(true);

11. 手动发送数据

手动发送数据

DATracker.getInstance().upload();

12. 手动禁用自动上传

这里的自动上传仅仅指的是允许 SDK 在会话开始和进入后台时自动上传数据

DATracker.getInstance().setAutoUploadOn(false);

13. 设置两次数据发送的最小时间间隔

当用户调用该接口设置两次数据发送的最小时间间隔interval(ms)时,开启固定间隔自动上传数据,默认关闭。当interval < 15000ms 时,仍按照默认值 15000ms 计算,即用户设置的间隔时间不得低于默认值 15000ms。

public void setFlushInterval(long flushInterval);

14. 设置本地数据库缓存的最大记录数

当用户调用该接口设置本地数据库缓存的最大记录数时,开启超出阈值立即上传数据,默认关闭。当用户设置的 flushBulkSize < 100 时,仍按照默认值 100 计算,即用户设置的最大记录数不得低于默认值 100。

public void setFlushBulkSize(int flushBulkSize);

15. 手动开启只在 WIFI 下发送数据

DATracker.getInstance().setSendOnWifiOn(true);

设置为只在 WIFI 下发送数据,会导致服务器接收数据延迟,对统计系统结果的及时性会产生影响,不建议使用

16. 推广跟踪

启用推广追踪,请在 Main Activity 里紧跟 启用 API 后调用

DATracker.getInstance().enableCampaign();

此方法只需要在 自定义Application 或 Main Activity 内调用,旧版接口,不推荐使用

17. 获取 Device ID

DATracker.getInstance().getDeviceId();

该 Device ID 并非 Apple UDID, 仅用户系统本身设备去重用途, 并且可能根据 Apple 政策做相应调整, 不保证长期唯一性

18. 用户帐号管理

在用户登录后,请调用如下接口,参数为用户帐号

public void loginUser(String userId);

当用户登出后,请调用

public void logoutUser();

如登录发生在需要捕捉事件后,则该事件无用户信息

19. 用户位置记录

在拿到用户经纬度时, 调用如下接口记录用户位置

public void setLocation(double latitude, double longitude);

或者如果App开启了定位权限,可以调用如下接口设置sdk的定位读取权限。若设置为true,sdk会在应用进入前台时,自动读取定位数据,部分机型可能会弹出定位询问对话框。若设置为false,sdk不会读取定位数据。默认为false。

public void enableLocationAccess(boolean bool);

20. 事件捕捉

调用如下方法进行事件捕捉

public void trackEvent(String eventId);
public void trackEvent(final String eventId, final Map<String, String> attributes);

eventId 为事件标识,如 "login", "buy"

DATracker.getInstance().trackEvent("login");

attributes 为自定义字段名称,格式如 "{"money":"100", "timestamp":"1357872572"}"

可对事件发生时的其他信息进行记录

Map<String, String> attr = new HashMap<String, String>();
attr.put("money", "100");
DATracker.getInstance().trackEvent("login", attr);

如果需要记录事件发生持续时间,可调用如下接口

public void trackEvent(String eventId, int costTime);
public void trackEvent(final String eventId, final int costTime, final Map<String, String> attributes);

如果需要记录事件发生时的位置信息, 可调用如下接口

public void trackEvent(final String eventId, double latitude, double longitude);
public void trackEvent(final String eventId, double latitude, double longitude,
                           final Map<String, String> attributes)

如果需要记录发生持续时间以及记录事件发生时的位置信息, 可调用如下接口

public void trackEvent(final String eventId, final int costTime, double latitude, double longitude,
                               final Map<String, String> attributes)

虽然在任何地方都可以进行事件捕捉,但最好不要在较多循环内或者非主线程中调用,以及最好不要使用很长 eventID 或者 key value 值,否则会增加 SDK 发送的数据量

21. 事件自定义通用属性

特别地,如果某个事件的属性,在所有事件中都会出现,可以将该属性设置为事件通用属性,通用属性会保存在 App 本地,可调用如下接口:

public void registerSuperProperties(Map<String, String> superProperties);

成功设置事件通用属性后,再通过 trackEvent 追踪事件时,事件通用属性会被添加进每个事件中。重复调用 registerSuperProperties 会覆盖之前已设置的通用属性。

如果不覆盖之前已经设定的通用属性,可调用:

public void registerSuperPropertiesOnce(Map<String, String> superProperties);

查看当前已设置的通用属性,调用:

public Map<String,String> currentSuperProperties();

删除一个通用属性,调用:

public void unregisterSuperProperty(String superPropertyName);

删除所有已设置的事件通用属性,调用:

public void clearSuperProperties();

当事件通用属性和事件属性的 Key 冲突时,事件属性优先级最高,它会覆盖事件公共属性。

22. 事件耗时统计

可以通过计时器统计事件的持续时间,默认的时间单位是毫秒。首先,在事件开始时调用 trackTimer 记录事件开始时间,该方法并不会真正发送事件,接口为

public void trackTimer(final String eventId);
public void trackTimer(final String eventId, final TimeUnit timeUnit);

调用trackEvent 时,若已记录该事件的开始时间,SDK会在追踪相关事件时自动将事件持续时间记录在事件属性中,并删除该事件定时器。

清除所有的事件定时器,调用:

public void clearTimedEvents();

多次调用 trackTimer 时,相同 eventId 的事件的开始时间以最后一次调用时为准。

23. 异常捕捉

在 try catch block 里面调用,参数为 Exception (含子类)实例

try {
    int b = 1/0;
} catch (ArithmeticException e) {
    DATracker.getInstance().trackException(e);
}

如还需要记录 Callstack,可调用

DATracker.getInstance().trackExceptionWithCallstack(e);

如需要 crash 捕捉, 需要在启用 SDK 后在每个需要捕捉 crash 信息的线程中调用如下方法来开启该功能

Thread.setDefaultUncaughtExceptionHandler(new DATracker.UncaughtExceptionHandler());

如需要在 Activity 中捕捉 crash,则需要在 onCreate 里面调用如下方法

Thread.setDefaultUncaughtExceptionHandler(new DATracker.UncaughtExceptionHandler());

如需捕捉应用运行过程中的所有 crash,则需在自定义Application的 onCreate 中调用如下方法。推荐使用。

Thread.setDefaultUncaughtExceptionHandler(new DATracker.UncaughtExceptionHandler());

24. 屏幕 View 捕捉

public void trackScreen(String screenName);

screenName 为当前 View 名称

25. 搜索动作捕捉

keyword 为搜索关键词,searchType 为搜索类型,比如新闻搜索,视频搜索等

public void trackSearch(String keyword, String searchType);

26. 分享动作捕捉

content 为分享内容,from 为分享发生地,to 为分享目的地,比如新浪微博,网易微博等

public void trackShare(String content, String from, String to);

27. 用户任务记录

对用户的任务进行记录,参数为任务 id 和任务失败原因,可用于用户行为完成,用户行为耗时等统计。

DATracker.getInstance().trackOnMissionBegan("mission-1")
DATracker.getInstance().trackOnMissionAccomplished("mission-1");
DATracker.getInstance().trackOnMissionFailed("mission-2", "no power");

28. 订单统计

public void trackOrder(@NonNull double amount, @NonNull String unit, Map<String, String> attr)

amount 为订单金额,不可为空;unit 为货币单位,采用国际通用标准,例如人民币 “CNY”,不可为空;attr 为其他自定义属性,可以为空

29. 设置用户属性

为了更准确地提供针对人群的分析服务,可以使用 SDK 的 DATracker$People 设置用户属性。用户可以在留存分析、分布分析等功能中,使用用户属性作为过滤条件,精确分析特定人群的指标。

获取当前用户信息设置实例

DATracker.getInstance().getPeople();

设置当前用户信息属性(全局或单个)

public void set(Map<String, String> properties);
public void set(String property, String value);

设置当前用户信息属性(如果该属性已经设置过,则忽略)。与 set() 方法不同的是,如果被设置的用户属性已存在,则这条记录会被忽略而不会覆盖已有数据,如果属性不存在则会自动创建。因此,setOnce() 比较适用于为用户设置首次激活时间、首次注册时间等属性。

public void setOnce(Map<String, String> properties);
public void setOnce(String property, String value);

清除当前用户信息属性

public void unset(String property);

删除当前用户记录

public void deleteUser();

记录用户消费接口(用于用户价值评估功能)。正数金额代表客户的消费金额,负金额代表客户的退款。

public void trackCharge(double amount);
public void trackCharge(double amount, Map<String, String> properties);

清除用户消费记录

public void clearCharges();

30. 设置用户公共属性

设置用户账户

public People setAccount(String account);

设置用户真实姓名

public People setRealName(String realName);

设置用户性别(0-女,1-男,2-未知)

public People setGender(int gender);

设置用户出生日期(SDK会自动转换格式:yyyy-MM-dd )

public People setBirthday(Date birthday);

连续设置用户基本信息

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
    Date date = dateFormat.parse("1989-08-03");
    DATracker.getInstance().getPeople().setAccount("nailperry").setRealName("张三").setGender(1).setBirthday(date);
} catch (ParseException e) {
    e.printStackTrace();
}

一次性设置用户基本信息

public void setPopulationAttributes(String account, String realName, Date birthday, int gender);

设置用户地址信息

public void setLocation(String country, String region, String city);

31. 页面统计

31.1. 版本要求

Android 4.0+

31.2. 默认采集页面数据

EventID 为 固定统一的 da_screen

dateTypepv

properties 的参数设计如下:

(1) $screenName 为当前页面的名称;

  • 当页面统计的当前页面为Activity时,$screenNameActivityName
  • 当页面统计的当前页面为Activity下的Fragment时,$screenNameActivityName/FragmentName

(2) $screenTitle 为当前页面的title,可为空;

31.3. 页面统计开关(默认为true)

开启

DATracker.getInstance().enablePageTrack(true);

关闭

DATracker.getInstance().enablePageTrack(false);

31.4. 自定义页面信息

  • Fragment

对于 App 中的核心页面Fragment,我们提供了一个接口 FragmentAutoTracker

public interface FragmentAutoTracker {
    /**
     * 返回当前页面的Url
     * 用作下个页面的referrer
     * @return String
     */
    String getScreenUrl();

    /**
     * 返回当前页面的Title
     * @return String
     */
    String getScreenTitle();

    /**
     * 返回自定义属性集合
     * 我们内置了两个属性:$screenName,代表当前页面名称;$screenTitle 为当前页面的title,可为空; 
     * 默认情况下,
     * $screenName会采集当前Activity的CanonicalName,即:
     * activity.getClass().getCanonicalName(), 如果想自定义页面名称, 可以在Map里put该key进行覆盖。注意:screenName的前面必须要要加"$"符号。
     * $screenTitle 会通过activity.getTitle().toString()采集页面主题,如果想自定义页面主题,可重写getScreenTitle()函数。
     *
     * @return Map<String, String>
     */
    Map<String, String> getTrackProperties();
}

当用户实现该接口时,SDK 会将 getTrackProperties 返回的属性(Map类型)加入页面统计事件的属性中,作为用户访问该页面时的事件属性;SDK 会将 getScreenUrl 返回的字符串作为页面的 Url Schema,记录在页面统计事件的 $url 属性中,并且当用户切换页面时,将前一个页面中的 Url Schema 作为当前页面事件的 $referrer 属性。

例如:

public class OrderDetailFragment extends Fragment implements FragmentAutoTracker {
    @Override
    public String getScreenUrl() {
        return "da://page/order/detail?orderId=888888";
    }

    @Override
    public String getScreenTitle() {
        return "订单详情";
    }

    @Override
    public Map<String, String> getTrackProperties() {
        Map<String, String> properties = new HashMap<>();
        properties.put("orderId", "888888");
        properties.put("manufacturer", "da");
        return properties;
    }
}
  • Activity

对于 App 中的核心页面Activity,我们提供了一个接口 ActivityAutoTracker

public interface ActivityAutoTracker extends FragmentAutoTracker{
    boolean trackFragmentAsScreen();
}

该接口相比于Fragment多了一个trackFragmentAsScreen()函数,当该函数返回 true 时,则将Activity中的Fragment作为页面进行统计,而不统计Activity页面。当该函数返回false时,则只统计Activity页面,不统计Activity中的Fragment。此功能需结合Fragment数据采集使用。

当对Activity中的Fragment进行数据采集时,请确保trackFragmentAsScreen()返回true。

31.5. 过滤部分页面

开启PageTrack后,如果需要指定部分页面不被PageTrack,可以按照下面示例指定哪些页面不被PageTrack:

HashSet<String> list = new HashSet<>();
list.add(MainActivity.class.getCanonicalName());
DATracker.getInstance().filterAutoTrackActivities(list);

31.6. 采集Fragment数据

情形一:

一个Activity同一时刻在屏幕中只将一个Fragment作为页面进行统计的情形,例如,主页(Activity)通过底部Tab切换Fragment,每切换到一个Tab,便将当前Tab对应的Fragment作为页面进行统计。

对于需要进行页面统计的Fragment,除了在FragmentonResume()onPause()生命周期中分别加入onFragmentResumeonFragmentPause代码外,APP开发人员还需要根据Fragment的管理方式重写setUserVisibleHintonHiddenChanged方法。如果不清楚是否应该重写setUserVisibleHintonHiddenChanged方法,建议这两个方法都重写。

建议上述代码可以在一个基类TrackedFragment中做,让所有需要进行页面统计的Fragment类都继承这个基类TrackedFragment,就完成了所有子类页面埋点。

代码示例如下:

public class TrackedFragment extends Fragment{
    @Override
    public void onResume() {
        super.onResume();
        DATracker.getInstance().onFragmentResume(this);
    }

    @Override
    public void onPause() {
        super.onPause();
        DATracker.getInstance().onFragmentPause(this);
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        DATracker.getInstance().setFragmentUserVisibleHint(this, isVisibleToUser);
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        DATracker.getInstance().onFragmentHiddenChanged(this, hidden);
    }
}

Activity实现ActivityAutoTracker接口且trackFragmentAsScreen()返回true时,SDK 会自动识别Activity中当前显示的Fragment并进行数据采集。反之,当Activity没有实现ActivityAutoTracker接口或者trackFragmentAsScreen()返回false时,不采集该Activity下的任何Fragment数据。

情形二:(局限性)

当一个Activity下同时在屏幕中显示多个调用了SDK的onFragmentResumeonFragmentPause接口的Fragment时,我们无法判断将哪个作为页面统计。

31.7. 页面时长统计

31.7.1. 启用

  • 开关

    DATracker.getInstance().enablePageTrack(true);
    
  • Activity

    打开开关后,即可自动统计,无需添加额外代码。

  • Fragment 和 V4Fragment

    需要分别继承 HubbleBaseFragment 和 HubbleBaseV4Fragment 两个基类。

31.7.2. 设置业务属性

  • 接口

    实现下面接口 (Activity、Fragment、V4Fragment)

      public interface IHubblePageInfo {
          /**
           * 获取页面自定义属性
           *
           * @return 页面自定义属性的封装对象
           */
          HubblePageInfo getPageInfo();
      }
    
  • 示例

      public class DemoActivity extends Activity implements IHubblePageInfo {
    
          private HubblePageInfo mHubblePageInfo;
    
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_demo);
          }
    
          @Override
          public HubblePageInfo getPageInfo() {
              // 创建对象,也可以放在其他位置
              if (mHubblePageInfo == null) {
                  mHubblePageInfo = new HubblePageInfo();
              }
              // 设置属性,也可以放在其他位置,原则上赋值时间越早越好
              // 自定义 eventId(可选)。如果不设置,SDK 默认设为 “da_duration_当前类名” 
              mHubblePageInfo.eventId = "id";
              // 自定义属性(可选)
              mHubblePageInfo.attributes.put("key1", "value1");
              mHubblePageInfo.attributes.put("key2", "value2");
    
              // 返回页面属性对象(必填)
              return mHubblePageInfo;
          }
      }
    
  • 原则

    • HubblePageInfo 对象必须声明为成员变量,否则会影响统计数据。
    • HubblePageInfo 对象的创建和属性赋值可以仿照上面示例的用法,也可以放在别处,原则上时间越早越好。 比如,一拿到属性数据就可以设置了。

32. AB编程试验

32.1. 最低版本要求

Android **5.0**(我们使用了[MediaProjection][1]来共享屏幕)

32.2. 需要的权限

<!-- Ab编程试验需要的权限 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

32.3. 接入代码样例

DATracker.getInstance().enableABVisualization(true);

32.4. 说明:

32.5. 1. 关于授权

我们需要两个权限, 一个是android.permission.SYSTEM_ALERT_WINDOW, 我们已经在SDK里面做了权限的申请, 第一次授权成功后, 请重新扫描二维码打开应用. 如果在左下角看到了悬浮按钮, 就说授权成功了.

应用每次扫描二维码打开时, 会向用户申请录制屏幕的权限, 目前只有授权成功后才会开始分享屏幕.
如果用不到该功能, 可以不写这个权限生命.

32.6. 关于proguard

SDK已经进行了proguard, 请不要二次proguard!!

results matching ""

    No results matching ""