AndPermission特性
- 兼容国产手机的各种bug(小米、华为、魅族,以及各种…)。
- 支持链式调用,一句话申请权限,为你省去复杂的逻辑判断。
- 支持注解回调结果、支持Listener回调结果。
- (可选)支持Rationale,拒绝一次权限,再次申请时先征求用户同意,再打开授权对话框,避免用户勾选不再提示。
- (可选)就算用户勾选不再提示,并且拒绝权限后,AndPermission智能提示用户去设置中授权。
- Rationale对话框自定义,申请授权失败后打开设置的dialog,预置了MD风格dialog,开发者也可以自定义。
- 如果使用默认对话框,自动支持国际化。
- 支持
Activity
、android.support.v4.app.Fragment
、android.app.Fragment
。
几个重要的方法与常量解释
int checkSelfPermission(String)
void requestPermissions(int, String...)
boolean shouldShowRequestPermissionRationale(String)
void onRequestPermissionsResult()
上述四个方法中,前三个方法在support-v4
的ActivityCompat
中都有,建议使用兼容库中的方法。最后一个方法是用户授权或者拒绝某个权限组时系统会回调Activity或者Fragment中的方法。
checkSelfPermission() 检查权限
- 检查某一个权限的当前状态,你应该在请求某个权限时检查这个权限是否已经被用户授权,已经授权的权限重复申请可能会让用户产生厌烦。
- 该方法有一个参数是权限名称,有一个int的返回值,用这个值与上面提到的两个常量做比较可判断检查的权限当前的状态。
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
}else{
}
requestPermissions() 申请权限
- 请求用户授权几个权限,调用后系统会显示一个请求用户授权的提示对话框,App不能配置和修改这个对话框,如果需要提示用户这个权限相关的信息或说明,需要在调用 requestPermissions() 之前处理,该方法有两个参数:
- int requestCode,会在回调
onRequestPermissionsResult()
时返回,用来判断是哪个授权申请的回调。 - String[] permissions,权限数组,你需要申请的的权限的数组。
- 由于该方法是异步的,所以无返回值,当用户处理完授权操作时,会回调Activity或者Fragment的
onRequestPermissionsResult()
方法。
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.READ_CONTACTS}, MMM);
onRequestPermissionsResult() 处理权限结果回调
- 该方法在Activity/Fragment中应该被重写,当用户处理完授权操作时,系统会自动回调该方法,该方法有三个参数:
- int requestCode,在调用
requestPermissions()
时的第一个参数。 - String[] permissions,权限数组,在调用
requestPermissions()
时的第二个参数。 - int[] grantResults,授权结果数组,对应permissions,具体值和上方提到的PackageManager中的两个常量做比较。
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MMM: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
}
return;
}
}
}
shouldShowRequestPermissionRationale()
- 望文生义,是否应该显示请求权限的说明。
- 第一次请求权限时,用户拒绝了,调用
shouldShowRequestPermissionRationale()
后返回true,应该显示一些为什么需要这个权限的说明。 - 用户在第一次拒绝某个权限后,下次再次申请时,授权的dialog中将会出现“不再提醒”选项,一旦选中勾选了,那么下次申请将不会提示用户。
- 第二次请求权限时,用户拒绝了,并选择了“不再提醒”的选项,调用
shouldShowRequestPermissionRationale()
后返回false。 - 设备的策略禁止当前应用获取这个权限的授权:
shouldShowRequestPermissionRationale()
返回false 。 - 加这个提醒的好处在于,用户拒绝过一次权限后我们再次申请时可以提醒该权限的重要性,免得再次申请时用户勾选“不再提醒”并决绝,导致下次申请权限直接失败。
综上所述,整合代码后:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)) {
} else {
ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MMM);
}
}
...
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MMM: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
}
return;
}
}
}
- 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
运行时权限最佳实践的套路
总体下来我们应该对运行时权限有一个系统的认识,我总结出了一些套路:
- 需要区分各种Normal Permissioin和Dangerous Permissions。
- 判断多个权限授权回调时需要判断每一个权限是否全都是被授权了,否则操作不能继续。
- 需要请求多个权限时需要挨个检查是否已经被授权过,没授权的才去请求,还要检查这些权限是否需要提示用户,如果多个权限都需要提示,该如何处理。
- 上述1 2 3如果在需要在多个页面 实现,代码重复。
- …
其实问题远远不止这些,认真看过文章的人应该会发现,实现代码比较简单,但是代码重复加上需要我们考虑和注意的细节太多了,那么下面我就为大家介绍一个开源内裤来解决这一系列问题。
AndPermission
这个开源库名叫AndPermission:https://github.com/yanzhenjie/AndPermission,经过我的实践是完全解决了上述问题,推荐大家使用,有兴趣的朋友可以去star下。
- AndroidStudio使用方法,gradle一句话远程依赖
compile ‘com.yanzhenjie:permission:1.0.5‘
申请权限
一个权限
AndPermission.with(this)
.requestCode(100)
.permission(Manifest.permission.WRITE_CONTACTS)
.send();
多个权限
AndPermission.with(this)
.requestCode(100)
.permission(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_SMS)
.send();
在使用到特殊权限时,只需要在Activity
、Fragment
中直接调用,等到AndPermission
回调时即可执行相应的代码。
注意
1. 如果你的Activity
继承的是AppCompatActivity
、FragmentActivity
或者它们的子类,那么你直接请求权限就可以。
2. 如果你的Fragment
继承的是android.support.v4.app.Fragment
或者它的子类,那么你直接请求权限就可以。
3. 如果你继承的是android.app.Activity
、android.app.Fragment
、在6.0以下的手机是没有onRequestPermissionsResult()
方法的,所以需要在申请权限前判断:
if(AndPermission.hasPermission(this, Manifest.permission.READ_SMS)) {
} else {
AndPermission.with(this)
.requestCode(100)
.permission(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_SMS)
.send();
}
回调结果
方式一:利用Listener方式回调
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
AndPermission.onRequestPermissionsResult(requestCode, permissions, grantResults, listener);
}
private PermissionListener listener = new PermissionListener() {
@Override
public void onSucceed(int requestCode, List<String> grantedPermissions) {
if(requeust == 100) {
} else if(requestCode == 101) {
}
}
@Override
public void onFailed(int requestCode, List<String> deniedPermissions) {
if (AndPermission.hasAlwaysDeniedPermission(this, deniedPermissions)) {
AndPermission.defaultSettingDialog(this, REQUEST_CODE_SETTING).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
方式二:利用注解回调
只需要重写Activity/Fragment的一个方法,然后提供一个授权时回调的方法即可:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
AndPermission.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
@PermissionYes(100)
private void getLocationYes(List<String> grantedPermissions) {
}
@PermissionNo(100)
private void getLocationNo(List<String> deniedPermissions) {
if (AndPermission.hasAlwaysDeniedPermission(this, deniedPermissions)) {
AndPermission.defaultSettingDialog(this, REQUEST_CODE_SETTING).show();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
如果你会用了,你就可以大刀阔斧的干了,博客中讲到的各种复杂逻辑,AndPermission自动完成。
Rationale拒绝一次后,再次提示用户权限作用
方式一:使用AndPermssion默认MD风格对话框
AndPermission.with(this)
.requestCode(REQUEST_CODE_PERMISSION_LOCATION)
.permission(Manifest.permission.ACCESS_FINE_LOCATION)
.rationale((requestCode, rationale) ->
AndPermission.rationaleDialog(PermissionActivity.this, rationale).show()
)
.send()
方式二:自定义对话框
AndPermission.with(this)
.requestCode(REQUEST_CODE_PERMISSION_LOCATION)
.permission(Manifest.permission.ACCESS_FINE_LOCATION)
.rationale(rationaleListener)
.send()
/**
* Rationale支持,这里自定义对话框。
*/
private RationaleListener rationaleListener = (requestCode, rationale) -> {
AlertDialog.build(this)
.setTitle("友好提醒")
.setMessage("您已拒绝过定位权限,没有定位权限无法为您推荐附近妹子,请把定位权限赐给我吧!")
.setPositiveButton("好,给你", (dialog, which) -> {
rationale.resume();
})
.setNegativeButton("我拒绝", (dialog, which) -> {
rationale.cancel();
}).show();
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20