上一篇文章中我們介紹了android社區中比較火的熱修復功能,並介紹了目前的幾個比較流行的熱修復框架,以及各自的優缺點,同時也介紹了一下自身項目中對熱修復功能的實踐。目前主流的熱修復原理上其實分為兩種,一種是通過利用dex的加載順序實現熱修復功能,一種是通過native層實現指針替換實現熱修復功能,兩種各有利弊可以根據自身產品的需要選擇不同的方案。
而文本將要介紹一下android產品中另一項基礎功能-數據統計。App數據統計的意義在於通過統計用戶的行為方式有針對性的更新展示算法,根據用戶的行為習慣更新產品功能等等,具體而言當我們開發好App後就會把它發到應用市場上,但是目前有很多的應用市場(如,豌豆莢,應用寶,安卓市場等),那麼問題來了,假如我們想統計我們開發的應用的下載次數,就必須使用統計吧,而且它不僅可以統計我們的應用的下載量,啟動次數,還可以統計頁面訪問量、查看程序的bug等等,所以相對於項目而言產品由於存在著持續的迭代與用戶體驗,所以做好數據統計工作是一項必不可少的工作。
本文中數據統計主要介紹兩種:第三方統計服務和自己實現數據統計功能。
相對而言這兩種方式各有利弊,第三方統計服務簡單、方便、統計范圍廣,但是數據保存在第三方,對於一些數據比較敏感的App可能不太喜歡這種方式,而自己實現數據統計功能主要優點就是安全可定制化,當然了缺點也是顯而易見的,就是繁瑣,復雜。
下面我分別就這兩種數據統計方式做一下簡單的介紹。
第三方統計服務
一般情況下App中都是使用第三方數據統計服務的,友盟、百度統計等等,這裡簡單介紹一下友盟統計,其余的都是大同小異。
友盟統計官網
友盟統計中不但有統計相關功能,還提供了錯誤分析,社會化分享,推送,即時通訊等等,當然這裡我們重點分析的是其數據統計功能。
在友盟官網中我們可以看到其對統計服務的介紹,這裡我們大概的看一下:
可以發現我們提供了用戶統計,渠道統計,頁面訪問路徑統計,點擊事件統計等等。
那麼我們如何才能繼承友盟的統計功能的,其在SDK文檔介紹中已經做了詳細介紹,大概的集成流程是下載友盟SDK jar包,然後引用,並在相應的Activity/Fragment的生命周期方法中調用相關的API。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCtfUvLrKtc/Wyv2+3c2zvMa5psTcDQo8cD621NPa0rvQqcr9vt3D9LjQtcRBcHDAtMu1v8nE3NfUvLrKtc/Wsr+31sr9vt3Ns7zGuabE3MrH0ru49rHIvc+yu7TttcTRodTxo6y1sbP1scrV39Ky1/a5/cDgy8a1xLmmxNyjrMbk1K3A7b7Nyseyzr+809HDy7XEyv2+3c2zvMbU2kFwcLTyv6q1xMqxuvLWtNDQyv2+3cnPsai5psTcoaM8L3A+DQo8cD7V4sDvvPK1pb3pydzSu8/C19S8usq1z9a1xMr9vt3Ns7zGuabE3LXEwfezzKO6PGJyIC8+DQqjqDGjqcr9vt3Ns7zGyc+xqNb30qq31s6qwb3W0Le9yr2jrM34wufH68fzyc+xqLrNzsS8/tDFz6LJz7Goo7s8YnIgLz4NCqOoMqOpzfjC58frx/PJz7Govs3Kx9axvdO199PDzfjC58frx/PI9Mfrx/PKp7Dco6zU8r2ryc+xqNDFz6Kxo7Tm1sGxvrXYzsS8/tbQo7s8YnIgLz4NCqOoM6Opsb612MnPsajOxLz+yejWw+Pa1rW6zbzkuPTKsbzko6zI9L7gwOvJz7TOyc+xqMqxvOS089Pa49rWtbvy1d/Kx87EvP6089ChtPPT2uPa1rXU8ta00NDJz7GostnX96OsyPTJz7Gos8m5ptTyyb6z/bG+tdjK/b7dzsS8/qO7PGJyIC8+DQqjqDSjqbG+tdjK/b7dzsS8/tTayc+xqNaux7DT0LzTw9y6zdG5y/Wy2df3o7s8YnIgLz4NCqOoNaOp1NpBcHC08r+qtcTKsbry1rTQ0NK7tM7K/b7dyc+xqLLZ1/ejrNTazNi2qLXEstnX98/Cv8nS1Na00NDJz7GostnX96O7PGJyIC8+DQqjqDajqcnPsaiy2df3ysfU2lNlcnZpY2W3/s7x1tDWtNDQo6yx3MPiyc+xqLLZ1/exu9PJ09q9+LPMsbvJscvAtvjW0LbPo7s8L3A+DQo8cD7X7rrzzPnJz86qwcvKtc/Wyv2+3cnPsai2+NfUtqjS5bXEyv2+3c2zvMa3/s7xo7o8L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;">
/**
* Created by aaron on 2016/4/8.
* desc:UU打點service
*/
public class UUPointService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/**
* desc:該service為APP打點service
* 主要實現兩個後台服務:
* (1)內存數據上報;
* (2)文件數據上報;
*/
if (intent != null && intent.getStringExtra(UUPoint.LOADTYPE) != null && intent.getStringExtra(UUPoint.LOADTYPE).trim().equals(UUPoint.LOADDATA)) {
if (UUPoint.writeMap.size() > 0) {
//(1)轉換數據
final List strList = new ArrayList();
Iterator> iterator = UUPoint.writeMap.entrySet().iterator();
while (iterator.hasNext()) {
StringBuffer sb = new StringBuffer();
Map.Entry entry = iterator.next();
String key = entry.getKey();
Integer count = entry.getValue();
sb.append(key).append(",").append(count);
strList.add(sb.toString());
}
if (strList.size() > 0) {
// 上傳服務器數據上傳服務器數據
SystemCommon.ReportLogBatch.Builder builder = SystemCommon.ReportLogBatch.newBuilder();
builder.addAllLogLine(strList);
SystemInterface.ReportLogInfoRequest.Builder request = SystemInterface.ReportLogInfoRequest.newBuilder();
request.setLogData(ByteString.copyFrom(GZipUtils.compress(builder.build().toByteArray())));// 壓縮數據包
NetworkTask task = new NetworkTask(CmdCodeDef.CmdCode.ReportLogInfo_VALUE);
task.setBusiData(request.build().toByteArray());
NetworkUtils.executeNetwork(task, new HttpResponse.NetWorkResponse() {
@Override
public void onSuccessResponse(UUResponseData responseData) {
if (responseData.getRet() == 0) {
try {
SystemInterface.ReportLogInfoResponse response = SystemInterface.ReportLogInfoResponse.parseFrom(responseData.getBusiData());
if (response.getRet() == 0) {
/*MLog.i("tab", "########################");
for (String str : strList) {
MLog.i("tab", str);
}*/
UUPoint.writeMap.clear();
UUPointUtils.setLastPointTime(UUPointService.this);
/*MLog.i("tab", "上報數據完成################");*/
} else {
UUPoint.saveWriteToIO(UUPointService.this);// 將寫map中的數據持久化到IO
}
} catch (Exception e) {
UUPoint.saveWriteToIO(UUPointService.this);// 將寫map中的數據持久化到IO
}
} else {
UUPoint.saveWriteToIO(UUPointService.this);// 將寫map中的數據持久化到IO
}
}
@Override
public void onError(VolleyError errorResponse) {
MLog.i("tab", "保存到本地文件");
UUPoint.saveWriteToIO(UUPointService.this);
}
@Override
public void networkFinish() {
}
});
}
}
}
// 上傳文件
else if (intent != null && intent.getStringExtra(UUPoint.LOADTYPE) != null && intent.getStringExtra(UUPoint.LOADTYPE).trim().equals(UUPoint.LOADFILE)) {
File file = new File(Config.CountFile);
List fileList = Arrays.asList(file.listFiles());
if (fileList != null && fileList.size() > 0) {
//按文件名稱排序
Collections.sort(fileList, new Comparator() {
@Override
public int compare(File lhs, File rhs) {
return rhs.getName().compareTo(lhs.getName());
}
});
// 上傳文件
for (final File files : fileList) {
// 先解密,在使用票據加密
FileEncrypter.decrypt(files, UUPoint.secretKey);// 解密
if (Config.isNetworkConnected(UUPointService.this)) {
NetworkTask networkTask = new NetworkTask(CmdCodeDef.CmdCode.ReportLogFile_VALUE);
networkTask.setUploadDataFile(true);// 上傳大點數據文件
networkTask.setBusiData(UUPointUtils.getBytesFromFile(files));
NetworkUtils.executeNetwork(networkTask, new HttpResponse.NetWorkResponse() {
@Override
public void onSuccessResponse(UUResponseData responseData) {
if (responseData.getRet() == 0) {
try {
SystemInterface.ReportLogInfoResponse response = SystemInterface.ReportLogInfoResponse.parseFrom(responseData.getBusiData());
if (response.getRet() == 0) {
// 上傳成功, 刪除加密文件
files.delete();
MLog.i("tab", "上傳文件完成" + files.getName() + "######################");
} else {
FileEncrypter.encrypt(files, UUPoint.secretKey);// 上傳失敗, 重新加密文件
}
} catch (Exception e) {
e.printStackTrace();
FileEncrypter.encrypt(files, UUPoint.secretKey);// 上傳失敗, 重新加密文件
}
} else {
FileEncrypter.encrypt(files, UUPoint.secretKey);// 上傳失敗, 重新加密文件
}
}
@Override
public void onError(VolleyError errorResponse) {
MLog.i("tab", errorResponse.toString());
FileEncrypter.encrypt(files, UUPoint.secretKey);// 上傳失敗, 重新加密文件
}
@Override
public void networkFinish() {
}
});
}
}
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
總結:
一般而言直接使用第三方統計服務就已經可以滿足絕大部分的業務需求了,當然了如果數據比較敏感也可以自己實現數據上報統計的功能。