适配android6.0:运行时权限检查机制

2024-06-04 16:58

本文主要是介绍适配android6.0:运行时权限检查机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

清明放假终于结束了,赶紧写点东西来脉动回来。这是一篇偏概念性的文章,文字偏多,所以别捉急,慢慢看。

现在高版本的android系统市场占有率提升的非常快,这依赖于智能手机越来越便宜,越来越普遍,新手机一般都会搭载高版本的android系统,来丰富用户的体验,但是也逐渐的暴露出了很多的问题,最严重的就是用户的安全问题。

之前很多应用会申请很多的权限,尤其是第三方sdk,我们也不知道到底他们要用这些权限做什么,只要把权限写到配置文件中,系统就默许了权限。

Google发现了这会给用户造成非常大的困扰和安全问题,例如app随意的读取手机的联系人,获取用户的地理位置等等,于是在Android 6.0 开始了新的权限机制:运行时检查,不再默认权限行为。这也是对开发者影响最大的一点,那么如果适配android 6.0呢?

正文

运行时权限检查机制

在app运行时,使用了敏感权限,会提示用户是否要授予这个app对应的权限,用户有拒绝和同意的权利,如果拒绝最好要提示用户,拒绝会造成什么样的影响,这样用户能明白申请的原因,重新授予权限。

哪些是敏感权限

<!-- CALENDAR 日历组 --><uses-permission android:name="android.permission.READ_CALENDAR" /><uses-permission android:name="android.permission.WRITE_CALENDAR" /><!-- CAMERA 相机拍照组 --><uses-permission android:name="android.permission.CAMERA" /><!-- CONTACTS 联系人组 --><uses-permission android:name="android.permission.READ_CONTACTS" /><uses-permission android:name="android.permission.WRITE_CONTACTS" /><uses-permission android:name="android.permission.GET_ACCOUNTS" /><!-- LOCATION 定位组 --><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><!-- MICROPHONE 麦克风组 --><uses-permission android:name="android.permission.RECORD_AUDIO" /><!-- PHONE 组 --><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.CALL_PHONE" /><uses-permission android:name="android.permission.READ_CALL_LOG" /><uses-permission android:name="android.permission.WRITE_CALL_LOG" /><uses-permission android:name="android.permission.USE_SIP" /><uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /><!-- SENSORS 传感器组 --><uses-permission android:name="android.permission.BODY_SENSORS" /><!-- SMS 组 --><uses-permission android:name="android.permission.SEND_SMS" /><uses-permission android:name="android.permission.RECEIVE_SMS" /><uses-permission android:name="android.permission.READ_SMS" /><uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" /><uses-permission android:name="android.permission.RECEIVE_MMS" /><!-- STORAGE 存储组 --><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

这是从别处复制过来的,看的出来只要是和用户相关的权限,几乎都属于敏感权限,值得注意的是有些权限,部分手机已经进行了优化,例如我使用的360手机,读写sd卡权限就是默许的,如果你也遇到了这个情况,也不用惊讶。

如何申请权限

android 6.0 把权限的申请和回执有两处:Activity和Fragment。其他的地方目前不可以。申请的方法:

 // 检查是否应被授权
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {// 已经被授权,直接进行操作
} else {// 没有授权,需要进行授权申请// Context  申请的权限   申请的请求码ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, 0);
}

