基礎(chǔ)集成
本文中含有需要您注意的重要提示信息,忽略該信息可能對(duì)您的業(yè)務(wù)造成影響,請(qǐng)務(wù)必仔細(xì)閱讀。
1 路徑設(shè)置
需要檢查目前是否已經(jīng)使用了友盟+SDK,如果已經(jīng)使用,請(qǐng)及時(shí)更改SDK文件路徑:
已經(jīng)集成了友盟+SDK,現(xiàn)在需要集成QT SDK:在QT和友盟+的所有代碼最前面增加(至少早于收數(shù)域名)
QTConfigure.resetStorePath
已經(jīng)集成了QT SDK,現(xiàn)在需要集成友盟+SDK:在QT和友盟+的所有代碼最前面增加(至少早于收數(shù)域名)
UMConfigure.resetStorePath
如果不按照上述的邏輯調(diào)用,則會(huì)使友盟+SDK與QT SDK共同使用一個(gè)存儲(chǔ)路徑,導(dǎo)致日志混亂。具體邏輯為:先調(diào)用的哪個(gè)SDK初始化方法,就重新設(shè)置另外一個(gè)SDK的文件路徑,比如先初始化的友盟+SDK,就調(diào)用 QTConfigure.resetStorePath;,如果是先初始化的QT SDK,就需要調(diào)用UMConfigure.resetStorePath;
2 域名設(shè)置
在預(yù)初始化之前,開發(fā)者需要在調(diào)用SDK任意其它接口之前最先調(diào)用QtConfigure.setCustomDomain()接口設(shè)置私有化環(huán)境收數(shù)域名。
/**
* 設(shè)置上傳統(tǒng)計(jì)日志的主域名和備用域名。此函數(shù)必須在SDK預(yù)初始化/初始化函數(shù)調(diào)用之前調(diào)用。SDK會(huì)優(yōu)先將統(tǒng)計(jì)數(shù)據(jù)上報(bào)到主域名,失敗的情況下會(huì)再嘗試將數(shù)據(jù)上報(bào)到備用域名。
* 主域名primaryDomain或不能傳入null或者空串,如果傳入null或者空串,SDK預(yù)初始化函數(shù)會(huì)拋出SdkDomainUndefined運(yùn)行時(shí)異常。
* @param standbyDomain 備用域名可以傳入null或者空串,此時(shí)SDK認(rèn)為備用域名和主域名完全相同。SDK上傳數(shù)據(jù)失敗后第二次也會(huì)向主域名上報(bào)數(shù)據(jù)。
* 傳入的域名參數(shù)應(yīng)該包含"https://" 前綴。
*/
public static void setCustomDomain(String primaryDomain, String standbyDomain)
參數(shù) | 含義 |
primaryDomain | 上傳日志的主域名收數(shù)地址。 |
standbyDomain | 上傳日志備用域名收數(shù)地址。 |
示例:
public class QTApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
QtConfigure.setCustomDomain("xxxxxx", null); // 請(qǐng)傳入您自己的收數(shù)域名
// 打開調(diào)試log
QtConfigure.setLogEnabled(true);
QtConfigure.preInit(this, "xxxxxx", "Channel");// 請(qǐng)傳入您自己的appkey
QtTrackAgent.disableActivityPageCollection();
// ...
3 合規(guī)初始化
3.1 初始化接口
由于工信部的合規(guī)要求App在用戶同意隱私政策前不可以獲取任何個(gè)人信息,所以 Quick Tracking 修改初始化為以下操作:
您需要確保App有《隱私政策》,并且在用戶首次啟動(dòng)App時(shí)就彈出《隱私政策》取得用戶同意。
您務(wù)必告知用戶您選擇Quick Tracking SDK服務(wù),請(qǐng)?jiān)凇峨[私政策》中增加如下參考條款:“我們的產(chǎn)品集成Quick Tracking SDK,Quick Tracking SDK需要收集您的OAID/GAID/MAC/IMEI/Android ID/IDFA/IDFV/OPENUDID/GUID/SIM卡 IMSI 信息/硬件序列號(hào)/MCC(移動(dòng)國家編碼)、MNC(移動(dòng)網(wǎng)號(hào))以提供統(tǒng)計(jì)分析服務(wù)。”
在用戶同意隱私政策后才可以正式初始化Quick Tracking SDK,具體技術(shù)操作如下:
SDK預(yù)初始化接口
在Applicaiton.onCreate函數(shù)中調(diào)用預(yù)初始化函數(shù)QtConfigure.preInit(),預(yù)初始化函數(shù)不會(huì)采集設(shè)備信息,也不會(huì)向Quick Tracking后臺(tái)上報(bào)數(shù)據(jù)。
// SDK預(yù)初始化函數(shù)
// preInit預(yù)初始化函數(shù)耗時(shí)極少,不會(huì)影響App首次冷啟動(dòng)用戶體驗(yàn)
public static void preInit(Context context,String appkey,String channel)
同意隱私協(xié)議后的正式初始化
一旦App獲取到《隱私政策》的用戶授權(quán),后續(xù)的App冷啟動(dòng),開發(fā)者應(yīng)該保證在Applicaiton.onCreate函數(shù)中調(diào)用預(yù)初始化函數(shù)QtConfigure.preInit()。正式初始化函數(shù)QtConfigure.init可以按需調(diào)用(可以在預(yù)初始化函數(shù)之后緊接著調(diào)用,也可以放到后臺(tái)線程中延遲調(diào)用,但還是必須調(diào)用,不能遺漏)
public static void init(Context context,String appkey,String channel,int deviceType,String pushSecret);
參數(shù) | 含義 | 備注 |
appkey | QT為當(dāng)前應(yīng)用平臺(tái)頒發(fā)的唯一標(biāo)識(shí)。 |
|
channel | app投放的應(yīng)用市場(chǎng) | QT分析平臺(tái)的“系統(tǒng)屬性”中“升級(jí)渠道”的數(shù)據(jù)來源 |
deviceType | QtConfigure.DEVICE_TYPE_PHONE | 默認(rèn)填寫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函數(shù)中調(diào)用該預(yù)初始化函數(shù)
QtConfigure.preInit(this,"您的appkey","應(yīng)用商店名稱");
//同意隱私政策,才可以正式初始化Quick Tracking SDK
if(isflag==1)
{
QtConfigure.init(this,"您的appkey","應(yīng)用商店名稱",QtConfigure.DEVICE_TYPE_PHONE, "");
}
}
}
3.2 Appkey獲取
在初始化SDK時(shí),需要填寫參數(shù)Appkey。Appkey是在Quick Tracking中代表應(yīng)用的唯一ID,在創(chuàng)建應(yīng)用時(shí)生成,其獲取或查看方法詳見文檔:應(yīng)用管理。
4 日志打印
可通過QtConfigure.setLogEnabled(boolean)接口控制【Quick Tracking】LOG的輸出。
注意:
App正式上線前請(qǐng)關(guān)閉SDK運(yùn)行調(diào)試日志。避免無關(guān)Log輸出。
可以通過調(diào)用如下方法控制SDK運(yùn)行調(diào)試日志是否輸出,默認(rèn)情況下SDK運(yùn)行調(diào)試日志關(guān)閉。需要用戶手動(dòng)打開。
/**
* 設(shè)置組件化的Log開關(guān)
* 參數(shù):boolean 默認(rèn)為false,如需查看LOG設(shè)置為true
*/
QtConfigure.setLogEnabled(true);
注意:
如果查看初始化過程中的LOG,一定要在調(diào)用初始化方法前將LOG開關(guān)打開。
日志分為四種等級(jí),方便用戶查看:
Error(打印SDK集成或運(yùn)行時(shí)錯(cuò)誤信息)。
Warn(打印SDK警告信息)。
Info(打印SDK提示信息)。
Debug(打印SDK調(diào)試信息)。
5 特殊場(chǎng)景
5.1 App內(nèi)強(qiáng)制kill或exit之類的方法殺死進(jìn)程
如果開發(fā)者調(diào)用kill或者exit之類的方法殺死進(jìn)程,請(qǐng)務(wù)必在此之前調(diào)用QtTrackAgent.onKillProcess方法,用來保存統(tǒng)計(jì)數(shù)據(jù)。
public static void onKillProcess(Context context);
參數(shù) | 含義 |
context | 當(dāng)前宿主進(jìn)程的ApplicationContext上下文。 |
6 數(shù)據(jù)自定義加密
6.1 自定義編解碼接口函數(shù):
SDK端不直接參與開發(fā)者自定義的加解密算法具體實(shí)現(xiàn),SDK和收數(shù)端提供接口CryptoProvider,由客戶自行實(shí)現(xiàn)此接口中的如下兩個(gè)方法。
public interface CryptoProvider {
byte[] encode(Map<String, String> header, byte[] input);
byte[] decode(Map<String, String> header, byte[] input);
}
接口方法 | 參數(shù)說明 |
public byte[] encode(Map<String, String> header, byte[] input); | 參數(shù): header: 需要傳遞給解密端的額外信息(如:使用的加密算法,加密模式等等任何信息)。 以多個(gè)字符串K-V鍵值對(duì)的形式傳入。SDK會(huì)將此Map中所有K-V鍵值對(duì)參數(shù)內(nèi)容做base64編碼后作為http header字段dc-args傳遞給收數(shù)服務(wù)端。 收數(shù)服務(wù)端會(huì)將此Map參數(shù)原封不動(dòng)傳給對(duì)應(yīng)解密方法。 input: 待加密原始數(shù)據(jù)。 返回值:加密后數(shù)據(jù)。 |
public byte[] decode(Map<String, String> header, byte[] input); | 參數(shù): header: 由加密方傳入的加密額外信息,解密實(shí)現(xiàn)方需要通過這些信息決定解密算法,模式等細(xì)節(jié)。 input: 待解密原始數(shù)據(jù)。 返回值:解密后數(shù)據(jù)。 |
6.2 自定義編解碼接口注冊(cè)函數(shù)
QtConfigure.registerCryptoProvider(Context appContext, CryptoProvider customProvider);
接口方法 | 參數(shù)說明 |
registerCryptoProvider | 參數(shù): appContext: 應(yīng)用applicationContext上下文對(duì)象。 customProvider: 用戶自行實(shí)現(xiàn)的CryptoProvider接口對(duì)象。 |
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("您的收數(shù)服務(wù)域名", null);
QtConfigure.setLogEnabled(true); // 打開SDK調(diào)試日志
QtConfigure.preInit(this, "您的appkey", "您的渠道");
// 開發(fā)者自行實(shí)現(xiàn)的加密、解密接口
CryptoProvider customProvider = new CryptoProvider() {
final String key = "just_for_test";
public byte[] customEncode(final byte[] data, final byte[] key) {
// 開發(fā)者自行實(shí)現(xiàn)
return null;
}
public byte[] customDecode(final byte[] data, final byte[] key) {
// 需開發(fā)者自行實(shí)現(xiàn)
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) {
// 如果傳入的待加密內(nèi)容為null,需要打印相關(guān)錯(cuò)誤日志,方便聯(lián)調(diào)
return result;
}
result = customEncode(input, key.getBytes()); // customEncode需要用戶自行實(shí)現(xiàn)
} 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;
}
};
// 注冊(cè)自定義CryptoProvider接口對(duì)象
final Context appContext = this.getApplicationContext();
QtConfigure.registerCryptoProvider(appContext, customProvider);
// 如果終端用戶已經(jīng)同意隱私授權(quán),再調(diào)用SDK正式初始化函數(shù)。
// 注意:如果是宿主應(yīng)用安裝后的首次冷啟動(dòng),QtConfigure.init正式初始化函數(shù)必須延遲到終端用戶點(diǎn)擊隱私授權(quán)對(duì)話框的“同意”按鈕之后才能被調(diào)用。否則會(huì)導(dǎo)致隱私合規(guī)問題。
if (privacyAuthorizationComplete(appContext)) {
QtConfigure.init(appContext, "您的appkey", "您的渠道", QtConfigure.DEVICE_TYPE_PHONE, null);
}
// ...
}
}