Android6.0权限适配
来源:互联网 发布:数据挖掘要求英语吗 编辑:程序博客网 时间:2024/05/16 09:09
Google在Android 6.0 上开始原生支持应用权限管理,再不是安装应用时的一刀切,很多权限需要在需要时实时请求,如果你的应用还没有做好6.0以上权限的适配,那么需要先限制targetSdkVersion在22及以下
当你做好处理, 就可以设置到22以上了,那么需要做哪些处理呢,首先我们得知道,哪些权限需要实时请求
Android的权限分为三类:
- 普通权限(Normal Permissions)
- 危险权限(Dangerous Permissions)
- 特殊权限(Special Permissions)
android.permission-group.CALENDAR(日历数据)
android.permission.READ_CALENDAR
android.permission.WRITE_CALENDAR
android.permission-group.CAMERA(相机)
android.permission.CAMERA
android.permission-group.CONTACTS(联系人)
android.permission.READ_CONTACTS
android.permission.WRITE_CONTACTS
android.permission.GET_ACCOUNTS
android.permission-group.LOCATION(位置)
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION
android.permission-group.MICROPHONE(麦克风)
android.permission.RECORD_AUDIO
android.permission-group.PHONE(电话)
android.permission.READ_PHONE_STATE
android.permission.CALL_PHONE
android.permission.READ_CALL_LOG
android.permission.WRITE_CALL_LOG
com.android.voicemail.permission.ADD_VOICEMAIL
android.permission.USE_SIP
android.permission.PROCESS_OUTGOING_CALLS
android.permission-group.SENSORS(传感器)
android.permission.BODY_SENSORS
android.permission-group.SMS(短信)
android.permission.SEND_SMS
android.permission.RECEIVE_SMS
android.permission.READ_SMS
android.permission.RECEIVE_WAP_PUSH
android.permission.RECEIVE_MMS
android.permission.READ_CELL_BROADCASTS
android.permission-group.STORAGE(存储)
android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE
比如,在应用中申请READ_EXTERNAL_STORAGE
权限,用户同意授权后,则应用同时具有READ_EXTERNAL_STORAGE
和 WRITE_EXTERNAL_STORAGE
权限
切记,危险权限除了需要动态申请,也还是需要在Manifest中声明的
特殊权限
看权限名就知道特殊权限比危险权限更危险,特殊权限
需要在manifest中申请并且通过发送Intent让用户在设置界面进行勾选.
特殊权限申请方式:
SYSTEM_ALERT_WINDOW
12345678910111213141516
private static final int REQUEST_CODE = 1;private void requestAlertWindowPermission() {Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);intent.setData(Uri.parse("package:" + getPackageName()));startActivityForResult(intent, REQUEST_CODE);}protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == REQUEST_CODE) {if (Settings.canDrawOverlays(this)) {Log.i(LOGTAG, "onActivityResult granted");}}}
WRITE_SETTINGS
12345678910111213141516
private static final int REQUEST_CODE_WRITE_SETTINGS = 2;private void requestWriteSettings() {Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);intent.setData(Uri.parse("package:" + getPackageName()));startActivityForResult(intent, REQUEST_CODE_WRITE_SETTINGS );}protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == REQUEST_CODE_WRITE_SETTINGS) {if (Settings.System.canWrite(this)) {Log.i(LOGTAG, "onActivityResult write settings granted" );}}}
如果永远不将targetSdkVersion设置到22以上是不是就没事了?错,如果用户去权限中心禁用了(当然一般用户不会去这么做),他会让你运行到对应代码时直接崩溃
更何况有很多手机会在应用运行时一个个权限弹出来帮你申请,用户手一滑或者无法理解时一禁用,你就杯具了,所以还是得处理
如何开始动态申请权限
首先我们得知道有哪些方法
ContextCompat.checkSelfPermission(Context context,String permission) //判断权限是否具有某项权限
ActivityCompat.requestPermissions(Activity activity,String[] permissions,int requestCode)//申请权限
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)//申请权限回调方法,在Activity或Fragment重写
ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission)//是否要提示用户申请该权限的缘由
有了这几个方法之后,我们需要整理一下我们对权限申请的流程是个什么样子的安排
你说请求权限时的不再提示是否要处理?不用了,用户第一次拒绝了之后就可以给用户提示了,为什么要等第二次
那么流程有了之后就是代码了
首先是对权限检查以及申请的工具类
PermissionUtil
/** * Created by yangjh on 2017/3/10. * 这个类用于6.0以上权限的处理 */public class PermissionUtil { private final String TAG = "PermissionUtil"; private int REQUEST_CODE_PERMISSION = 0x00099; /** * 请求权限 * * @param permissions 请求的权限 * @param requestCode 请求权限的请求码 */ public boolean requestPermission(String[] permissions, int requestCode,Activity activity) { this.REQUEST_CODE_PERMISSION = requestCode; //检查是否具有一些权限 if (checkPermissions(permissions,activity)) { permissionSuccess(REQUEST_CODE_PERMISSION); return true; } else {//发现有权限未申请到,则准备发出申请 //获取未申请到的权限列表 List<String> needPermissions = getDeniedPermissions(permissions,activity); //发出权限申请 ActivityCompat.requestPermissions(activity, needPermissions.toArray(new String[needPermissions.size()]), REQUEST_CODE_PERMISSION); return false; } } /** * 系统请求权限回调,返回TRUE表示权限都通过了不需要处理 * 返回FALSE表示有未通过的需要提示处理 * * @param requestCode * @param permissions * @param grantResults */ public boolean onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == REQUEST_CODE_PERMISSION) { //确认所有权限是否都已授权 if (verifyPermissions(grantResults)) { permissionSuccess(REQUEST_CODE_PERMISSION); return true; } else {//发现有没有授权的 permissionFail(REQUEST_CODE_PERMISSION);// showTipsDialog(); return false; } } return true; } /** * 检测所有的权限是否都已授权 * * @param permissions * @return */ private boolean checkPermissions(String[] permissions,Activity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { return true; } for (String permission : permissions) { if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } /** * 确认所有的权限是否都已授权 * * @param grantResults * @return */ private boolean verifyPermissions(int[] grantResults) { for (int grantResult : grantResults) { if (grantResult != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } /** * 获取需要申请权限的列表 * * @param permissions * @return */ private List<String> getDeniedPermissions(String[] permissions,Activity activity) { List<String> needRequestPermissionList = new ArrayList<>(); for (String permission : permissions) { //发现这条权限没有获取到权限,或者系统认为需要提示用户申请该权限的缘由时 if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED || ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) { //添加需要提示的权限进集合 needRequestPermissionList.add(permission); } } return needRequestPermissionList; } /** * 获取权限成功 * * @param requestCode */ public void permissionSuccess(int requestCode) { Log.d(TAG, "获取权限成功=" + requestCode); } /** * 权限获取失败 * @param requestCode */ public void permissionFail(int requestCode) { Log.d(TAG, "获取权限失败=" + requestCode); }}
然后是对权限申请的逻辑的组织类:
PermissionApply
/** * Created by yangjh on 2017/3/10. * 权限申请的入口类,负责申请对应的权限以及权限申请成功时候后的处理 * 这里有一种情况目前没有处理,就是比如: * 先申请电话权限,然后在还没得到结果时又申请SD卡权限,此时会导致检查权限申请状况时,电话权限检查不到,所以不要这样申请 */public class PermissionApply { private PermissionUtil permissionUtil; private Activity mActivity; HashMap<Integer,OnPermissResponse> permissionResponses = new HashMap<Integer,OnPermissResponse>(); public PermissionApply(Activity activity){ mActivity = activity; permissionUtil = new PermissionUtil(); } /** * 请求电话权限 */ public void requestPhonePermission(OnPermissResponse permissionRes){ permissionResponses.put(REQUEST_CALL_PHONE,permissionRes); if(permissionUtil.requestPermission(new String[]{PERMISSION_CALL_PHONE}, REQUEST_CALL_PHONE,mActivity)){ callBack(REQUEST_CALL_PHONE); } } /** * 请求SD卡权限 */ public void requestSDCardPermission(OnPermissResponse permissionRes){ permissionResponses.put(REQUEST_WRITE_EXTERNAL_STORAGE,permissionRes); if(permissionUtil.requestPermission(new String[]{PERMISSION_WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_EXTERNAL_STORAGE,mActivity)){ callBack(REQUEST_WRITE_EXTERNAL_STORAGE); } } /** * 请求相机权限 */ public void requestCameraPermission(OnPermissResponse permissionRes){ permissionResponses.put(REQUEST_CAMERA,permissionRes); if(permissionUtil.requestPermission(new String[]{PERMISSION_CAMERA}, REQUEST_CAMERA,mActivity)){ callBack(REQUEST_CAMERA); } } /** * 请求联系人权限 */ public void requestContactsPermission(OnPermissResponse permissionRes){ permissionResponses.put(REQUEST_CONTACTS,permissionRes); if(permissionUtil.requestPermission(new String[]{PERMISSION_CONTACTS}, REQUEST_CONTACTS,mActivity)){ callBack(REQUEST_CONTACTS); } } /** * 请求日历权限 */ public void requestCalendarPermission(OnPermissResponse permissionRes){ permissionResponses.put(REQUEST_CALENDAR,permissionRes); if(permissionUtil.requestPermission(new String[]{PERMISSION_CALENDAR}, REQUEST_CALENDAR,mActivity)){ callBack(REQUEST_CALENDAR); } } /** * 请求地理(GPS)权限 */ public void requestLocationPermission(OnPermissResponse permissionRes){ permissionResponses.put(REQUEST_LOCATION,permissionRes); if(permissionUtil.requestPermission(new String[]{PERMISSION_LOCATION}, REQUEST_LOCATION,mActivity)){ callBack(REQUEST_LOCATION); } } /** * 请求麦克风权限 */ public void requestMicrophonePermission(OnPermissResponse permissionRes){ permissionResponses.put(REQUEST_MICROPHONE,permissionRes); if(permissionUtil.requestPermission(new String[]{PERMISSION_MICROPHONE}, REQUEST_MICROPHONE,mActivity)){ callBack(REQUEST_MICROPHONE); } } /** * 请求传感器权限 */ public void requestSensorsPermission(OnPermissResponse permissionRes){ permissionResponses.put(REQUEST_SENSORS,permissionRes); if(permissionUtil.requestPermission(new String[]{PERMISSION_SENSORS}, REQUEST_SENSORS,mActivity)){ callBack(REQUEST_SENSORS); } } /** * 请求短信权限 */ public void requestSmsPermission(OnPermissResponse permissionRes){ permissionResponses.put(REQUEST_SMS,permissionRes); if(permissionUtil.requestPermission(new String[]{PERMISSION_SMS}, REQUEST_SMS,mActivity)){ callBack(REQUEST_SMS); } } /** * 接收权限请求的结果 * @param requestCode * @param permissions * @param grantResults */ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){ boolean success = permissionUtil.onRequestPermissionsResult(requestCode,permissions,grantResults); if(!success){//没有成功就打开设置页面 showTipsDialog(); }else{ callBack(requestCode); } } private void callBack(int requestCode){ OnPermissResponse response = permissionResponses.get(requestCode); if(null != response){ response.onPermissionSuccess(); } } /** * 显示提示对话框 */ private void showTipsDialog() { new AlertDialog.Builder(mActivity) .setTitle("提示信息") .setMessage("当前应用缺少必要权限,该功能暂时无法使用。如若需要,请单击【确定】按钮前往设置中心进行权限授权。") .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }) .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startAppSettings(); } }).show(); } /** * 启动当前应用设置页面 */ private void startAppSettings() { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.parse("package:" + mActivity.getPackageName())); mActivity.startActivity(intent); } public interface OnPermissResponse{ public abstract void onPermissionSuccess(); } //请求电话方面的权限 private static final String PERMISSION_CALL_PHONE = Manifest.permission.CALL_PHONE; private static final int REQUEST_CALL_PHONE = 0x0001; //SD卡读取写入权限 private static final String PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE; private static final int REQUEST_WRITE_EXTERNAL_STORAGE = 0x0002; //相机 private static final String PERMISSION_CAMERA = Manifest.permission.CAMERA; private static final int REQUEST_CAMERA = 0x0003; //读取联系人 private static final String PERMISSION_CONTACTS = Manifest.permission.READ_CONTACTS; private static final int REQUEST_CONTACTS = 0x0004; //日历 private static final String PERMISSION_CALENDAR = Manifest.permission.READ_CALENDAR; private static final int REQUEST_CALENDAR = 0x0005; //GPS private static final String PERMISSION_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION; private static final int REQUEST_LOCATION = 0x0006; //麦克风 private static final String PERMISSION_MICROPHONE = Manifest.permission.RECORD_AUDIO; private static final int REQUEST_MICROPHONE = 0x0007; //传感器 private static final String PERMISSION_SENSORS = Manifest.permission.BODY_SENSORS; private static final int REQUEST_SENSORS = 0x0008; //短信 private static final String PERMISSION_SMS = Manifest.permission.READ_SMS; private static final int REQUEST_SMS = 0x0009;}
这两个类就足够了,然后是调用的示例:
/** * Created by yangjh on 2017/3/9. */public class ActivityS extends Activity { PermissionApply apply; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_main2); apply = new PermissionApply(this); ImageView img1 = (ImageView)findViewById(R.id.img1); img1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { apply.requestPhonePermission(new PermissionApply.OnPermissResponse() { @Override public void onPermissionSuccess() { Intent callIntent = new Intent(Intent.ACTION_CALL); callIntent.setData(Uri.parse("tel:10086")); callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(callIntent); } }); } }); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); apply.onRequestPermissionsResult(requestCode,permissions,grantResults); }}
至此,权限的封装就结束了
- Android6.0权限适配
- Android6.0权限适配
- Android6.0权限适配
- Android6.0权限适配
- Android6.0权限适配
- Android6.0权限适配
- Android6.0权限适配
- Android6.0权限适配
- Android6.0权限适配
- Android6.0权限适配实践
- Android6.0运行时候权限适配
- android6.0权限适配RxPermissions
- Android6.0运行时权限适配
- Android6.0权限适配的那些坑
- 关于Android6.0权限适配的问题
- Android6.0后权限适配,参考地址
- Android6.0权限开发
- Android6.0权限管理
- C#语音播放引擎cscore及其播放器
- 连号区间数
- DUTOJ-1084(二分答案)
- hdu 5536 Chip Factory 01 Trie
- 算法训练 表达式计算
- Android6.0权限适配
- Java多线程基础
- 用JavaScript实现图片剪切效果
- android_File
- android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析
- ZCMU—B
- Java中进程与线程
- 华为oj初级 查找组成一个偶数最接近的两个素数
- Linux Kernel设备驱动模型之总线查找设备