先检查是否已经授予了权限,如果没有就去申请权限。处理结果在:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {switch(requestCode){case 0:// 处理用户授权的返回结果if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {} else {// 授权失败}break;default:break;}
}

这样整个授权流程就弄清楚了,两个api,重写onRequestPermissionsResult。那么问题来了,如果直接在Activity中申请权限还好一点,如果是原来的Dialog里呢?

接口式开发

这个概念已经是老朋友了,而且我们也经常用,例如自定义View,在onClick调用自定义的点击接口,这就是接口式开发,把实际的功能实现交给其他人,控件本身作为一个媒介。

android 6.0很明显是希望用户改变原来的习惯,或者说是规范编码习惯,例如,有些Dialog的代码非常的庞大,有10个按钮,Dialog里就会有10个功能逻辑,典型的就是第三方分享(按钮真心多啊)。

Dialog大概就是对话框的意思,从概念上就能感受到,他是一个很轻量的东西,就跟跑腿的一样,老板说问问客人要吃啥,服务员问完客人在回来告诉老板,老板知道结果后,就给客人做什么。

写一个小Demo

只贴一下MainActivity的代码把:

public class MainActivity extends AppCompatActivity implements TipDialog.OnTipDialogButtonOnClickListener {private static final String PERMISSION = Manifest.permission.CAMERA;private ConstraintLayout container;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);container = (ConstraintLayout) findViewById(R.id.container);findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {TipDialog tipDialog = new TipDialog(MainActivity.this);tipDialog.setTitle("是否打开摄像头");tipDialog.setOnTipDialogButtonOnClickListener(MainActivity.this);tipDialog.show();}});}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {switch (requestCode) {case 0:// 处理用户授权的返回结果if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {openCamera();} else {// 授权失败Toast.makeText(MainActivity.this, "未授予摄像头权限,无法使用", Toast.LENGTH_SHORT).show();}break;default:break;}}@Overridepublic void onTipDialogCancelButtonClick(TipDialog dialog) {dialog.dismiss();}@Overridepublic void onTipDialogSureButtonClick(TipDialog dialog) {dialog.dismiss();openCamera();}private void openCamera() {// 检查是否应被授权if (ContextCompat.checkSelfPermission(MainActivity.this, PERMISSION) != PackageManager.PERMISSION_GRANTED) {
//            // 没有授权,需要进行授权申请
//            // Context  申请的权限   申请的请求码ActivityCompat.requestPermissions(MainActivity.this, new String[]{PERMISSION}, 0);} else {container.addView(new FlashLightSurfaceView(this), 0, 0);}}
}

这个demo 非常简单,首先我自定义了一个FlashLightSurfaceView,他里面打开了Camera,使用摄像头前判断权限,没有的话申请权限,被拒绝就提示没有权限无法使用。

强调一点:onRequestPermissionsResult只能回调这个Activity发起的权限申请(requestPermissions)。

但是这个demo却没有什么代表性,因为他只能在原生android运行正常,例如模拟器,但是真机就很难说了。

真机运行情况

已经有很多朋友已经踩过这个坑了,由于了国内产商都对系统进行了定制,我发现对权限这部分影响真的是太大了,我遇到主要有以下几种情况:

1、仅仅是申请权限,但是当时没有使用到权限对应的Api,不会弹出权限申请窗口。

2、当使用到对应权限的API,app会自动申请权限,弹出权限申请窗口,而这个申请结果我们是无法通过onRequestPermissionsResult来获取结果的。

3、如果直接拒绝了权限申请,仍然返回PackageManager.PERMISSION_GRANTED。

是不是很尴尬?整个权限流程已经被蹂躏的惨不忍睹,这还怎么接着搞事情?

解决办法

我目前发现的最好的办法就是 try-catch,使用了没有权限的API,系统就会报错甚至崩溃,那我就直接在外围加上try-catch,如果抛出了问题,百分之八十都是权限的问题,那么修改一下:

@Overridepublic void surfaceCreated(SurfaceHolder surfaceHolder) {try {if (camera == null) {int count = Camera.getNumberOfCameras();if (count > 0) {camera = Camera.open();camera.setPreviewDisplay(holder);} else {Toast.makeText(getContext(), "没有找到摄像头...", Toast.LENGTH_SHORT).show();}}} catch (Exception e) {if (camera != null)camera.release();camera = null;Toast.makeText(getContext(), "未授予摄像头权限,无法使用", Toast.LENGTH_SHORT).show();}}

总结

android6.0 的权限运行机制是好的,但是没想到会变成目前这么乱套的情况,给我们的适配也增加了很大的难度。目前流行的各大厂商可能也有自己的考虑,把权限这一块似乎都想把控在自己的手里,造成这样的局面,也是很尴尬。

虽然通过一些小手段可以暂时弥补,但是最关键的还是希望各位厂商大大们还是尽量保持原生的权限机智吧…

ok,那就到这里了,如果你有更好的解决android 6.0的权限适配的问题,请留下您的技巧,让大家共同进步。

Demo下载地址,仅供参考

补充

忘了强调一个细节,在申请权限的时候,不能申请Manifest.permission_group.xxxx,否则是不会弹出权限申请的提示的。你要问我为啥,我只能猜测,设计者更希望你只申请一个,而不是一组…

这篇关于适配android6.0:运行时权限检查机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1030581

相关文章

Spring Boot项目打包和运行的操作方法

《SpringBoot项目打包和运行的操作方法》SpringBoot应用内嵌了Web服务器,所以基于SpringBoot开发的web应用也可以独立运行,无须部署到其他Web服务器中,下面以打包dem... 目录一、打包为JAR包并运行1.打包为可执行的 JAR 包2.运行 JAR 包二、打包为WAR包并运行

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构

JVM垃圾回收机制之GC解读

《JVM垃圾回收机制之GC解读》:本文主要介绍JVM垃圾回收机制之GC,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、死亡对象的判断算法1.1 引用计数算法1.2 可达性分析算法二、垃圾回收算法2.1 标记-清除算法2.2 复制算法2.3 标记-整理算法2.4

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

Python如何精准判断某个进程是否在运行

《Python如何精准判断某个进程是否在运行》这篇文章主要为大家详细介绍了Python如何精准判断某个进程是否在运行,本文为大家整理了3种方法并进行了对比,有需要的小伙伴可以跟随小编一起学习一下... 目录一、为什么需要判断进程是否存在二、方法1:用psutil库(推荐)三、方法2:用os.system调用

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Spring Security+JWT如何实现前后端分离权限控制

《SpringSecurity+JWT如何实现前后端分离权限控制》本篇将手把手教你用SpringSecurity+JWT搭建一套完整的登录认证与权限控制体系,具有很好的参考价值,希望对大家... 目录Spring Security+JWT实现前后端分离权限控制实战一、为什么要用 JWT?二、JWT 基本结构

Python运行中频繁出现Restart提示的解决办法

《Python运行中频繁出现Restart提示的解决办法》在编程的世界里,遇到各种奇怪的问题是家常便饭,但是,当你的Python程序在运行过程中频繁出现“Restart”提示时,这可能不仅仅是令人头疼... 目录问题描述代码示例无限循环递归调用内存泄漏解决方案1. 检查代码逻辑无限循环递归调用内存泄漏2.

SpringRetry重试机制之@Retryable注解与重试策略详解

《SpringRetry重试机制之@Retryable注解与重试策略详解》本文将详细介绍SpringRetry的重试机制,特别是@Retryable注解的使用及各种重试策略的配置,帮助开发者构建更加健... 目录引言一、SpringRetry基础知识二、启用SpringRetry三、@Retryable注解

SpringKafka错误处理(重试机制与死信队列)

《SpringKafka错误处理(重试机制与死信队列)》SpringKafka提供了全面的错误处理机制,通过灵活的重试策略和死信队列处理,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、Spring Kafka错误处理基础二、配置重试机制三、死信队列实现四、特定异常的处理策略五