安卓6.0以后申请部分权限需要在应用程序中提醒用户去开通,这些需要运行时申请的权限都是影响到用户信息安全的,6.0之前只要在AndroidManifest注册即可,6.0以后必须先申请,因此增加了安全性,但是给开发人员带来了麻烦。因此从网上找到了一个第三方库PermissionsDispatcher很容易处理运行时的异常。
PermissionsDispatcher
github地址:https://github.com/hotchemi/PermissionsDispatcher
说明文档:https://hotchemi.github.io/PermissionsDispatcher/
它以依赖注入的方式进行运行时异常的操作,我们以READ_CONTACTS读取通讯录权限为例,简要说明下调用过程。
1.首先还是得需要在AndriodManifest文件中注册READ_CONTACTS权限。
<uses-permission android:name="android.permission.READ_CONTACTS"/>
2.给相应方法提供注解
我们先来了解下PermissionsDispatcher都有哪些注解
@RuntimePermissions:注册一个Activity或者Fragment处理权限。
@NeedsPermission:注解一个方法,可以用来申请一个或者多个权限,当权限全都通过的时候,进行回调。
@OnShowRationale:注解一个方法,用来解释用户为什么需要这个权限,用PermissionRequest 来决定是继续,不做任何处理,还是去申请权限。
request.proceed() 代表用户同意开通此权限,request.cancel() 代表不做任何处理。(一般该方式是写一个AlertDialog,提醒用户是否开通权限)
当用户没有开通权限的时候调用此方法。
@OnPermissionDenied:用户禁止了权限时,调用此方法。
@OnNeverAskAgain:用户点击了申请权限框中的“never ask again”回调此方法。
注意:被注解的方法不能被private修饰。
@RuntimePermissions
public class AuthContactActivity extends AppCompatActivity {
@NeedsPermission(Manifest.permission.READ_CONTACTS)
void checkContactPermission(){
MyLogger.i(TAG,"checkContactPermission");
Uri uri = ContactsContract.Contacts.CONTENT_URI;
Intent intent = new Intent(Intent.ACTION_PICK, uri);
activity.startActivityForResult(intent, requestCode);
}
@OnShowRationale(Manifest.permission.READ_CONTACTS)
void showRationaleForContact(final PermissionRequest request) {
if (mAlertDialog==null) {
mAlertDialog = new AlertDialog.Builder(this)
.setMessage(BaseUtils.getStringByResouceId(R.string.auth_contact_permission_remind))
.setPositiveButton(R.string.auth_contact_permission_open, (dialog, button) -> request.proceed())
.setNegativeButton(R.string.auth_contact_permission_cancel, (dialog, button) -> request.cancel())
.create();
mAlertDialog.setCancelable(false);
mAlertDialog.setCanceledOnTouchOutside(false);
}
mAlertDialog.show();
}
@OnPermissionDenied(Manifest.permission.READ_CONTACTS)
void showDeniedForContact() {
MyLogger.i(TAG,"READ_CONTACTS Denied");
}
@OnNeverAskAgain(Manifest.permission.READ_CONTACTS)
void showNeverAskForContact() {
MyLogger.i(TAG,"READ_CONTACTS NeverAskFor");
if (notAskDialog==null) {
notAskDialog = new AlertDialog.Builder(this)
.setMessage(BaseUtils.getStringByResouceId(R.string.auth_contact_permission_not_ask))
.setPositiveButton(R.string.auth_contact_permission_do_open, (dialog, button) -> "跳转到系统权限管理界面或者其他")
.setNegativeButton(R.string.auth_contact_permission_cancel, (dialog, button) -> notAskDialog.dismiss())
.create();
notAskDialog.setCancelable(false);
notAskDialog.setCanceledOnTouchOutside(false);
}
notAskDialog.show();
}
notAskDialog.setCancelable(false);
notAskDialog.setCanceledOnTouchOutside(false);
}
notAskDialog.show();
}
3.委托生成一个帮助类
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button_contact).setOnClickListener(v -> {
AuthContactActivityPermissionsDispatcher.checkContactPermissionWithCheck(this);
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
AuthContactActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button_contact).setOnClickListener(v -> {
AuthContactActivityPermissionsDispatcher.checkContactPermissionWithPermissionCheck(this);
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
AuthContactActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
注解方法都已完成,需要根据需求调用他们,这里是当用户点击按钮时候判断是否开通了读取通讯录权限。
调用方法是[被@RuntimePermissions注释的Activity] + PermissionsDispatcher.[被@NeedsPermission注释的方法名称]+WithPermissionCheck(Context)
例如:AuthContactActivityPermissionsDispatcher.checkContactPermissionWithCheck(this)
用户选择完系统权限框的选项后,将结果回传给onRequestPermissionsResult,这里也用到了[被@RuntimePermissions注释的Activity] + PermissionsDispatcher的onRequestPermissionsResult方法。
本案例调用过程为:
用户点击按钮,调用xxxWithCheck方法
如果此应用通过了权限,那么直接执行checkContactPermission方法;
如果用户没有通过此权限,弹框提示是否开通此权限
用户点击“开通”:调用 PermissionRequest的proceed方法,默认是调用系统的申请权限提示框(具体的实现可以看源码)
系统提示框点击“始终允许”执行 checkContactPermission方法
系统提示框点击“禁止”执行 showDeniedForContact方法
系统提示框点击“禁止后不再询问”执行 showNeverAskForContact方法
(这里在showNeverAskForContact方法中设置了继续弹出一个弹框提示用户去系统权限界面设置)
用户点击“取消”:调用 PermissionRequest的cancel方法,默认调用showDeniedForContact方法
附:危险权限组和权限