PermissionsDispatcher是一个基于注解、帮助开发者简单处理Android 6.0系统中的运行时权限的开源库。避免了开发者编写大量繁琐的样板代码。
开源地址:https://github.com/hotchemi/PermissionsDispatcher
1. 添加依赖:
工程项目的:build.gradle
app模块的build.gradle
并将targetSdkVersion
设为23,即:
targetSdkVersion 23
2、在Activity或Fragment中使用
注解列表:
Annotation | Required | Description |
---|---|---|
@RuntimePermissions | ✓ | 注解在其内部需要使用运行时权限的Activity或Fragment上 |
@NeedsPermission | ✓ | 注解在需要调用运行时权限的方法上,当用户给予权限时会执行该方法 |
@OnShowRationale | 注解在用于向用户解释为什么需要调用该权限的方法上,只有当第一次请求权限被用户拒绝,下次请求权限之前会调用 | |
@OnPermissionDenied | 注解在当用户拒绝了权限请求时需要调用的方法上 | |
@OnNeverAskAgain | 注解在当用户选中了授权窗口中的不再询问复选框后并拒绝了权限请求时需要调用的方法,一般可以向用户解释为何申请此权限,并根据实际需求决定是否再次弹出权限请求对话框 |
只有注意:被注解的方法不能是私有方法。
@RuntimePermissions
和
@NeedsPermission
是必须的,其余注解均为可选。当使用了
@RuntimePermissions
和
@NeedsPermission
之后,需要点击菜单栏中
Build
菜单下的
Make Project
,或者按快捷键
Ctrl + F9
编译整个项目,编译器会在
app\build\intermediates\classes\debug
目录下与被注解的Activity同一个包下生成一个辅助类,名称为
被注解的Activity名称+PermissionsDispatcher.class
接下来可以调用辅助类里面的方法完成应用的权限请求了。
在需要调用权限的位置调用辅助类里面的xxxWithCheck
方法,xxx
是被@NeedsPermission
注解的方法名。如:
MainActivityPermissionsDispatcher.showCameraWithCheck(this);
之后,还需要重写该Activity的onRequestPermissionsResult()
方法,其方法内调用辅助类的onRequestPermissionsResult()
方法,如下:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// NOTE: delegate the permission handling to generated method
MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
完整的MainActivity
如下所示。
- MainActivity.java
@RuntimePermissions
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button_camera).setOnClickListener(this);
findViewById(R.id.button_contacts).setOnClickListener(this);
}
@Override
public void onClick(@NonNull View v) {
switch (v.getId()) {
case R.id.button_camera:
// NOTE: delegate the permission handling to generated method
MainActivityPermissionsDispatcher.showCameraWithCheck(this);
break;
case R.id.button_contacts:
// NOTE: delegate the permission handling to generated method
MainActivityPermissionsDispatcher.showContactsWithCheck(this);
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// NOTE: delegate the permission handling to generated method
MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
@NeedsPermission(Manifest.permission.CAMERA)
void showCamera() {
// NOTE: Perform action that requires the permission. If this is run by PermissionsDispatcher, the permission will have been granted
getSupportFragmentManager().beginTransaction()
.replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
.addToBackStack("camera")
.commitAllowingStateLoss();
}
@NeedsPermission({Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS})
void showContacts() {
// NOTE: Perform action that requires the permission.
// If this is run by PermissionsDispatcher, the permission will have been granted
getSupportFragmentManager().beginTransaction()
.replace(R.id.sample_content_fragment, ContactsFragment.newInstance())
.addToBackStack("contacts")
.commitAllowingStateLoss();
}
@OnShowRationale(Manifest.permission.CAMERA)
void showRationaleForCamera(PermissionRequest request) {
// NOTE: Show a rationale to explain why the permission is needed, e.g. with a dialog.
// Call proceed() or cancel() on the provided PermissionRequest to continue or abort
showRationaleDialog(R.string.permission_camera_rationale, request);
}
@OnShowRationale({Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS})
void showRationaleForContact(PermissionRequest request) {
// NOTE: Show a rationale to explain why the permission is needed, e.g. with a dialog.
// Call proceed() or cancel() on the provided PermissionRequest to continue or abort
showRationaleDialog(R.string.permission_contacts_rationale, request);
}
@OnPermissionDenied(Manifest.permission.CAMERA)
void onCameraDenied() {
// NOTE: Deal with a denied permission, e.g. by showing specific UI
// or disabling certain functionality
Toast.makeText(this, R.string.permission_camera_denied, Toast.LENGTH_SHORT).show();
}
@OnNeverAskAgain(Manifest.permission.CAMERA)
void onCameraNeverAskAgain() {
Toast.makeText(this, R.string.permission_camera_never_askagain, Toast.LENGTH_SHORT).show();
}
public void onBackClick(View view) {
getSupportFragmentManager().popBackStack();
}
private void showRationaleDialog(@StringRes int messageResId, final PermissionRequest request) {
new AlertDialog.Builder(this)
.setPositiveButton("允许", new DialogInterface.OnClickListener() {
@Override
public void onClick(@NonNull DialogInterface dialog, int which) {
request.proceed();
}
})
.setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
@Override
public void onClick(@NonNull DialogInterface dialog, int which) {
request.cancel();
}
})
.setCancelable(false)
.setMessage(messageResId)
.show();
}
}
3、附:危险权限和权限组列表
Android官方文档:https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
摘录如下:
权限组 | 权限 |
---|---|
CALENDAR | READ_CALENDAR WRITE_CALENDAR |
CAMERA | CAMERA |
CONTACTS | READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS |
LOCATION | ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION |
PHONE | READ_PHONE_STATE CALL_PHONE READ_CALL_LOG WRITE_CALL_LOG ADD_VOICEMAIL USE_SIP PROCESS_OUTGOING_CALLS |
SENSORS | BODY_SENSORS |
SMS | SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS |
STORAGE | READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE |
获取定位权限的代码片段:
//HomeActivityPermissionsDispatcher是在Activity头部添加注解@RuntimePermissions之后自动生成的,startLocationWithCheck方法是在方法头部添加了注解 @NeedsPermission之后生成的
HomeActivityPermissionsDispatcher.startLocationWithCheck(this);
startLocation();
/**
* 注解在用于向用户解释为什么需要调用该权限的方法上,只有当第一次请求权限被用户拒绝,下次请求权限之前会调用
* @param request
*/
@OnShowRationale({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_PHONE_STATE})
void showRationaleForGPS(final PermissionRequest request) {
new AlertDialog.Builder(this)
.setMessage("请授权,以便正常使用。")
.setPositiveButton("允许", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
request.proceed();
}
})
.setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
request.cancel();
}
})
.show();
}
/**
* 注解在当用户拒绝了权限请求时需要调用的方法上
*/
@OnPermissionDenied(Manifest.permission.ACCESS_FINE_LOCATION)
void showDeniedForFineLocation() {
Toast.makeText(this, "该应用需要开启GPS权限才能正常工作", Toast.LENGTH_SHORT).show();
}
/**
* 注解在当用户选中了授权窗口中的不再询问复选框后并拒绝了权限请求时需要调用的方法,一般可以向用户解释为何申请此权限,并根据实际需求决定是否再次弹出权限请求对话框
*/
@OnNeverAskAgain(Manifest.permission.ACCESS_FINE_LOCATION)
void showNeverAskForFineLocation() {
Toast.makeText(this, "该应用需要开启GPS权限才能正常工作", Toast.LENGTH_SHORT).show();
}
/**
* 方法内调用编译生成的辅助类的onRequestPermissionsResult()方法,用于在申请权限之后进行相应操作
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// NOTE: delegate the permission handling to generated method
HomeActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
原文地址:http://blog.csdn.net/feng787900247/article/details/54342003