如有转载,请申明:
转载至 http://blog.csdn.net/qq_35064774/article/details/52950674
安卓6.0给权限进行了分类,所以就出现了运行时权限。运行时权限需要在代码中申请。
这里我收集了一份 Android 6.0的运行时权限。
如果你的App涉及的运行时权限很少,可以考虑在需要使用的时候再申请,如果申请成功,就运行相应的代码,申请失败就给出提示。
以下是申请权限的流程。
// check whether has specific permission
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_CONTACTS)
== PackageManager.PERMISSION_GRANTED) {
// has permission or no need permission
} else {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
// result callback
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
}
}
这个用起来有点麻烦,不过幸好,现在同一组权限只要任意授权一个,同组其他的权限就不用申请了。
不过这api用着还是有点繁琐,主要是整个申请过程中有3个逻辑分支,这样就容易导致逻辑混乱。
幸运的是,已经有很多好心人帮我们把这些麻烦事封装起来了。你完全可以在github上搜索permission
,然后选择java进行筛选。
我这里推荐两个比较好用的库。
PermissionsDispatcher 使用注解的方式申请权限。
PermissionHelper 封装了api,方便申请和回调判断,此外,作者还特地封装了一个漂亮的Activity界面用来统一申请所有权限。
从安卓4.4开始,将不再支持非默认短信对短信数据库的写操作。
也就是意味着如果你想写短信的数据库,就必须先申请成为系统默认的短信App。
官方是这样说明的,你可以在写短信前申请成为默认短信APP,然后写完后,把默认短信App改回去。当然,修改需要经过用户的许可。
详情可以看这里 Explicitly saving new messages to inbox。
和上一条一样,从安卓4.4开始,短信方面变化很大,我们已经不能通过简单的一行代码abortBroadcast();
来拦截短信了。
同样只有默认的短信App才能实现拦截。
详情请看这里Abort SMS Intent on Android KitKat
在安卓5.0之前,我们可以通过getRunningTasks
来获取当前运行的App。
List infos = am.getRunningTasks(1);
String packageName = infos.get(0).topActivity.getPackageName();
而在5.0时,该api被废弃了。取而代之的是UsageStatsManager
。
但是要使用它来获取当前运行的App还需要相应的权限。
这个权限是系统App才能用的,所以需要忽略保护性权限的错误。
配置好权限后,还需要向系统申请查看App使用情况的权限。
如果系统版本大于或等于5.0,并且没有获得查看App使用情况的权限,就通过意图去申请权限。具体代码如下:
// request the permission to get top task package name
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !hasGetUsageStatsPermission()) {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
/**
* check whether has permission to get usage stats
* @return true if have, false otherwise
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private boolean hasGetUsageStatsPermission() {
AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
int mode = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
}
return mode == AppOpsManager.MODE_ALLOWED;
}
有了权限之后,就可以调用UsageStatsManager
来查看当前运行的App了。
/**
* get current task top app package name
* @param am
* @return the top app package name
*/
private String getTaskTopAppPackageName(ActivityManager am) {
String packageName = "";
// if the sdk > 20. It can only use getRunningAppProcesses to get task top package name
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager usage = (UsageStatsManager)getSystemService(USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);
if (stats != null) {
SortedMap runningTask = new TreeMap();
for (UsageStats usageStats : stats) {
runningTask.put(usageStats.getLastTimeUsed(), usageStats);
}
if (runningTask.isEmpty()) {
return null;
}
packageName = runningTask.get(runningTask.lastKey()).getPackageName();
}
} else {// if sdk <= 20, can use getRunningTasks
List infos = am.getRunningTasks(1);
packageName = infos.get(0).topActivity.getPackageName();
}
return packageName;
}
在安卓5.0之前,可以通过am.getRunningAppProcesses();
获取所有运行的app信息。
从安卓5.0开始,这个方法只能返回自身app的信息。
不过上有政策下有对策,有大神通过读取proc
文件的方法来获得运行中的App列表。这位大神已经把库开源了。
详情点这里AndroidProcesses。
安卓6.0之前,可以通过反射调用PackageManager
的freeStorageAndNotify
方法来清理所有App的缓存。
但从6.0开始,这个方法被移除了。暂时没有找到替代的方案。