關鍵字: 應用統計 Android源碼 應用使用時長 應用使用次數
最近在做有關于應用統計有關的工作,主要是統計系統中客戶端應用(非系統自帶的那些基礎應用,比如DownLoadManager),在每一天的使用情況,統計內容包括:應用打開次數,應用合計使用時長等。
在所搜尋的方案中,大致有如下兩種:
方案一:自行記錄每次activity的打開和關閉,根據這些數據進行統計。
方案二:使用系統自行記錄的每次activity的打開和關閉數據,進行統計。
以下方案采用兩個方案并行,主要是以系統數據統計結果為主,以自行記錄的數據作為參照,用以對比兩組數據,以保證數據統計結果的有效性和穩定性。
系統數據
在Android中,系統會自行記錄應用的打開次數和使用時間,且提供了相關api于開發者,但是每一次版本提升都可能會對api帶來相當大的改變,這一塊也不例外。但是始終沒有變化的就是在撥號鍵盤輸入* # * #4636# * #*,進入工程模式,點擊“使用情況統計數據”,你就可以看到統計界面了。由于各個版本之間差異比較大,而且相關的資料也比較少,本次使用的api以及相關的說明都是以Android-5.1為基礎。在某些版本中,應用統計api,存在不少缺陷以及避坑的地方,尤其是手機廠家修改過源碼之后,所以對于某些品牌的測試機器,程序的運行結果會有一點不一樣,請各位讀者有所注意。
如何獲取系統數據
第一步:獲取權限
在manifest文件中注冊該權限
在系統setting應用中打開相應開關,準許demo應用獲取數據。如果不執行這一步的話,demo將無法讀取系統數據。
測試機 : 小米4C。
打開目錄 : 設置 -〉其他高級設置 -〉安全和隱私 -〉有權查看使用情況的應用。界面如下圖:
第二步:獲取數據
獲取系統統計信息:
@SuppressWarnings("ResourceType")
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static ArrayList getUsageList(Context context, long startTime, long endTime) {
Log.i(TAG," EventUtils-getUsageList() Range start:" + startTime);
Log.i(TAG," EventUtils-getUsageList() Range end:" + endTime);
Log.i(TAG," EventUtils-getUsageList() Range start:" + dateFormat.format(startTime));
Log.i(TAG," EventUtils-getUsageList() Range end:" + dateFormat.format(endTime));
ArrayList list = new ArrayList<>();
UsageStatsManager mUsmManager = (UsageStatsManager) context.getSystemService("usagestats");
Map map = mUsmManager.queryAndAggregateUsageStats(startTime, endTime);
for (Map.Entry entry : map.entrySet()) {
UsageStats stats = entry.getValue();
if(stats.getTotalTimeInForeground() > 0){
list.add(stats);
Log.i(TAG," EventUtils-getUsageList() stats:" + stats.getPackageName() + " TotalTimeInForeground = " + stats.getTotalTimeInForeground());
}
}
return list;
}
獲取系統記錄的詳細的各個activity的使用情況:
@SuppressWarnings("ResourceType")
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static ArrayList getEventList(Context context, long startTime, long endTime){
ArrayList mEventList = new ArrayList<>();
Log.i(TAG," EventUtils-getEventList() Range start:" + startTime);
Log.i(TAG," EventUtils-getEventList() Range end:" +endTime);
Log.i(TAG," EventUtils-getEventList() Range start:" + dateFormat.format(startTime));
Log.i(TAG," EventUtils-getEventList() Range end:" + dateFormat.format(endTime));
UsageStatsManager mUsmManager = (UsageStatsManager) context.getSystemService("usagestats");
UsageEvents events = mUsmManager.queryEvents(startTime, endTime);
while (events.hasNextEvent()) {
UsageEvents.Event e = new UsageEvents.Event();
events.getNextEvent(e);
if (e != null && (e.getEventType() == 1 || e.getEventType() == 2)) {
Log.i(TAG," EventUtils-getEventList() "+e.getTimeStamp()+" event:" + e.getClassName() + " type = " + e.getEventType());
mEventList.add(e);
}
}
return mEventList;
}
獲取系統記錄的各個應用的使用次數:
由于該字段不能通過api拿到,故而采取反射的形式,拿到該字段。(注:其實該字段的統計數據并不可靠,一旦強行關機,比如拔電池,就可能失去數據,所以在系統代碼中該字段是被隱藏的。當然關于數據的可靠性,在接下來的文章中會有更詳細的說明)
private int getLaunchCount(UsageStats usageStats) throws IllegalAccessException {
Field field = null;
try {
field = usageStats.getClass().getDeclaredField("mLaunchCount");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return (int) field.get(usageStats);
}
結語:
本文主要介紹了關于Android系統中統計各個app的使用情況的解決方案,以及獲取相關數據的方法。關于系統記錄的數據的原理以及在該原理的邏輯下可能出現的bug,將會在接下來的文章中詳細闡述。
轉載請注明出處。