运行时权限管理

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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所需的权限列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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/ 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值