1.2.1.3 Android SDK使用说明

优质
小牛编辑
139浏览
2023-12-01

Android SDK 使用文档

需要许可如下权限(添加到 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.1. Gradle

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

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

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")

appbuild.gradle 中添加下列语句

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

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          
              );
    
  • 全部参数接口概览

接口名称参数类型参数默认值参数含义
setAppChannelStringNull应用渠道名称
setAppVersionStringPackageInfoversionName应用版本号
enableLogBooleanfalse是否输出控制台日志
enableAutoUploadBooleantrue是否自动上传数据
enableSendOnWifiBooleanfalse是否仅在wifi下上传数据
enablePageTrackBooleantrue是否开启自动页面统计
enableLocationAccessBooleanfalse是否读取位置信息
enableABTestBooleanfalse是否使用 A/B Test
enableABVisualizationBooleanfalse是否使用 A/B Test 可视化调试
enableCodelessTrackBooleanfalse是否开启自动埋点
enableCodelessCircleBooleanfalse是否使用自动埋点可视化圈选
enableMultiProcessBooleanfalse是否支持多进程
setFlushBulkSizeInteger100本地数据库缓存的最大记录数
setFlushIntervalLong15000(ms)两次数据发送的最小时间间隔
setClientDAClientHttp 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.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 {
            // 跳转至旧首页
        }
    }
});

配置说明

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

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

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();
    }
}

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

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

DATracker.getInstance().enableLog(true);

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

DATracker.getInstance().enableLog(false);

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

DATracker.getInstance().enableLocationAccess(true);

手动发送数据

DATracker.getInstance().upload();

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

DATracker.getInstance().setAutoUploadOn(false);

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

public void setFlushInterval(long flushInterval);

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

public void setFlushBulkSize(int flushBulkSize);
DATracker.getInstance().setSendOnWifiOn(true);

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

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

DATracker.getInstance().enableCampaign();

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

DATracker.getInstance().getDeviceId();

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

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

public void loginUser(String userId);

当用户登出后,请调用

public void logoutUser();

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

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

public void setLocation(double latitude, double longitude);

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

public void enableLocationAccess(boolean bool);

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

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 发送的数据量

特别地,如果某个事件的属性,在所有事件中都会出现,可以将该属性设置为事件通用属性,通用属性会保存在 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 冲突时,事件属性优先级最高,它会覆盖事件公共属性。

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

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

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

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

public void clearTimedEvents();

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

在 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());
public void trackScreen(String screenName);

screenName 为当前 View 名称

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

public void trackSearch(String keyword, String searchType);

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

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

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

DATracker.getInstance().trackOnMissionBegan("mission-1")
DATracker.getInstance().trackOnMissionAccomplished("mission-1");
DATracker.getInstance().trackOnMissionFailed("mission-2", "no power");
public void trackOrder(@NonNull double amount, @NonNull String unit, Map<String, String> attr)

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

为了更准确地提供针对人群的分析服务,可以使用 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();

设置用户账户

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.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.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!!