从 Android 6.0(API 级别 23)开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予。
系统权限分为两类:
如需了解更多关于正常权限与危险权限可以参阅这里。
关于 Android 6.0 运行时权限的详细讲解可以看这篇文章和官方文档。
PermissionsDispatcher 提供简单的基于注解的 api 处理 Android Marshmallow 下的运行时权限(非反射方式)。
GitHub 地址:https://github.com/permissions-dispatcher/PermissionsDispatcher
注意把 ${latest.version}
改为最新版本。
打开命令行,cd 到工程根目录,执行 gradlew -version 或者 gradlew -v 命令查看当前工程 gradle 版本。
根据 gradle 版本进行如下配置:
Android Gradle Plugin >= 2.2
在 app 模块下的 build.gradle 添加下面的配置:
dependencies {
compile 'com.github.hotchemi:permissionsdispatcher:${latest.version}'
annotationProcessor 'com.github.hotchemi:permissionsdispatcher-processor:${latest.version}'
}
Android Gradle Plugin < 2.2
在 project-level 下的 build.gradle
添加下面配置:
buildscript {
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
然后,在 app 模块下的 build.gradle
添加下面配置:
apply plugin: 'android-apt'
dependencies {
compile 'com.github.hotchemi:permissionsdispatcher:${latest.version}'
apt 'com.github.hotchemi:permissionsdispatcher-processor:${latest.version}'
}
注意:注解的方法不能是
private
的。
示例代码
@RuntimePermissions
public class MainActivity extends AppCompatActivity {
// 单个权限
// @NeedsPermission(Manifest.permission.CAMERA)
// 多个权限
@NeedsPermission({ Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO })
void showCamera() {
getSupportFragmentManager().beginTransaction()
.replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
.addToBackStack("camera")
.commitAllowingStateLoss();
}
// 向用户说明为什么需要这些权限(可选)
@OnShowRationale(Manifest.permission.CAMERA)
void showRationaleForCamera(final PermissionRequest request) {
new AlertDialog.Builder(this)
.setMessage(R.string.permission_camera_rationale)
.setPositiveButton(R.string.button_allow, (dialog, button) -> request.proceed())
.setNegativeButton(R.string.button_deny, (dialog, button) -> request.cancel())
.show();
}
// 用户拒绝授权回调(可选)
@OnPermissionDenied(Manifest.permission.CAMERA)
void showDeniedForCamera() {
Toast.makeText(this, R.string.permission_camera_denied, Toast.LENGTH_SHORT).show();
}
// 用户勾选了“不再提醒”时调用(可选)
@OnNeverAskAgain(Manifest.permission.CAMERA)
void showNeverAskForCamera() {
Toast.makeText(this, R.string.permission_camera_neverask, Toast.LENGTH_SHORT).show();
}
}
2. 调用自动生成的辅助类
注解写好后,Build ——> Make Module ***,PermissionsDispatcher
会生成一个 MainActivityPermissionsDispatcher(Activity Name + PermissionsDispatcher)
,你可以使用它来安全地访问这些受权限保护的方法。
你唯一需要做的一件事是将工作委托给这个辅助类:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button_camera).setOnClickListener(v -> {
// 调用带权限检查的 showCamera 方法
MainActivityPermissionsDispatcher.showCameraWithCheck(this);
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 代理权限处理到自动生成的方法
MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
PermissionDispatcher.WithCheck
方法对你原来的方法进行了包装,包了一层权限检查的代码,你需要做的就是把原来的方法调用改为 PermissionDispatcher.WithCheck
。另外,在 onRequestPermissionsResult
中回调 PermissionsDispatcher.onRequestPermissionsResult
方法。
两个特殊权限:
Manifest.permission.SYSTEM_ALERT_WINDOW
:显示悬浮窗Manifest.permission.WRITE_SETTINGS
:读写系统设置对于这两个权限,在 Android 下默认是需要到 Settings -> Apps
中手动授权的。由于不同 ROM 情况可能还有点不一样。
PermissionsDispatcher
对于两个特殊权限也做了兼容处理(Android6.0+),使用方法如上一样。
如果需要兼容低版本的 Android 系统或者不同 ROM 可以参考这个开源项目。
有一个 maxSdkVersion
属性,PermissionsDispatcher
对它也做了支持。
比如,在 Androidmanifest.xml 中定义了如下权限:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
注解中添加 maxSdkVersion
:
@RuntimePermissions
public class MainActivity extends AppCompatActivity {
@NeedsPermission(value = Manifest.permission.WRITE_EXTERNAL_STORAGE, maxSdkVersion = 18)
void getStorage() {
// ...
}
}