Android 6.0 运行时权限处理完全解析

转载请标明出处: 
http://blog.csdn.net/lmj623565791/article/details/50709663; 
本文出自:【张鸿洋的博客】

一、概述

随着Android 6.0发布以及普及,我们开发者所要应对的主要就是新版本SDK带来的一些变化,首先关注的就是权限机制的变化。对于6.0的几个主要的变化,查看查看官网的这篇文章http://developer.android.com/intl/zh-cn/about/versions/marshmallow/android-6.0-changes.html,其中当然包含Runtime Permissions

ok,本篇文章目的之一就是对运行时权限处理的一个介绍,以及对目前权限相关的库的一些了解。

当然非常推荐阅读官网权限相关文章:

本文也是在上述文章基础上理解、实验以及封装。

二、运行时权限的变化及特点

对于6.0以下的权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装,造成了我们想要使用某个app,就要默默忍受其一些不必要的权限(比如是个app都要访问通讯录、短信等)。而在6.0以后,我们可以直接安装,当app需要我们授予不恰当的权限的时候,我们可以予以拒绝(比如:单机的象棋对战,请求访问任何权限,我都是不同意的)。当然你也可以在设置界面对每个app的权限进行查看,以及对单个权限进行授权或者解除授权。

新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。

  • Normal Permissions如下
ACCESS_LOCATION_EXTRA_COMMANDS ACCESS_NETWORK_STATE ACCESS_NOTIFICATION_POLICY ACCESS_WIFI_STATE BLUETOOTH BLUETOOTH_ADMIN BROADCAST_STICKY CHANGE_NETWORK_STATE CHANGE_WIFI_MULTICAST_STATE CHANGE_WIFI_STATE DISABLE_KEYGUARD EXPAND_STATUS_BAR GET_PACKAGE_SIZE INSTALL_SHORTCUT INTERNET KILL_BACKGROUND_PROCESSES MODIFY_AUDIO_SETTINGS NFC READ_SYNC_SETTINGS READ_SYNC_STATS RECEIVE_BOOT_COMPLETED REORDER_TASKS REQUEST_INSTALL_PACKAGES SET_ALARM SET_TIME_ZONE SET_WALLPAPER SET_WALLPAPER_HINTS TRANSMIT_IR UNINSTALL_SHORTCUT USE_FINGERPRINT VIBRATE WAKE_LOCK WRITE_SYNC_SETTINGS
  • 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
  • 33
  • 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
  • 33
  • Dangerous Permissions:
group:android.permission-group.CONTACTS   permission:android.permission.WRITE_CONTACTS   permission:android.permission.GET_ACCOUNTS   permission:android.permission.READ_CONTACTS  group:android.permission-group.PHONE   permission:android.permission.READ_CALL_LOG   permission:android.permission.READ_PHONE_STATE   permission:android.permission.CALL_PHONE   permission:android.permission.WRITE_CALL_LOG   permission:android.permission.USE_SIP   permission:android.permission.PROCESS_OUTGOING_CALLS   permission:com.android.voicemail.permission.ADD_VOICEMAIL  group:android.permission-group.CALENDAR   permission:android.permission.READ_CALENDAR   permission:android.permission.WRITE_CALENDAR  group:android.permission-group.CAMERA   permission:android.permission.CAMERA  group:android.permission-group.SENSORS   permission:android.permission.BODY_SENSORS  group:android.permission-group.LOCATION   permission:android.permission.ACCESS_FINE_LOCATION   permission:android.permission.ACCESS_COARSE_LOCATION  group:android.permission-group.STORAGE   permission:android.permission.READ_EXTERNAL_STORAGE   permission:android.permission.WRITE_EXTERNAL_STORAGE  group:android.permission-group.MICROPHONE   permission:android.permission.RECORD_AUDIO  group:android.permission-group.SMS   permission:android.permission.READ_SMS   permission:android.permission.RECEIVE_WAP_PUSH   permission:android.permission.RECEIVE_MMS   permission:android.permission.RECEIVE_SMS   permission:android.permission.SEND_SMS   permission:android.permission.READ_CELL_BROADCASTS
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

可以通过adb shell pm list permissions -d -g进行查看。

