调研一下Android 6.0临时运行权限
调研一下原理
概述
临时运行权限是Android 6.0所带来的变化,主要是为了解决app滥用权限的现象。6.0之前的系统app安装的时候会有一个权限列表用户同意了以后才可以安装,而6.0以后用户可以直接安装app,当app需要使用某些危险权限的时候系统会给用户提示,用户可以选择拒绝和同意,同时用户可以设置里面查看app的权限。
危险权限和普通权限
Google将权限分为了两类
第一种是普通权限(Normal Permission),这些权限不会涉及用户的隐私
- ACCESS_LOCATION_EXTRA_COMMANDS
- ACCESS_NETWORK_STATE
- ACCESS_NOTIFICATION_POLICY
- ACCESS_WIFI_STATE
- BLUETOOTH
- BLUETOOTH_ADMIN
- BROADCAST_STICKY
- CHANGE_NETWORK_STATE
- CHANGE_WIFI_MULTICAST_STATE
- CHANGE_WIFI_STATE
- DISABLE_KEYGUARD
- EXPAND_STATUS_BAR
- GET_PACKAGE_SIZE
- INSTALL_SHORTCUT
- INTERNET
- KILL_BACKGROUND_PROCESSES
- MODIFY_AUDIO_SETTINGS
- NFC
- READ_SYNC_SETTINGS
- READ_SYNC_STATS
- RECEIVE_BOOT_COMPLETED
- REORDER_TASKS
- REQUEST_INSTALL_PACKAGES
- SET_ALARM
- SET_TIME_ZONE
- SET_WALLPAPER
- SET_WALLPAPER_HINTS
- TRANSMIT_IR
- UNINSTALL_SHORTCUT
- USE_FINGERPRINT
- VIBRATE
- WAKE_LOCK
- WRITE_SYNC_SETTINGS
第二种是危险权限(Dangerous Permissions),这些权限又可以能会涉及到用户的隐私
- group:android.permission-group.CONTACTS
- permission:android.permission.WRITE_CONTACTS
- permission:android.permission.GET_ACCOUNTS
- permission:android.permission.READ_CONTACTS
- group:android.permission-group.PHONE
- permission:android.permission.READ_CALL_LOG
- permission:android.permission.READ_PHONE_STATE
- permission:android.permission.CALL_PHONE
- permission:android.permission.WRITE_CALL_LOG
- permission:android.permission.USE_SIP
- permission:android.permission.PROCESS_OUTGOING_CALLS
- permission:com.android.voicemail.permission.ADD_VOICEMAIL
- group:android.permission-group.CALENDAR
- permission:android.permission.READ_CALENDAR
- permission:android.permission.WRITE_CALENDAR
- group:android.permission-group.CAMERA
- permission:android.permission.CAMERA
- group:android.permission-group.SENSORS
- permission:android.permission.BODY_SENSORS
- group:android.permission-group.LOCATION
- permission:android.permission.ACCESS_FINE_LOCATION
- permission:android.permission.ACCESS_COARSE_LOCATION
- group:android.permission-group.STORAGE
- permission:android.permission.READ_EXTERNAL_STORAGE
- permission:android.permission.WRITE_EXTERNAL_STORAGE
- group:android.permission-group.MICROPHONE
- permission:android.permission.RECORD_AUDIO
- group:android.permission-group.SMS
- permission:android.permission.READ_SMS
- permission:android.permission.RECEIVE_WAP_PUSH
- permission:android.permission.RECEIVE_MMS
- permission:android.permission.RECEIVE_SMS
- permission:android.permission.SEND_SMS
- permission:android.permission.READ_CELL_BROADCASTS
要做的几件事
AndroidManifast.xml文件中的权限还是要添加,不然系统还是会报错
1.检查权限
ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED
2.申请权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 1);
3.处理权限回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + phoneNumber);
intent.setData(data);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "Permisson Denied", Toast.LENGTH_SHORT).show();
}
}
}
简单的例子
PermissionSimpleTest
常见的三方库
- AndPermission
- RxPermission
- PermissionGen
- MPermissions
常见三方库的用法
AndPermission
地址:https://github.com/yanzhenjie/AndPermission
用法:
-
依赖方式:
远程依赖
compile 'com.yanzhenjie:permission:1.0.1'
-
申请一个权限:
//申请权限
AndPermission.with(this) .requestCode(101) .permission(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_SMS, Manifest.permission.WRITE_EXTERNAL_STORAGE) .rationale(mRationaleListener) .callback(listener) .start();
-
申请多个权限:
//申请权限
AndPermission.with(this) .requestCode(101) .permission(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_SMS, Manifest.permission.WRITE_EXTERNAL_STORAGE) .rationale(mRationaleListener) .callback(listener) .start();
回调处理:
-
Listener方式回调
private PermissionListener listener = new PermissionListener() { @Override public void onSucceed(int requestCode, List<String> grantedPermissions) { // 权限申请成功回调。 // 这里的requestCode就是申请时设置的requestCode。 // 和onActivityResult()的requestCode一样,用来区分多个不同的请求。 if (requestCode == 101) { // TODO ... Toast.makeText(getApplicationContext(), "申请权限成功", Toast.LENGTH_SHORT).show(); } } @Override public void onFailed(int requestCode, List<String> deniedPermissions) { // 权限申请失败回调。 if (requestCode == 101) { // TODO ... Toast.makeText(getApplicationContext(), "申请权限失败", Toast.LENGTH_SHORT).show(); } } };
-
注解方式回调
// 成功回调的方法,用注解即可,里面的数字是请求时的 requestCode。 @PermissionYes(100) private void getLocationYes() { // 申请权限成功,可以去做点什么了。 Toast.makeText(this, "获取定位权限成功", Toast.LENGTH_SHORT).show(); } // 失败回调的方法,用注解即可,里面的数字是请求时的 requestCode。 @PermissionNo(100) private void getLocationNo() { // 申请权限失败,可以提醒一下用户。 Toast.makeText(this, "获取定位权限失败", Toast.LENGTH_SHORT).show(); }
-
Rationale能力
Android运行时权限有一个特点,就是用户在拒绝过一次权限以后,再次申请权限的时候弹出的提示框中会多一个【不再提示】的选项,
当用户选择并拒绝申请的时候,那么以后再次申请权限将直接导致申请失败!因此为了避免用户以后一直无法申请权限,Rationale显然是
有必要的,Rationale的功能是在用户拒绝申请之前提示用户申请这个权限的目的和用处,Rationale的提示框是开发者可以定义的。private RationaleListener mRationaleListener = new RationaleListener() { @Override public void showRequestPermissionRationale(int requestCode, final Rationale rationale) { new AlertDialog.Builder(AndPermissionActivity.this) .setTitle("友好提醒") .setMessage("没有定位权限将不能为您推荐附近妹子,请把定位权限赐给我吧!") .setPositiveButton("好,给你", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); rationale.resume();// 用户同意继续申请。 } }) .setNegativeButton("我拒绝", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); rationale.cancel(); // 用户拒绝申请。 } }).show(); } };
RxPermission
地址:https://github.com/tbruyelle/RxPermissions
PermissionGen
地址:https://github.com/lovedise/PermissionGen
用法
-
申请权限
PermissionGen.with(MainActivity.this) .addRequestCode(100) .permissions( Manifest.permission.READ_CONTACTS, Manifest.permission.RECEIVE_SMS, Manifest.permission.WRITE_CONTACTS) .request();
-
回调处理
-
回调方式一
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { PermissionGen.onRequestPermissionsResult(this, requestCode, permissions, grantResults); }
@PermissionSuccess(requestCode = 100) public void test(){ startActivity(new Intent(this, ContactActivity.class)); } @PermissionFail(requestCode = 100) private void test2() { Dlog.debug("contact fail"); }
-
MPermissions
地址:https://github.com/hongyangAndroid/MPermissions
AndPermission和PermissionGen的对比
AndPermission的最大的有点就是有一个Rationale这对于用户是一个不错的体验,并且我们可以自定义Dialog,这是PermissionGen不具备的。
AndPermission具备在其它类中申请权限的能力,这显然也是PermissionGen不具备的
PermissionGen代码量相对较少,调用方便。
两个库都不具备判断具体哪个权限被拒绝的能力
选择一个三方库
AndPermission
参考文章:
http://blog.csdn.net/lmj623565791/article/details/50709663
http://www.jianshu.com/p/a1edba708761