- 本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家發(fā)布
什么是使用記錄訪問權限呢委乌?這是在Android5.0(Api level 21)新添加的,通過該權限我們可以查看設備上其它應用使用情況的統計信息等诺舔。
如何使用該權限呢玉锌?
首先在manifest中添加:
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
由于該權限默認只授予系統應用技羔,所以添加了ignore
屬性蚀同。
然后通過如下代碼進而手動打開權限:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivityForResult(intent);
當然只要我們在manifest中進行了權限配置,也可以通過設置->安全->有權查看使用情況的應用來打開權限:
到此我們的應用就擁有了該權限读跷。那么有了這個權限到底能做什么呢梗搅?繼續(xù)往下看......
前段時間和同事聊到了一個叫我要當學霸的app,里邊有個學習監(jiān)督的功能效览,就需要使用記錄訪問權限无切,當打開權限后,除了自己和桌面外丐枉,其它app都不能正常使用哆键,點擊其它app時會直接退到后臺并彈出一個提示頁面。不妨我們來模擬下這個功能瘦锹。
在這之前我們首先看一個類UsageStatsManager:
public final class UsageStatsManager {
public static final int INTERVAL_BEST = 4; //根據提供的開始籍嘹、結束時間決定時間間隔
public static final int INTERVAL_DAILY = 0; //以天為時間間隔(最長7天)
public static final int INTERVAL_MONTHLY = 2; //以月為時間間隔(最長6個月)
public static final int INTERVAL_WEEKLY = 1; //以周為時間間隔(最長4個星期)
public static final int INTERVAL_YEARLY = 3; //以年為時間間隔(最長2年)
UsageStatsManager() {
throw new RuntimeException("Stub!");
}
public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) {
throw new RuntimeException("Stub!");
}
public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime, long endTime) {
throw new RuntimeException("Stub!");
}
public UsageEvents queryEvents(long beginTime, long endTime) {
throw new RuntimeException("Stub!");
}
public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
throw new RuntimeException("Stub!");
}
public boolean isAppInactive(String packageName) {
throw new RuntimeException("Stub!");
}
}
可以看到該類提供了五種時間間隔類型,這里我們比較關注queryUsageStats()
方法弯院,通過該方法我們可以得到一段時間內 其它應用的使用情況辱士。
我們實現思路是這樣的,通過UsageStatsManager類獲得2秒內手機app的使用數據抽兆,找到時間最近的一個识补,如果不是我們自己的app或桌面則模擬home鍵點擊,同時彈出一個提示頁面辫红,具體的代碼如下:
private void getTopApp() {
UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);//usagestats
long time = System.currentTimeMillis();
List<UsageStats> usageStatsList = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, time - 2000, time);
if (usageStatsList != null && !usageStatsList.isEmpty()) {
SortedMap<Long, UsageStats> usageStatsMap = new TreeMap<>();
for (UsageStats usageStats : usageStatsList) {
usageStatsMap.put(usageStats.getLastTimeUsed(), usageStats);
}
if (!usageStatsMap.isEmpty()) {
String topPackageName = usageStatsMap.get(usageStatsMap.lastKey()).getPackageName();
if (getLauncherPackageName(mContext).equals(topPackageName) || "com.othershe.test".equals(topPackageName)) {
return;
}
Log.e("TopPackage Name", topPackageName);
//模擬home鍵點擊
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
//啟動提示頁面
Intent intent1 = new Intent(mContext, TipActivity.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent1);
}
}
}
因為時間周期是2秒凭涂,所以這里我們采用INTERVAL_BEST作為時間間隔。其中的UsageStats對象對應一個查詢到的app數據贴妻,主要包含以下信息:
getTopApp()是我們的核心方法切油,當然我們需要開啟一個服務,然后在服務中每隔500毫秒執(zhí)行一次上邊的方法名惩,這樣就能起到不斷檢測的作用:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mTimer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
getTopApp();
}
};
mTimer.schedule(task, 1000, 500);
return super.onStartCommand(intent, flags, startId);
}
打開權限澎胡、啟動服務,可以看到實際的運行效果如下娩鹉,基本符合我們的預期攻谁。
類似的道理,我們也可以判斷摸個app是否在前臺運行弯予。
上邊我們使用了**INTERVAL_BEST **時間間隔類型戚宦,還可以使用其它4中,例如使用INTERVAL_YEARLY:
private void getHistoryApps() {
Calendar calendar = Calendar.getInstance();
long endTime = calendar.getTimeInMillis();
calendar.add(Calendar.YEAR, -1);
long startTime = calendar.getTimeInMillis();
UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
List<UsageStats> usageStatsList = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, startTime, endTime);
if (usageStatsList != null && !usageStatsList.isEmpty()) {
HashSet<String> set = new HashSet<>();
for (UsageStats usageStats : usageStatsList) {
set.add(usageStats.getPackageName());
}
if (!set.isEmpty()) {
Log.e("size", set.size() + "");
}
}
}
上邊的代碼我們最終獲得了過去一年手機上使用過的app的包名集合(其中包括系統級別的):
拿到這些包名可以做什么呢锈嫩?
其實對于網賺類型的應用有這樣一種業(yè)務場景受楼,就是用戶通過下載app來做任務進而賺取收益垦搬,但是如果當前設備通過其它網賺應用已經下載過某個app,然后卸載了艳汽,再通過你的網賺應用下載猴贰。如果你不知道用戶之前安裝過該app,就需要給用戶結算相應的收益河狐,但是你的上游渠道是不會給你結算的米绕,因為這屬于同一設備上的重復下載,這樣對公司而言就是虧損的馋艺。
有了歷史包名信息义郑,我們就可以判斷用戶在一定的時間周期內是否安裝過對應的app,進而采取相應的策略丈钙,這樣可以在一定程度降低損失。當然有個前提交汤,你要友好的引導用戶開啟權限雏赦。
先到這里吧,更多的用法還有待進一步探究芙扎。