看到上面的dangerous permissions,会发现一个问题,好像危险权限都是一组一组的,恩,没错,的确是这样的,

那么有个问题:分组对我们的权限机制有什么影响吗?

的确是有影响的,如果app运行在Android 6.x的机器上,对于授权机制是这样的。如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。

不过需要注意的是,不要对权限组过多的依赖,尽可能对每个危险权限都进行正常流程的申请,因为在后期的版本中这个权限组可能会产生变化。

三、相关API

好在运行时相关的API也比较简单,所以适配起来并不会非常痛苦。

API的讲解就跟着申请权限步骤一起了:

  1. 在AndroidManifest文件中添加需要的权限。

    这个步骤和我们之前的开发并没有什么变化,试图去申请一个没有声明的权限可能会导致程序崩溃。

  2. 检查权限

    if (ContextCompat.checkSelfPermission(thisActivity,                 Manifest.permission.READ_CONTACTS)         != PackageManager.PERMISSION_GRANTED) { }else{     // }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里涉及到一个API,ContextCompat.checkSelfPermission,主要用于检测某个权限是否已经被授予,方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。当返回DENIED就需要进行申请授权了。

  3. 申请授权

     ActivityCompat.requestPermissions(thisActivity,                 new String[]{Manifest.permission.READ_CONTACTS},                 MY_PERMISSIONS_REQUEST_READ_CONTACTS);
    • 1
    • 2
    • 3
    • 1
    • 2
    • 3

    该方法是异步的,第一个参数是Context;第二个参数是需要申请的权限的字符串数组;第三个参数为requestCode,主要用于回调的时候检测。可以从方法名requestPermissions以及第二个参数看出,是支持一次性申请多个权限的,系统会通过对话框逐一询问用户是否授权。

  4. 处理权限申请回调

    @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;         }     } } 
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ok,对于权限的申请结果,首先验证requestCode定位到你的申请,然后验证grantResults对应于申请的结果,这里的数组对应于申请时的第二个权限字符串数组。如果你同时申请两个权限,那么grantResults的length就为2,分别记录你两个权限的申请结果。如果申请成功,就可以做你的事情了~

当然,到此我们的权限申请的不走,基本介绍就如上述。不过还有个API值得提一下:

// 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.  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这个API主要用于给用户一个申请权限的解释,该方法只有在用户在上一次已经拒绝过你的这个权限申请。也就是说,用户已经拒绝一次了,你又弹个授权框,你需要给用户一个解释,为什么要授权,则使用该方法。

那么将上述几个步骤结合到一起就是:

// Here, thisActivity is the current activity if (ContextCompat.checkSelfPermission(thisActivity,                 Manifest.permission.READ_CONTACTS)         != PackageManager.PERMISSION_GRANTED) {      // 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.     } }
  • 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
  • 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

四、简单的例子

这里写一个简单的例子,针对于运行时权限。相信大家在最开始接触Android的时候,都利用Intent实验了打电话、发短信等功能。

我们看看直接拨打电话在Android 6.x的设备上权限需要如何处理。

当然代码非常简单:

