Android高版本适配总结1

版权声明:本文为 宇不语 原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35064774/article/details/52950674


如有转载,请申明:
转载至 http://blog.csdn.net/qq_35064774/article/details/52950674


目录

  1. 权限适配
  2. 写短信操作适配
  3. 拦截短信操作适配
  4. 查看App使用情况适配
  5. 获取所有运行的App
  6. 清除App缓存

权限适配(安卓6.0 API api23)

安卓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 api19)

从安卓4.4开始,将不再支持非默认短信对短信数据库的写操作。
也就是意味着如果你想写短信的数据库,就必须先申请成为系统默认的短信App。
官方是这样说明的,你可以在写短信前申请成为默认短信APP,然后写完后,把默认短信App改回去。当然,修改需要经过用户的许可。
详情可以看这里 Explicitly saving new messages to inbox

拦截短信操作适配(安卓4.4 api19)

和上一条一样,从安卓4.4开始,短信方面变化很大,我们已经不能通过简单的一行代码abortBroadcast();来拦截短信了。
同样只有默认的短信App才能实现拦截。
详情请看这里Abort SMS Intent on Android KitKat

查看App使用情况适配(安卓5.0 api21)

在安卓5.0之前,我们可以通过getRunningTasks来获取当前运行的App。

List<ActivityManager.RunningTaskInfo> infos = am.getRunningTasks(1);
String packageName = infos.get(0).topActivity.getPackageName();

而在5.0时,该api被废弃了。取而代之的是UsageStatsManager
但是要使用它来获取当前运行的App还需要相应的权限。

<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />

这个权限是系统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<UsageStats> stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);
        if (stats != null) {
            SortedMap<Long, UsageStats> runningTask = new TreeMap<Long,UsageStats>();
            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<ActivityManager.RunningTaskInfo> infos = am.getRunningTasks(1);
        packageName = infos.get(0).topActivity.getPackageName();
    }
    return packageName;
}

获取所有运行的App(安卓5.0 api21)

在安卓5.0之前,可以通过am.getRunningAppProcesses();获取所有运行的app信息。
从安卓5.0开始,这个方法只能返回自身app的信息。
不过上有政策下有对策,有大神通过读取proc文件的方法来获得运行中的App列表。这位大神已经把库开源了。
详情点这里AndroidProcesses

清除App缓存(安卓6.0 api23)

安卓6.0之前,可以通过反射调用PackageManagerfreeStorageAndNotify方法来清理所有App的缓存。
但从6.0开始,这个方法被移除了。暂时没有找到替代的方案。

猜你喜欢

转载自blog.csdn.net/qq_35064774/article/details/52950674