阅读前说明:
具体流程=单个权限流程图+权限组流程图
代码中有例子,就不详细说明了。
easypermissions
dependencies {
implementation 'pub.devrel:easypermissions:1.2.0'
}
public static final int PERMISSION_STORAGE_CODE = 10001;
public static final String PERMISSION_STORAGE_MSG = "此app需要获取SD卡读取权限";
public static final String[] PERMISSION_STORAGE = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};
public static boolean hasPermissions(Context context, String... permissions) {
return EasyPermissions.hasPermissions(context, permissions);
}
/**
* 是否有SD卡权限
*
* @param context
* @return
*/
public static boolean hasStoragePermission(Context context) {
return hasPermissions(context, PERMISSION_STORAGE);
}
@AfterPermissionGranted(PERMISSION_STORAGE_CODE)
public void initSimple() {
if (hasStoragePermission(context)) {
//有权限
} else {
//申请权限
EasyPermissions.requestPermissions(context, PERMISSION_STORAGE_MSG, PERMISSION_STORAGE_CODE, PERMISSION_STORAGE);
}
}
EasyPermissions.PermissionCallbacks
接口,直接处理权限是否成功申请 @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// Forward results to EasyPermissions
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
//成功
@Override
public void onPermissionsGranted(int requestCode, List list) {
// Some permissions have been granted
// ...
}
//失败
@Override
public void onPermissionsDenied(int requestCode, List list) {
// Some permissions have been denied
// ...
}
EasyPermissions.requestPermissions(context, PERMISSION_STORAGE_MSG, PERMISSION_STORAGE_CODE, PERMISSION_STORAGE);
或者
EasyPermissions.requestPermissions(
new PermissionRequest.Builder(this, RC_CAMERA_AND_LOCATION, perms)
.setRationale(R.string.camera_and_location_rationale)
.setPositiveButtonText(R.string.rationale_ask_ok)
.setNegativeButtonText(R.string.rationale_ask_cancel)
.setTheme(R.style.my_fancy_style)
.build());
方法回调实现EasyPermissions.RationaleCallbacks
接口:
/**
* dialog提醒点击“确定”
*
* @param requestCode
*/
@Override
public void onRationaleAccepted(int requestCode) {
}
/**
* dialog提醒点击“取消”
*
* @param requestCode
*/
@Override
public void onRationaleDenied(int requestCode) {
}
详细使用参考:easypermissions
/**
* 拒绝权限
*
* @param requestCode
* @param perms
*/
@Override
public void onPermissionsDenied(int requestCode, @NonNull List perms) {
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this)
.setTitle("提醒")
.setRationale("此app需要这些权限才能正常使用")
.build()
.show();
}
}
方法回调
/**
/**
* 设置页面回调
*
* @param requestCode
* @param resultCode
* @param data
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {
if (PermissionUtils.hasStoragePermission(context)){
//有权限
}else{
//没有权限
}
}
}
国产ROM问题一直是最多的,申请权限的弹窗不按Android原生来,有时候允许权限了,回调却是走失败。
如果想适配国产ROM,我推荐 AndPermission
AndPermission可以简化在Android上请求权限的流程。
为了兼容一些特殊中国产手机,AndPermission请求权限的流程是这样的:
发起请求
│
调用SDK Api判断是否有权限
│
┌─────────────┴─────────────┐
有权限 没权限
│ │
│ 使用SDK Api请求权限
│ │
│ 用户授权或者拒绝
└─────────────┬─────────────┘
执行权限相关代码
┌───────┴───────┐
正常 异常
│ │
onGranted() onDenied()
┌──────┴──────┐ │
正常 异常───────┘
可以看出AndPermission的申请流程和标准的申请流程大相径庭,这样做主要是因为以下几点原因。
因为部分权限(例如发送短信、打电话、接听/挂断电话等),AndPermission不能执行权限相关代码做测试,所以对于这一类权限在执行权限相关代码步骤仅仅使用了AppOpsManager做检测。因为极少部分国产机总是返回true,因此直接回调到onGranted()中让开发者执行相关代码来辅助AndPermission的整个流程,如果onGranted()方法发生异常,那么则认为是没有权限,所以重新回调到onDenied()方法中,如果onGranted()方法正常执行那么则认为有权限。这样一来刚好是一个完整的流程,也可以最大限度的兼容到更多异常的手机。
回调onGranted()时AndPermission对onGranted()方法做了try catch。这样做可以保证两点,第一点是防止部分手机返回错误状态时回调了onGranted()后的崩溃,第二点是防止部分手机需要真正执行权限相关代码时触发授权Dialog后被用户拒绝后的崩溃。而这两点都是没有权限,因此会重新回调到onDenied()中让开发者处理没权限的情况。
AndPermission详细说明文档
GitHub