本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。
1 路径设置
需要检查目前是否已经使用了友盟+SDK,如果已经使用,请及时更改SDK文件路径:
已经集成了友盟+SDK,现在需要集成QT SDK:在QT和友盟+的所有代码最前面增加(至少早于收数域名)
QTConfigure.resetStorePath
已经集成了QT SDK,现在需要集成友盟+SDK:在QT和友盟+的所有代码最前面增加(至少早于收数域名)
UMConfigure.resetStorePath
如果不按照上述的逻辑调用,则会使友盟+SDK与QT SDK共同使用一个存储路径,导致日志混乱。具体逻辑为:先调用的哪个SDK初始化方法,就重新设置另外一个SDK的文件路径,比如先初始化的友盟+SDK,就调用 QTConfigure.resetStorePath;,如果是先初始化的QT SDK,就需要调用UMConfigure.resetStorePath;
2 域名设置
在预初始化之前,开发者需要在调用SDK任意其它接口之前最先调用QtConfigure.setCustomDomain()接口设置私有化环境收数域名。
/**
* 设置上传统计日志的主域名和备用域名。此函数必须在SDK预初始化/初始化函数调用之前调用。SDK会优先将统计数据上报到主域名,失败的情况下会再尝试将数据上报到备用域名。
* 主域名primaryDomain或不能传入null或者空串,如果传入null或者空串,SDK预初始化函数会抛出SdkDomainUndefined运行时异常。
* @param standbyDomain 备用域名可以传入null或者空串,此时SDK认为备用域名和主域名完全相同。SDK上传数据失败后第二次也会向主域名上报数据。
* 传入的域名参数应该包含"https://" 前缀。
*/
public static void setCustomDomain(String primaryDomain, String standbyDomain)
参数 | 含义 |
primaryDomain | 上传日志的主域名收数地址。 |
standbyDomain | 上传日志备用域名收数地址。 |
示例:
public class QTApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
QtConfigure.setCustomDomain("xxxxxx", null); // 请传入您自己的收数域名
// 打开调试log
QtConfigure.setLogEnabled(true);
QtConfigure.preInit(this, "xxxxxx", "Channel");// 请传入您自己的appkey
QtTrackAgent.disableActivityPageCollection();
// ...
3 合规初始化
3.1 初始化接口
由于工信部的合规要求App在用户同意隐私政策前不可以获取任何个人信息,所以 Quick Tracking 修改初始化为以下操作:
您需要确保App有《隐私政策》,并且在用户首次启动App时就弹出《隐私政策》取得用户同意。
您务必告知用户您选择Quick Tracking SDK服务,请在《隐私政策》中增加如下参考条款:“我们的产品集成Quick Tracking SDK,Quick Tracking SDK需要收集您的OAID/GAID/MAC/IMEI/Android ID/IDFA/IDFV/OPENUDID/GUID/SIM卡 IMSI 信息/硬件序列号/MCC(移动国家编码)、MNC(移动网号)以提供统计分析服务。”
在用户同意隐私政策后才可以正式初始化Quick Tracking SDK,具体技术操作如下:
SDK预初始化接口
在Applicaiton.onCreate函数中调用预初始化函数QtConfigure.preInit(),预初始化函数不会采集设备信息,也不会向Quick Tracking后台上报数据。
// SDK预初始化函数
// preInit预初始化函数耗时极少,不会影响App首次冷启动用户体验
public static void preInit(Context context,String appkey,String channel)
同意隐私协议后的正式初始化
一旦App获取到《隐私政策》的用户授权,后续的App冷启动,开发者应该保证在Applicaiton.onCreate函数中调用预初始化函数QtConfigure.preInit()。正式初始化函数QtConfigure.init可以按需调用(可以在预初始化函数之后紧接着调用,也可以放到后台线程中延迟调用,但还是必须调用,不能遗漏)
public static void init(Context context,String appkey,String channel,int deviceType,String pushSecret);
参数 | 含义 | 备注 |
appkey | QT为当前应用平台颁发的唯一标识。 |
|
channel | app投放的应用市场 | QT分析平台的“系统属性”中“升级渠道”的数据来源 |
deviceType | QtConfigure.DEVICE_TYPE_PHONE | 默认填写QtConfigure.DEVICE_TYPE_PHONE即可 |
pushSecret | 废弃字段,填写空即可 | 废弃字段,填写空即可 |
示例:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//必须在Applicaiton.onCreate函数中调用该预初始化函数
QtConfigure.preInit(this,"您的appkey","应用商店名称");
//同意隐私政策,才可以正式初始化Quick Tracking SDK
if(isflag==1)
{
QtConfigure.init(this,"您的appkey","应用商店名称",QtConfigure.DEVICE_TYPE_PHONE, "");
}
}
}
3.2 Appkey获取
在初始化SDK时,需要填写参数Appkey。Appkey是在Quick Tracking中代表应用的唯一ID,在创建应用时生成,其获取或查看方法详见文档:应用管理。
4 日志打印
可通过QtConfigure.setLogEnabled(boolean)接口控制【Quick Tracking】LOG的输出。
注意:
App正式上线前请关闭SDK运行调试日志。避免无关Log输出。
可以通过调用如下方法控制SDK运行调试日志是否输出,默认情况下SDK运行调试日志关闭。需要用户手动打开。
/**
* 设置组件化的Log开关
* 参数:boolean 默认为false,如需查看LOG设置为true
*/
QtConfigure.setLogEnabled(true);
注意:
如果查看初始化过程中的LOG,一定要在调用初始化方法前将LOG开关打开。
日志分为四种等级,方便用户查看:
Error(打印SDK集成或运行时错误信息)。
Warn(打印SDK警告信息)。
Info(打印SDK提示信息)。
Debug(打印SDK调试信息)。
5 特殊场景
5.1 App内强制kill或exit之类的方法杀死进程
如果开发者调用kill或者exit之类的方法杀死进程,请务必在此之前调用QtTrackAgent.onKillProcess方法,用来保存统计数据。
public static void onKillProcess(Context context);
参数 | 含义 |
context | 当前宿主进程的ApplicationContext上下文。 |
6 数据自定义加密
6.1 自定义编解码接口函数:
SDK端不直接参与开发者自定义的加解密算法具体实现,SDK和收数端提供接口CryptoProvider,由客户自行实现此接口中的如下两个方法。
public interface CryptoProvider {
byte[] encode(Map<String, String> header, byte[] input);
byte[] decode(Map<String, String> header, byte[] input);
}
接口方法 | 参数说明 |
public byte[] encode(Map<String, String> header, byte[] input); | 参数: header: 需要传递给解密端的额外信息(如:使用的加密算法,加密模式等等任何信息)。 以多个字符串K-V键值对的形式传入。SDK会将此Map中所有K-V键值对参数内容做base64编码后作为http header字段dc-args传递给收数服务端。 收数服务端会将此Map参数原封不动传给对应解密方法。 input: 待加密原始数据。 返回值:加密后数据。 |
public byte[] decode(Map<String, String> header, byte[] input); | 参数: header: 由加密方传入的加密额外信息,解密实现方需要通过这些信息决定解密算法,模式等细节。 input: 待解密原始数据。 返回值:解密后数据。 |
6.2 自定义编解码接口注册函数
QtConfigure.registerCryptoProvider(Context appContext, CryptoProvider customProvider);
接口方法 | 参数说明 |
registerCryptoProvider | 参数: appContext: 应用applicationContext上下文对象。 customProvider: 用户自行实现的CryptoProvider接口对象。 |
6.3 示例代码
import com.quick.qt.commonsdk.sm.CryptoProvider;
import com.quick.qt.commonsdk.QtConfigure;
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
QtConfigure.setCustomDomain("您的收数服务域名", null);
QtConfigure.setLogEnabled(true); // 打开SDK调试日志
QtConfigure.preInit(this, "您的appkey", "您的渠道");
// 开发者自行实现的加密、解密接口
CryptoProvider customProvider = new CryptoProvider() {
final String key = "just_for_test";
public byte[] customEncode(final byte[] data, final byte[] key) {
// 开发者自行实现
return null;
}
public byte[] customDecode(final byte[] data, final byte[] key) {
// 需开发者自行实现
return null;
}
@Override
public byte[] encode(Map<String, String> header, final byte[] input) {
byte[] result = null;
try {
if (header != null) {
// 示例
header.put("arg1", "value1");
header.put("arg2", "value2");
}
if (input == null) {
// 如果传入的待加密内容为null,需要打印相关错误日志,方便联调
return result;
}
result = customEncode(input, key.getBytes()); // customEncode需要用户自行实现
} catch (Exception e) {
Log.e("customProvider:encode: ", "exception: " + e.getMessage());
}
return result;
}
@Override
public byte[] decode(Map<String, String> header, final byte[] input) {
byte[] result = null;
try {
if (header != null && header.size() > 0) {
Log.i("customProvider", "K-V from encode call.");
for (String key : header.keySet()) {
Log.i("customProvider", "decode: " + key + " = " + header.get(key));
}
}
result = customDecode(input, key.getBytes());
} catch (Exception e) {
Log.e("customProvider:decode: ", "exception: " + e.getMessage());
}
return result;
}
};
// 注册自定义CryptoProvider接口对象
final Context appContext = this.getApplicationContext();
QtConfigure.registerCryptoProvider(appContext, customProvider);
// 如果终端用户已经同意隐私授权,再调用SDK正式初始化函数。
// 注意:如果是宿主应用安装后的首次冷启动,QtConfigure.init正式初始化函数必须延迟到终端用户点击隐私授权对话框的“同意”按钮之后才能被调用。否则会导致隐私合规问题。
if (privacyAuthorizationComplete(appContext)) {
QtConfigure.init(appContext, "您的appkey", "您的渠道", QtConfigure.DEVICE_TYPE_PHONE, null);
}
// ...
}
}