参考资料
http://www.jianshu.com/p/d299f22dfbdb
http://blog.youkuaiyun.com/qq_34767498/article/details/51814669
Android Runtime Permission
Android 6.0(API 级别 23) 引入了一种新的权限模式,用户可以在运行时对管理应用权限。有点类似 iOS 。即使你的 APP 不去适配 Android 6.0,但是官方建议还是使用新的权限 API 去开发你的应用。
大致的使用流程如下:
在 AndroidManifest.xml 申明权限,添加 uses-permission ,这一步和以前的权限申请一致
检查权限,ContextCompat.checkSelfPermission() 方法。如果应用具有此权限,方法将返回 PackageManager.PERMISSION_GRANTED,并且应用可以继续操作。如果应用不具有此权限,方法将返回 PERMISSION_DENIED,且应用必须明确向用户要求权限。比如
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);
请求权限,如果你的 APP 权限里有危险的权限(拍照,短信,麦克风),那么必须要要让用户授予权限,调用 shouldShowRequestPermissionRationale() 会弹出对话框让用户选择,这个对话框是不是能修改的! 来看下大致的代码:
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
4 . 处理权限请求回调,看代码
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
大致的流程就是上面的几步,怎么区分你的权限是否需要用户授权,可以查看https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
当然也可以使用命令 adb shell pm list permissions -d -g 查看Dangerous Permission
下面是完整的代码,检测相机的权限,原生的 permission 实现
public class PermissionActivity extends AppCompatActivity {
private String sdPath;//SD卡的路径
private String picPath;//图片存储路径
public static final int REQUEST_CUST_CAMERA = 0X12;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_permission);
findViewById(R.id.readSDCard).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkPermission(Manifest.permission.CAMERA);
}
});
}
// 原生的permission check
public void checkPermission(String permission) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
// 这里很奇怪,基本进不到这步
Toast.makeText(this, "show permission detail", Toast.LENGTH_SHORT).show();
} else {
ActivityCompat.requestPermissions(this, new String[]{permission}, REQUEST_CUST_CAMERA);
}
} else {
showReadFile();
}
}
void showReadFile() {
sdPath = Environment.getExternalStorageDirectory().getPath();
picPath = sdPath + "/" + "temp.png";
Intent intent2 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = Uri.fromFile(new File(picPath));
//为拍摄的图片指定一个存储的路径
intent2.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent2, 0x12);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CUST_CAMERA) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showReadFile();
} else {
//用户取消了授权
//用户在安全中心关闭了权限(测试的小米手机)
Toast.makeText(PermissionActivity.this, "permission denied", Toast.LENGTH_SHORT).show();
//如果实在很重要,可以引导用户去设置界面,开启
}
}
}
}
## 下面来介绍下第三方的库: PermissionsDispatcher 这个库有以下的特点:
- 100% 自由反射
- 支持特殊的权限
- 支持小米
- 支持 kotlin
首先来看下怎么使用
1. 下载
dependencies {
// 这里注意替换掉 {latest.version} 去github 查询最新的版本号,自行替换
compile("com.github.hotchemi:permissionsdispatcher:${latest.version}") {
// if you don't use android.app.Fragment you can exclude support for them
exclude module: "support-v13"
}
annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:${latest.version}"
}
repositories {
jcenter()
// 项目根目录的 build.gradle repositories 添加 maven 支持
maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' }
}
添加好后,build 下就可以下载该库了
2. AndroidManifest.xml 申明权限,添加 uses-permission ,这一步和以前的权限申请一致
// 比如
<uses-permission android:name="android.permission.CAMERA" />
3. 在相应的页面添加下面的代码,看注释
// 这里注解是必须的, 表明这个Activity 要申请权限, 可以在 Activity 和 Fragment 上使用这个注解
@RuntimePermissions
public class PermissionActivity extends AppCompatActivity {
private String sdPath;//SD卡的路径
private String picPath;//图片存储路径
public static final int REQUEST_CUST_CAMERA = 0X12;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_permission);
findViewById(R.id.readSDCard).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// PermissionActivityPermissionsDispatcher 这个类是由库自动生成的,一个封装好权限检测的类,其实就是在当前类的后面加上PermissionsDispatcher,所以初学者千万不要照抄这里
// showCameraWithCheck 则是根据NeedsPermission 注解生成的,可能有点不好理解,具体看 showCamera()
PermissionActivityPermissionsDispatcher.showCameraWithCheck(PermissionActivity.this);
}
});
}
// 这个注解也是必须的,指的是请求权限的方法,后面跟上对应的权限
// 这个注解修饰方法会在PermissionsDispatcher 类生成 (方法名+WithCheck)的方法,看上面的showCameraWithCheck
@NeedsPermission(Manifest.permission.CAMERA)
void showCamera() {
sdPath = Environment.getExternalStorageDirectory().getPath();
picPath = sdPath + "/" + "temp.png";
Intent intent2 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = Uri.fromFile(new File(picPath));
//为拍摄的图片指定一个存储的路径
intent2.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent2, 0x12);
}
// 这里和原生的一致
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 调用 PermissionActivityPermissionsDispatcher 的静态方法,然后会回调 @NeedsPermission,@OnPermissionDenied 和 @OnNeverAskAgain,分别对应为 用户通过了权限,权限不通过和 用户点了不再询问。
PermissionActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
// 权限不通过 这个注解也是必须的
@OnPermissionDenied(Manifest.permission.CAMERA)
void showDeniedForRead() {
Toast.makeText(this, "showDeniedForRead", Toast.LENGTH_SHORT).show();
}
// 用户点了不再询问 这个注解也是必须的
@OnNeverAskAgain(Manifest.permission.CAMERA)
void showNeverAskForRead() {
Toast.makeText(this, "showNeverAskForRead", Toast.LENGTH_SHORT).show();
}
}
本文详细介绍了Android 6.0中引入的运行时权限管理机制,包括如何在应用中请求和处理权限,特别是对于敏感权限如摄像头、联系人等的处理流程。同时,还提供了一个第三方库PermissionsDispatcher的使用指南,简化权限处理过程。
1万+

被折叠的 条评论
为什么被折叠?