package com.zhy.android160217;  import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Toast;  public class MainActivity extends AppCompatActivity {      private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1;      @Override     protected void onCreate(Bundle savedInstanceState)     {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);     }      public void testCall(View view)     {         if (ContextCompat.checkSelfPermission(this,                 Manifest.permission.CALL_PHONE)                 != PackageManager.PERMISSION_GRANTED)         {              ActivityCompat.requestPermissions(this,                     new String[]{Manifest.permission.CALL_PHONE},                     MY_PERMISSIONS_REQUEST_CALL_PHONE);         } else         {             callPhone();         }     }      public void callPhone()     {         Intent intent = new Intent(Intent.ACTION_CALL);         Uri data = Uri.parse("tel:" + "10086");         intent.setData(data);         startActivity(intent);     }      @Override     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)     {          if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE)         {             if (grantResults[0] == PackageManager.PERMISSION_GRANTED)             {                 callPhone();             } else             {                 // Permission Denied                 Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();             }             return;         }         super.onRequestPermissionsResult(requestCode, permissions, grantResults);     } } 
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

在Android 6.x上运行是,点击testCall,即会弹出授权窗口,如何你Allow则直接拨打电话,如果Denied则Toast弹出”Permission Denied”。

例子很简单,不过需要注意的是,对于Intent这种方式,很多情况下是不需要授权的甚至权限都不需要的,比如:你是到拨号界面而不是直接拨打电话,就不需要去申请权限;打开系统图库去选择照片;调用系统相机app去牌照等。更多请参考Consider Using an Intent 
.

当然,上例也说明了并非所有的通过Intent的方式都不需要申请权限。一般情况下,你是通过Intent打开另一个app,让用户通过该app去做一些事情,你只关注结果(onActivityResult),那么权限是不需要你处理的,而是由打开的app去处理。

五、封装

(1)申请权限

虽然权限处理并不复杂,但是需要编写很多重复的代码,所以目前也有很多库对用法进行了封装,大家可以在github首页搜索:android permission,对比了几个库的使用方式,发现https://github.com/lovedise/PermissionGen这个库据我所见相比较而言使用算是比较简单的,那么就以这个库的源码为基础来讲解,大家有兴趣可以多看几个库的源码。

封装的代码很简单,正如大家的对上面的权限代码所见,没有特别复杂的地方。

对于申请权限的代码,原本的编写为:

if (ContextCompat.checkSelfPermission(this,                 Manifest.permission.CALL_PHONE)                 != PackageManager.PERMISSION_GRANTED) {      ActivityCompat.requestPermissions(this,             new String[]{Manifest.permission.CALL_PHONE},             MY_PERMISSIONS_REQUEST_CALL_PHONE); } else {     callPhone(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

大家可以看到,对于其他的权限,其实申请的逻辑是类似的;唯一不同的肯定就是参数,那么看上面的代码,我们需要3个参数:Activity|Fragment权限字符串数组int型申请码

也就是说,我们只需要写个方法,接受这几个参数即可,然后逻辑是统一的。

public static void needPermission(Fragment fragment, int requestCode, String[] permissions) {     requestPermissions(fragment, requestCode, permissions); }  @TargetApi(value = Build.VERSION_CODES.M) private static void requestPermissions(Object object, int requestCode, String[] permissions) {     if (!Utils.isOverMarshmallow())     {         doExecuteSuccess(object, requestCode);         return;     }     List<String> deniedPermissions = Utils.findDeniedPermissions(getActivity(object), permissions);      if (deniedPermissions.size() > 0)     {         if (object instanceof Activity)         {             ((Activity) object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);         } else if (object instanceof Fragment)         {             ((Fragment) object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);         } else         {             throw new IllegalArgumentException(object.getClass().getName() + " is not supported");         }      } else     {         doExecuteSuccess(object, requestCode);     } }
  • 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
  • 33
  • 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
  • 33

Utils.findDeniedPermissions其实就是check没有授权的权限。

#Utils @TargetApi(value = Build.VERSION_CODES.M) public static List<String> findDeniedPermissions(Activity activity, String... permission) {     List<String> denyPermissions = new ArrayList<>();     for (String value : permission)     {         if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED)         {             denyPermissions.add(value);         }     }     return denyPermissions; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

那么上述的逻辑就很清晰了,需要的3种参数传入,先去除已经申请的权限,然后开始申请权限。

ok,我相信上面代码,大家扫一眼就可以了解了。

(2)处理权限回调

对于回调,因为要根据是否授权去执行不同的事情,所以很多框架也需要些一连串的代码,或者和前面的申请代码耦合。不过这个框架还是比较方便的,也是我选择它来讲解的原因。

回调主要做的事情:

  1. 了解是否授权成功。
  2. 根据授权情况进行回调。

对于第一条逻辑都一样;对于第二条,因为涉及到两个分支,每个分支执行不同的方法。

对于第二条,很多框架选择将两个分支的方法在申请权限的时候进行注册,然后在回调中根据requestCode进行匹配执行,不过这样需要在针对每次申请进行对象管理。

不过这个框架采取了一种很有意思的做法,它利用注解去确定需要执行的方法,存在两个注解:

@PermissionSuccess(requestCode = 100) @PermissionFail(requestCode = 100)
  • 1
  • 2
  • 1
  • 2

利用反射根据授权情况+requestCode即可找到注解标注的方法,然后直接执行即可。

大致的代码为:

@Override public void onRequestPermissionsResult(int requestCode, String[] permissions,       int[] grantResults) {     PermissionGen.onRequestPermissionsResult(this, requestCode, permissions, grantResults); }  private static void requestResult(Object obj, int requestCode, String[] permissions,                                   int[] grantResults) {     List<String> deniedPermissions = new ArrayList<>();     for (int i = 0; i < grantResults.length; i++)     {         if (grantResults[i] != PackageManager.PERMISSION_GRANTED)         {             deniedPermissions.add(permissions[i]);         }     }      if (deniedPermissions.size() > 0)     {         doExecuteFail(obj, requestCode);     } else     {         doExecuteSuccess(obj, requestCode);     } }
  • 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
  • 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

首先根据grantResults进行判断成功还是失败,对于成功则:

private static void doExecuteSuccess(Object activity, int requestCode) {     Method executeMethod = Utils.findMethodWithRequestCode(activity.getClass(),             PermissionSuccess.class, requestCode);      executeMethod(activity, executeMethod); }  #Utils public static <A extends Annotation> Method findMethodWithRequestCode(Class clazz,  Class<A> annotation, int requestCode) {     for (Method method : clazz.getDeclaredMethods())     {         if (method.isAnnotationPresent(annotation))         {             if (isEqualRequestCodeFromAnntation(method, annotation, requestCode))             {                 return method;             }         }     }     return null; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

根据注解和requestCode找到方法,然后反射执行即可。失败的逻辑类似,不贴代码了。

ok,到此我们的运行时权限相对于早起版本的变化、特点、以及如何处理和封装都介绍完了。

不过对于上面讲解的库,肯定有人会说:运行时反射会影响效率,没错,不过我已经在上述代码的基础上将运行时注解改成Annotation Processor的方式了,即编译时注解,这样的话,就不存在反射损失效率的问题了。本来准备fork修改,然后PR,结果写完,改动太大,估计PR是不可能通过了,所以另起项目了,也方便后面的做一些扩展和维护。

详见库:https://github.com/hongyangAndroid/MPermissions.

六、MPermissions用法

对外的接口和PermissionGen基本一致,因为申请只需要三个参数,抛弃了使用原本类库的单例的方式,直接一个几个静态方法,简单整洁暴力。

贴一个用法:

public class MainActivity extends AppCompatActivity {      private Button mBtnSdcard;     private static final int REQUECT_CODE_SDCARD = 2;      @Override     protected void onCreate(Bundle savedInstanceState)     {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          mBtnSdcard = (Button) findViewById(R.id.id_btn_sdcard);         mBtnSdcard.setOnClickListener(new View.OnClickListener()         {             @Override             public void onClick(View v)             {                 MPermissions.requestPermissions(MainActivity.this, REQUECT_CODE_SDCARD, Manifest.permission.WRITE_EXTERNAL_STORAGE);             }         });     }      @Override     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)     {         MPermissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);         super.onRequestPermissionsResult(requestCode, permissions, grantResults);     }       @PermissionGrant(REQUECT_CODE_SDCARD)     public void requestSdcardSuccess()     {         Toast.makeText(this, "GRANT ACCESS SDCARD!", Toast.LENGTH_SHORT).show();     }      @PermissionDenied(REQUECT_CODE_SDCARD)     public void requestSdcardFailed()     {         Toast.makeText(this, "DENY ACCESS SDCARD!", Toast.LENGTH_SHORT).show();     } }
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

是不是简单明了~~对于onRequestPermissionsResult所有的Activity都是一致的,所以可以放到BaseActivity中去。此外,在Fragment中使用的方式一致,详见demo。

详见库:https://github.com/hongyangAndroid/MPermissions.

至于为什么不直接介绍MPermission的源码,因为主要涉及到Annotation Processor,所以以这种方式引出,后面考虑单篇博文介绍下我目前所会的编译时注解的相关做法以及API的使用。

转载于:https://www.cnblogs.com/gccBlog/p/5666087.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值