权限管理 -1

泡在网上的日子 / 文 发表于2016-01-06 18:23 次阅读 权限

 blob.png

随着棉花糖的出现,一种新的权限模式添加到了安卓中,这也导致开发者需要对安卓权限管理采取稍微不同的方法了。在这个系列中,我们将从技术和用户体验的角度,探讨处理权限请求的方法。 

一般而言app权限分为两种情况:一种是app核心功能所需的权限,没有这个权限都不能正常运行;一种是次要功能所需的权限。比如,对于一个相机app来说,CAMERA权限就是核心功能的一部分,一个不能拍照的相机应用完全就是无用的。但是也存在一些额外的功能,没有它app还是可以使用,比如为相片标注位置,这是一个不错的功能,需要ACCESS_FINE_LOCATION权限,但也并不是没有它app就不能操作了。

同样,我们准备在下一个系列文章中着手一个app,但是因为某些用处它需要两个权限:RECORD_AUDIO 和 MODIFY_AUDIO_SETTINGS。为了获取这些权限,我们需要像通常那样在Manifest中声明它们:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  package="com.stylingandroid.permissions">

  <uses-permission android:name="android.permission.RECORD_AUDIO" />
  <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

  <application
    android:allowBackup="false"
    android:fullBackupContent="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme.NoActionBar"
    tools:ignore="GoogleAppIndexingWarning">

    <activity android:name=".MainActivity" />

    <activity
      android:name=".PermissionsActivity"
      android:label="@string/title_activity_permissions"
      android:theme="@style/AppTheme.NoActionBar">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>

</manifest>

 

这是至api 1之后在安卓上声明权限的标准方法。但是,一旦我们指定targetSdkVersion为23或者之后我们还需要在运行时请求这些所需的权限。这很重要,因为已经出现了很多开发者把targetSdkVersion飙到了最新,然后发现自己的app疯狂的崩溃,这是由于他们没有实现执行运行时权限请求的代码。当你已经把一个targeting API 为23或者之后的app发布到了Google Play上,这更是一个问题,你无法立即把那个apk的targeting API替换成更早的版本。

这里需要指出的是,目前已经有几个用来简化运行时权限请求过程的库。它们的质量和用处各异,但是我觉得在使用这些库之前,理解背后的过程还是相当重要的,否则可能因为你不了解自己所用的库到底做了什么而遇到问题。这也是这个系列文章的主要写作动机。

我们需要的两个权限刚好落在了两种权限中:RECORD_AUDIO 被视为敏感权限,而 MODIFY_AUDIO_SETTINGS被视为普通权限。一个敏感权限就是一个可能危及隐私和安全的权限;而普通权限则是为了获取app域之外的资源,但是对用户隐私只有很少或者没有风险。普通权限系统自动授权,而敏感权限则需要在运行时让用户明确授予。

在这个过程中,我们需要做的第一件事就是判断我们是都被授予了相关权限。在 API 23中,为了检查某个特定的权限是否已经被授权,Context中添加了几个新的方法。但是,为了避免自己写API-level 检查,最好使用ContextCompat而不是直接使用Context:

class PermissionsChecker {
    private final Context context;

    public PermissionsChecker(Context context) {
        this.context = context;
    }

    public boolean lacksPermissions(String... permissions) {
        for (String permission : permissions) {
            if (lacksPermission(permission)) {
                return true;
            }
        }
        return false;
    }

    private boolean lacksPermission(String permission) {
        return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED;
    }

}

 

这段代码其实很简单-ContextCompat的checkSelfPermission方法顾名思义就是检查权限的意思,它返回 PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。其余的代码是这个app所需的,用于检查所需的某个权限是否还未被授权。

这里还得唠叨几句ContextCompat为我们做了的事情。当运行在不支持运行时权限模式的Marshmallow以前的设备上的时候,checkSelfPermission()方法总是会返回 PackageManger.PERMISSION_GRANTED   -  老的系统版本上总是隐式的授予权限。因此我们跨系统版本也只需一个方法调用,也不用去写什么检查API-level 的代码。

你可能会好奇为什么为了这个专门写了个类,主要是后面所有的Activity中都要做这个检查,所以把这个检查的逻辑独立出来,减少重复,提高代码的可维护性。

要早在Activity中实际使用它,我们只需传入activity所需的权限列表:

public class MainActivity extends AppCompatActivity {
    private static final String[] PERMISSIONS = new String[] {Manifest.permission.RECORD_AUDIO, Manifest.permission.MODIFY_AUDIO_SETTINGS};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        PermissionsChecker checker = new PermissionsChecker(this);

        if (checker.lacksPermissions(PERMISSIONS)) {
            Snackbar.make(toolbar, R.string.no_permissions, Snackbar.LENGTH_INDEFINITE).show();
        }
    .
    .
    .
    }
}

简单吧。 

在 pre-Marshamllow的设备上正常工作:

blob.png

但是我们还没有为Marshmallow和之后的设备做任何处理 - 我们只是显示一个Snackbar而已:

blob.png

对于特殊权限的请求是更复杂的东西。我们将在下篇文章探讨。

本文的源代码在 这里

作者Mark Allison。本文最初发表在 Styling Android

英文原文:https://blog.stylingandroid.com/permissions-part-1/ 

收藏 赞 (9) 踩 (0)
上一篇:Android开发常用的adb命令整理
adb的全称是 Android Debug Bridge adb start-server 启动adb服务,如果它没启动的话 adb kill-server 关闭服务 adb devices 查看所连接的设备以及设备所对应的序列号 adb install -r xxxx.apk 安装app,需要注意的是如果连接了两台设备,则会报错,此时可以添加
下一篇:Android开发者应该知道的Kotlin
Android开发者在语言限制方面面临着一个困境。众所周知,目前的Android开发只支持Java 6(语言本身从Java 7开始进行了一些改进),因此我们每天只能使用一种古老的语言来进行开发,这极大地降低了我们的生产力,同时也迫使我们不得不编写大量的样板与脆弱的