1 概述
对于6.0的几个主要的变化,查看查看官网的这篇文章Runtime Permissions,其中包含Runtime Permissions。
Android 6.0系统中需要动态授权的危险权限表,一共是9组27个权限。当我们在动态授权时,只要用户允许了一组当中的一个权限,那么系统默认会通过整组的权限,所以我们在动态授权时每组只要将一个permission进行授权即可。
具体的权限说明,参考:android6.0获取通讯录权限
2 运行时权限的变化及特点
在6.0以后,我们可以直接安装,当app需要我们授予不恰当的权限的时候,我们可以予以拒绝。当然你也可以在设置界面对每个app的权限进行查看,以及对单个权限进行授权或者解除授权。
新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。
3 授予单个权限的Demo
/**
* 个人中心页面
* Created by chenliguan on 16/6/29.
*/
public class PersonActivity extends AppCompatActivity {
private static final int PERMISSIONS_CALL_PHONE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.vContact:
callPhone();//拨号
break;
default:
break;
}
}
/**
* 拨号
*/
public void callPhone() {
/**
* 1.检查权限
*/
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
/**
* 2.申请授权
* 第二个参数是需要申请的权限的字符串数组
* 第三个参数为requestCode,主要用于回调的时候检测
*/
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CALL_PHONE}, PERMISSIONS_CALL_PHONE);
} else {
submitPhoneCall();
}
}
/**
* 处理权限申请回调
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case PERMISSIONS_CALL_PHONE:
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
submitPhoneCall();//调用拨号界面,不直接拨打电话
} else {
showShortToast(R.string.toast_permission_no);
}
return;
default:
break;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
/**
* 调用拨号界面,不直接拨打电话
*/
private void submitPhoneCall() {
//Intent.ACTION_CALL 直接拨打电话
intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + Config.CLIENT_SERVER.replace("-", "")));
startActivity(intent);
}
}
4 授予多个权限的Demo
// 声明一个数组,用来存储所有需要动态申请的权限
String[] permissions = new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE,};
// 声明一个集合,在后面的代码中用来存储用户拒绝授权的权
List<String> mPermissionList = new ArrayList<>();
// 检查权限方法
private void checkPermission() {
mPermissionList.clear();
/**
* 判断哪些权限未授予,以便必要的时候重新申请
*/
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(mContext, permission) != PackageManager.PERMISSION_GRANTED) {
mPermissionList.add(permission);
}
}
/**
* 判断存储委授予权限的集合是否为空
*/
if (!mPermissionList.isEmpty()) {
// 后续操作...
} else {//未授予的权限为空,表示都授予了
// 后续操作...
}
}
boolean mShowRequestPermission = true;//用户是否禁止权限
// 回调动态授权结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
//判断是否勾选禁止后不再询问
boolean showRequestPermission = ActivityCompat.shouldShowRequestPermissionRationale(ShopNearbyActivity.this, permissions[i]);
if (showRequestPermission) {
// 后续操作...
} else {
// 后续操作...
}
}
}
// 授权结束后的后续操作...
break;
default:
break;
}
}
5 判断某项权限是否被授权
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int checkResult = appOpsManager.checkOpNoThrow(
AppOpsManager.OPSTR_FINE_LOCATION, Binder.getCallingUid(), context.getPackageName());
if(checkResult == AppOpsManager.MODE_ALLOWED){
Toast.makeText(context,"有权限",Toast.LENGTH_LONG).show();
Log.e("jijiaxin","有权限");
}else if(checkResult == AppOpsManager.MODE_IGNORED){
Toast.makeText(context,"被禁止了,没有权限",Toast.LENGTH_LONG).show();
Log.e("jijiaxin","被禁止了,没有权限");
}else if(checkResult == AppOpsManager.MODE_ERRORED){
Toast.makeText(context,"出错了",Toast.LENGTH_LONG).show();
Log.e("jijiaxin","出错了");
}else if(checkResult == 4){
Toast.makeText(context,"权限需要询问",Toast.LENGTH_LONG).show();
Log.e("jijiaxin","权限需要询问");
}
}
6 权限授权第三方框架
6.1 推荐AndPermission
6.2 使用
(1)Gradle
compile 'com.yanzhenjie:permission:1.1.2'
(2) 使用模板
// Activity:
AndPermission.with(activity)
.requestCode(100)
.permission(Permission.SMS)
.rationale(...)
.callback(...)
.start();
// Fragment:
AndPermission.with(fragment)
.requestCode(100)
.permission(
// Multiple permissions group.
Permission.SMS,
Permission.LOCATION
)
.rationale(...)
.callback(...)
.start();
// Anywhere:
AndPermission.with(context)
.requestCode(100)
.permission(Permission.SMS)
.rationale(...)
.callback(...)
.start();
// If only want to request a permission:
AndPermission.with(this)
.requestCode(300)
.permission(Manifest.permission.WRITE_CONTACTS)
.rationale(...)
.callback(...)
.start();
// If only want to request some permissions:
AndPermission.with(this)
.requestCode(300)
.permission(
Manifest.permission.WRITE_CONTACTS,
Manifest.permission.READ_SMS
)
.rationale(...)
.callback(...)
.start();
(3) 例子
AndPermission.with(context)
.requestCode(200)
.permission(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_PHONE_STATE)
.callback(new PermissionListener() {
@Override
public void onSucceed(int requestCode, @NonNull List<String> grantPermissions) {
if (requestCode == 200) {
}
}
@Override
public void onFailed(int requestCode, @NonNull List<String> deniedPermissions) {
}
})
.start();