Android6.0权限,如何封装处理授权问题
来源:互联网 发布:双系统ubuntu安装教程 编辑:程序博客网 时间:2024/06/11 02:41
*Android6.0简介:*
Android6.0称为Marshmallow(棉花糖),在2015年Google的I/O大会上正式发布,至今已经有一年多了,所占市场份额在2.3%以上,更新了比较多的模块,当然主要是对Android系统进行了优化,对于我们码农来说主要是应用权限的管理。
*主要更新模块*
电源管理
在原有的电源管理的基础上加入了两种新的状态:- App Standby—应用待机状态
当系统检测到设备不充电,且用户没有直接或间接启动该应用时,该应用进入应用待机状态,而反之(当应用被激活或者设备在充电时)系统将该应用移出应用待机状态; - Doze 系统休眠状态
当系统检测到设备不充电,且设备静止灭屏一段时间会进入休眠状态,而如此周期性检测,状态不改变则会进入更长的休眠状态,一直到进入饱和休眠状态;
- App Standby—应用待机状态
规范化App Link (应用程序链接)
*技术点:隐式Intent
鼓励应用程序间关联,弱化浏览器的使用:比如说用户点击淘宝的广告,优先考虑跳转到淘宝APP(如果用户安装了淘宝APP),而不是浏览器广告。*指纹识别(统一API)
6.0以前手机厂商自己研发(良莠不齐),6.0以后Android提供API,厂商只需要提供硬件支持即可。- 应用权限管理:运行时权限
*5.0以前,只需要在manifest清单文件中注册声明即可;
5.0以后,用户可以在安装时关闭某些权限;
6.0及以后,对于一些隐私权限会在第一时间提示用户是否授权(类Iphone);*
运行时权限开发应用
Android6.0对权限进行了分类,分为:
1. Normal Premission:普通权限
2. Dangerous Permission/Group: 危险权限/组
*危险权限分组:比如当用户授予应用读sdk权限,则该应用同时拥有写的权限,而不会再次询问用户*
新增API
- ContextCompact.checkSelfPermission() 检测是否拥有权限
- ActivityCompact.requestPermission() 申请授权
- onRequestPermissionsResult() 用户是否授权
- ActivityCompat.shouldShowRequestPermissionRationale() 权限解释(用户拒绝后出现)
使用流程:
- 在manifest清单文件中添加权限(适配6.0以下)
- 检查权限(危险)
- 申请授权
危险权限查看:
- 官网查看
- 命令行查看:控制台输入下面命令即可查看危险权限组
adb shell pm list permissions -d -g
- 1
下面是危险权限组:
group:android.permission-group.CONTACTS permission:android.permission.WRITE_CONTACTS permission:android.permission.GET_ACCOUNTS permission:android.permission.READ_CONTACTSgroup: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_VOICEMAILgroup:android.permission-group.CALENDAR permission:android.permission.READ_CALENDAR permission:android.permission.WRITE_CALENDARgroup:android.permission-group.CAMERA permission:android.permission.CAMERAgroup:android.permission-group.SENSORS permission:android.permission.BODY_SENSORSgroup:android.permission-group.LOCATION permission:android.permission.ACCESS_FINE_LOCATION permission:android.permission.ACCESS_COARSE_LOCATIONgroup:android.permission-group.STORAGE permission:android.permission.READ_EXTERNAL_STORAGE permission:android.permission.WRITE_EXTERNAL_STORAGEgroup:android.permission-group.MICROPHONE permission:android.permission.RECORD_AUDIOgroup: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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
下面是正常权限:
ACCESS_LOCATION_EXTRA_COMMANDSACCESS_NETWORK_STATEACCESS_NOTIFICATION_POLICYACCESS_WIFI_STATEBLUETOOTHBLUETOOTH_ADMINBROADCAST_STICKYCHANGE_NETWORK_STATECHANGE_WIFI_MULTICAST_STATECHANGE_WIFI_STATEDISABLE_KEYGUARDEXPAND_STATUS_BARGET_PACKAGE_SIZEINSTALL_SHORTCUTINTERNETKILL_BACKGROUND_PROCESSESMODIFY_AUDIO_SETTINGSNFCREAD_SYNC_SETTINGSREAD_SYNC_STATSRECEIVE_BOOT_COMPLETEDREORDER_TASKSREQUEST_INSTALL_PACKAGESSET_ALARMSET_TIME_ZONESET_WALLPAPERSET_WALLPAPER_HINTSTRANSMIT_IRUNINSTALL_SHORTCUTUSE_FINGERPRINTVIBRATEWAKE_LOCKWRITE_SYNC_SETTINGS
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
代码实战:读写SD卡和拨打电话权限
- 首先在清单文件中添加:
<uses-permission android:name="android.permission.CALL_PHONE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- 1
- 2
- 3
- 4
6.0以前,我们可以直接在点击事件里调用下面的代码实现拨打电话的功能:
startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+10086)));
- 1
6.0以后这样写不行,程序会闪退,报一下错误,我们可以专门写一个方法来实现:
首先我们可以把拨打电话的代码进行封装:
/** * 通过隐式Intent去拨打电话 */ private void doCallPhone() { startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+10086))); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
在AndroidStudio中doCallPhone()方法里面的代码会被划上红色波浪线,不要担心,这里并不影响编译和运行,只是提示你这里有危险权限需要检查是否授权。
然后需要检查是否授权,有授权就可以直接拨打电话,如果没有就需要申请授权。
/** * 6.0后拨打电话 */ private void callPhone(){ //当没有授权时 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)!= PackageManager.PERMISSION_GRANTED){ //申请权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE},1); }else { doCallPhone(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
在申请授权时requestPermission()方法的第二个参数可以同时申请多个权限,第三个参数是请求码。
在没有授权的情况下只是申请授权是不够的,还需要监测申请授权是否成功,成功就可以直接调用拨打电话的doCallPhone()方法,不成功提示用户或者其他逻辑,下面我们来看代码:
/** * 处理申请授权是否成功 * @param requestCode 请求码 * @param permissions 权限数组 * @param grantResults 授权结果数组 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode){ case 1: //打电话权限回调 if (grantResults[0]==PackageManager.PERMISSION_GRANTED){ doCallPhone(); }else { //提示用户权限未被授予 Log.d("MainActivity","未授予拨打电话权限"); } break; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
由于前面只有一个权限的申请,所以就只使用了grantResults[0],如果是多个权限可以使用foreach遍历,具体写法下面的封装中会提及;至此,一个拨打电话的授权就介绍了。如果大家觉得授权很麻烦,目前可以暂时修改app的buildgradle配置文件中targetSdkVersion为小于23即可,而编译版本可以不变,如下:
android { compileSdkVersion 25 buildToolsVersion "25.0.0" defaultConfig { applicationId "com.jack.justforandroid6" minSdkVersion 15 targetSdkVersion 22 versionCode 1 versionName "1.0" } ...}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
当然这只是懒方法,躲得了初一,躲不过十五,所以有眼光的攻城狮们,会为了我们的应用有更顽强的生命力,也是要顺应时代趋势,坚定地进行运行时权限的适配。
这里只是一个授权申请就写了这么多代码,那当有很多权限需要用户授权呢?
那接下来我们就来封装授权逻辑。
在项目开发中,我们的Activity一般都是继承自BaseActivity,那么我们的运行时权限是否能放到BaseActivity中呢?
Why not ?
那么接下我们就来实践下:
既然每次我们都要判断每一个危险权限是否被授权,那我们就在BaseActivity封装一个方法来判断某权限是否已经授权,如下
/** * 判断是否已经授权 * @param permissions 权限数组(String...就是数组类型) * @return */ public boolean hasPermission(String... permissions){ for (String permission:permissions){ if (ContextCompat.checkSelfPermission(this, permission)!= PackageManager.PERMISSION_GRANTED){ return false; } } return true; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
然后就是没有授权时申请权限了,我们来写个常量类用作申请授权的请求码:
/** * 权限常量相关 * Created by Jack on 16/12/1. */public class Constants { //读SD卡权限请求码 public static final int WRITE_EXTERNAL_CARD=0x01; //写SD卡权限请求码 public static final int READ_EXTERNAL_CARD=0x01; //写打电话权限请求码 public static final int CALL_PHONE_CARD=0x02;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
接着我们来实现申请权限的封装:
/** * 权限申请方法 */ public void requestPermission(int code,String... permissions){ ActivityCompat.requestPermissions(this, permissions,code); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
在这里申请权限后就是要监听用户是否授予权限了,来看下如何封装:
/** * 授权回调处理 * @param requestCode * @param permissions * @param grantResults */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (checkPermissionResult(grantResults)) { switch (requestCode) { case Constants.WRITE_EXTERNAL_CARD: //处理写sd卡授权回调 doWriteExternalCard(); break; case Constants.CALL_PHONE_CARD: //处理写sd卡授权回调 doCallPhone(); break; } }else { Toast.makeText(getApplicationContext(), "权限已拒绝", Toast.LENGTH_SHORT).show(); } } /** * 检测请求结果码判定是否授权 * @param grantResults * @return */ private boolean checkPermissionResult(int[] grantResults) { if (grantResults!=null) { for (int result : grantResults) { if (result==PackageManager.PERMISSION_GRANTED){ return true; } } } return false; } /**
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
可以看到这里我们首先判断用户是否授予了我们权限,然后再通过请求码区分不同的权限请求,然后调用了一个空方法,等待子类去重写。这里为什么用空方法呢,在BaseActivity我们无法预知具体的授权逻辑,所以在BaseActivity中只是一些空方法,当然如果业务允许,也是可以执行一些逻辑,子类中调用super.doCallPhone()(其他方法同理)方法就好了然后在子类中重写就好了,看代码:
/** * 默认的打电话逻辑 */ public void doCallPhone() { //这里父类并没有执行任何逻辑,但可以加一些通用的逻辑,然后让子类去重写 }
- 1
- 2
- 3
- 4
- 5
- 6
那么接下就是看集成自BaseActivity的Activity中如何调用、如何重写来完成运行时权限的适配了:在点击事件中调用拨打电话的逻辑判定和实现;
/** * 拨打电话 */ private void callPhone(){ if (hasPermission(Manifest.permission.CALL_PHONE)){ doCallPhone(); }else { requestPermission(Constants.CALL_PHONE_CARD,Manifest.permission.CALL_PHONE); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如上代码:首先就是调用BaseActivity判断是否已经拥有权限,如果有授权就执行通过隐式Intent启动拨打电话程序,否则申请用户授权。
因为父类已经实现了onRequestPermissionsResult()的回调,所以子类就只需要重写父类的doCallPhone()方法,然后去具体实现打电话的逻辑:
/** * 子类具体去实现打电话的逻辑 */ @Override public void doCallPhone() { startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+10086))); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
至此,我们所有的封装都完成的了,相信大家看过这篇博客心中就有思路了,遇到Android6.0就再不慌了。
这里我们没有使用任何第三方库,自己封装完成所有运行时权限的逻辑,当然现在也有封装的很好的第三方库,例如:PremissionGen,AndPremission,但是PremissionGen的在监听用户是否授权时对失败的回调没有成功,不知什么情况,有兴趣的朋友可以去了解下,但是逻辑他就是这么个逻辑,理就是这么个理,你弄懂了这个理,就可以直接去使用第三方库了。
- Android6.0权限,如何封装处理授权问题
- Android6.0权限处理封装
- Android6.0权限问题处理
- Android6.0权限处理问题
- Android6.0权限封装
- Android6.0权限封装
- Android6.0运行时权限处理-超简单封装
- android6.0的权限处理(封装版)
- Android6.0 权限处理
- Android6.0权限处理
- Android6.0 权限处理
- Android6.0 权限申请封装
- Android6.0权限封装使用
- android6.0权限问题
- Android6.0权限问题
- Android6.0权限问题
- android6.0权限问题
- Android6.0权限问题
- Java多线程(五):Timer和TimerTask
- 【LeetCode】刷题-esay
- 无人机驾驶员培训学习记录(一)
- 2-2 Time类的定义
- History API 使用指北
- Android6.0权限,如何封装处理授权问题
- xgboost安装教程,可用
- Win10使用SublimeText3代替Arduino IDE开发Arduino程序
- 东野圭吾《梦幻花》读后感
- 云数据库MongoDB版使用教程
- 剑指offer 16 反转链表
- 如何看待机器视觉的“对抗样本”问题,其原理是什么?
- IOS学习 Sqlite索引
- ie8兼容问题(二) select文字垂直居中问题