Android 运行时权限处理解析

android GrantPermissionsActivity 详解 存在的意义: <activity android:name=".permission.ui.GrantPermissionsActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:excludeFromRecen... 阅读详情

一.Android6.0权限改变

1. Android6.0版本之前的权限是写在配置文件AndroidManifest.xml中的,Android app在安装的时候Android系统检测配置文件的权限给用户提示app需要的权限,用户可以点击接受和拒绝。但是这种方式用户在Androidapp的时候并不知道这个权限用在哪里有啥危害。于是Android6.0开始改变权限申请的方式,出现了权限组和动态申请权限。

2.从设计来看我们可以想象设计一套这样的功能。一般需要定义一套权限规则,二设计一套权限检测的方法把用户定义的权限解析以及用户申请权限的方法,三设计一个用户操作权限的授权的功能,第四设计一套权限存储更新的功能。这样想就和服务器一样的功能用户需要什么功能通过协议去请求检测这样的功能是不是满足需要功能的权限。

3.从系统底层来看。我们看源码的地址是:http://androidxref.com/9.0.0_r3/xref/frameworks/

从系统源码来看我们可以从上面的功能分析设计上来找对应的模块。权限定义模块,权限检测模块,用户授权模块,权限存储。

1.权限定义模块

http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/res/AndroidManifest.xml

687    <!-- Allows an application to send SMS messages.
688         <p>Protection level: dangerous
689    -->
690    <permission android:name="android.permission.SEND_SMS"
691        android:permissionGroup="android.permission-group.SMS"
692        android:label="@string/permlab_sendSms"
693        android:description="@string/permdesc_sendSms"
694        android:permissionFlags="costsMoney"
695        android:protectionLevel="dangerous" />
696
697    <!-- Allows an application to receive SMS messages.
698         <p>Protection level: dangerous
699    -->
700    <permission android:name="android.permission.RECEIVE_SMS"
701        android:permissionGroup="android.permission-group.SMS"
702        android:label="@string/permlab_receiveSms"
703        android:description="@string/permdesc_receiveSms"
704        android:protectionLevel="dangerous"/>
705
706    <!-- Allows an application to read SMS messages.
707         <p>Protection level: dangerous
708    -->
709    <permission android:name="android.permission.READ_SMS"
710        android:permissionGroup="android.permission-group.SMS"
711        android:label="@string/permlab_readSms"
712        android:description="@string/permdesc_readSms"
713        android:protectionLevel="dangerous" />

protectionLevel共有5个选项值分别为signature,system,dangerous,normal,development,简单介绍下这5个值 
System permissions: 表示如果想获取该权限必须为系统应用 

Normal permissions:只需要在AndroidManifest.xml 中声明,如INTERNET,WAKE_LOCK等

Signature permissions:申请该权限的应用和定义该权限的应用有相同签名时,这个权限才会被授予,一些Signature permissions不能被三方应用使用

Dangerous permissions:需要申请运行时权限

Special permissions:如SYSTEM_ALERT_WINDOW需要应用发送Settings.ACTION_MANAGE_OVERLAY_PERMISSION intent去提示用户是否开启该权限

任何一个权限都有自己的所属的权限组。同一组的任何一个权限被授权了,其他权限也自动被授权。

如:android.permission.READ_EXTERNAL_STORAGE和android.permission.WRITE_EXTERNAL_STORAGE都在android.permission-group.STORAGE这个权限组里面,申请权限时同意了组中的一个另一个同时也同意了。

2.权限检测功能模块pms ,用户动态权限检测

 

3.用户权限授权模块GrantPermissionsActivity

https://www.androidos.net.cn/android/6.0.1_r16/xref/packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java

1.系统中定义。

2.调用流程

3.全透明GrantPermissionsActivity源码解析

 

4.权限更新模块

 

5.权限adb命令调试查看:

adb shell dumpsys package + 包名

6.特殊的需求处理。

比如hook住权限调用过程,更改弹窗显示或者拦截显示。

 

二.封装方案

1.通过fragment中带有权限请求和回调的方法进行请求工具封装

1.传入参数

1.上下文  activity 或者fragment

2.请求的权限的列表

3.结果返回后的接口

2.工具封装

1.封装一个请求权限Fragment在fragment中请求

public class PermissionFragment extends Fragment {
    //requestCode
    private static final int PERMISSIONS_REQUEST_CODE = 1;
    private PermissionListener listener;
    public void setListener(PermissionListener listener) {
        this.listener = listener;
    }
    
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @TargetApi(Build.VERSION_CODES.M)
    public void requestPermissions(@NonNull String[] permissions) {
        List<String> requestPermissionList = new ArrayList<>();
        //找出所有未授权的权限
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(getContext(), permission) != PackageManager.PERMISSION_GRANTED) {
                requestPermissionList.add(permission);
            }
        }
        if (requestPermissionList.isEmpty()) {
            //已经全部授权
            permissionAllGranted();
        } else {
            //申请授权
            requestPermissions(requestPermissionList.toArray(new String[requestPermissionList.size()]), PERMISSIONS_REQUEST_CODE);
        }
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode != PERMISSIONS_REQUEST_CODE) {
            return;
        }
        if (grantResults.length > 0) {
            List<String> deniedPermissionList = new ArrayList<>();
            for (int i = 0; i < grantResults.length; i++) {
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                    deniedPermissionList.add(permissions[i]);
                }
            }
            if (deniedPermissionList.isEmpty()) {
                //已经全部授权
                permissionAllGranted();
            } else {
                //勾选了对话框中”Don’t ask again”的选项, 返回false
                for (String deniedPermission : deniedPermissionList) {
                    boolean flag = shouldShowRequestPermissionRationale(deniedPermission);
                    if (!flag) {
                        //拒绝授权
                        permissionShouldShowRationale(deniedPermissionList);
                        return;
                    }
                }
                //拒绝授权
                permissionHasDenied(deniedPermissionList);
            }
        }
    }

    /**
     * 权限全部已经授权
     */
    private void permissionAllGranted() {
        if (listener != null) {
            listener.onGranted();
        }
    }

    /**
     * 权限被拒绝
     *
     * @param deniedList 被拒绝的权限List
     */
    private void permissionHasDenied(List<String> deniedList) {
        if (listener != null) {
            listener.onDenied(deniedList);
        }
    }

    /**
     * 权限被拒绝并且勾选了不在询问
     *
     * @param deniedList 勾选了不在询问的权限List
     */
    private void permissionShouldShowRationale(List<String> deniedList) {
        if (listener != null) {
            listener.onShouldShowRationale(deniedList);
        }
    }
}

2.通过传进来的activity或者fragment上下文生成工具fragment

public class PermissionUtil {
    private static final String TAG = PermissionUtil.class.getSimpleName();
    private PermissionFragment permissionFragment;

    public PermissionUtil(@NonNull FragmentActivity activity) {
        permissionFragment = getRxPermissionsActivity(activity);
    }

    public PermissionUtil(@NonNull Fragment fragment) {
        permissionFragment = getRxPermissionsFragment(fragment);
    }

    private PermissionFragment getRxPermissionsActivity(FragmentActivity activity) {
        PermissionFragment fragment = (PermissionFragment) activity.getSupportFragmentManager().findFragmentByTag(TAG);
        boolean isNewInstance = fragment == null;
        if (isNewInstance) {
            fragment = new PermissionFragment();
            FragmentManager fragmentManager = activity.getSupportFragmentManager();
            fragmentManager.beginTransaction().add(fragment, TAG).commit();
            fragmentManager.executePendingTransactions();
        }
        return fragment;
    }

    private PermissionFragment getRxPermissionsFragment(Fragment activity) {
        PermissionFragment fragment = (PermissionFragment) activity.getChildFragmentManager().findFragmentByTag(TAG);
        boolean isNewInstance = fragment == null;
        if (isNewInstance) {
            fragment = new PermissionFragment();
            FragmentManager fragmentManager = activity.getChildFragmentManager();
            fragmentManager.beginTransaction().add(fragment, TAG).commit();
            fragmentManager.executePendingTransactions();
        }
        return fragment;
    }

    /**
     * 外部使用 申请权限
     *
     * @param permissions 申请授权的权限
     * @param listener    授权回调的监听
     */
    public void requestPermissions(String[] permissions, PermissionListener listener) {
        permissionFragment.setListener(listener);
        permissionFragment.requestPermissions(permissions);
    }

}

3.结果返回

请求结果通过接口设计

public interface PermissionListener {
    void onGranted();
    void onDenied(List<String> deniedPermission);
    void onShouldShowRationale(List<String> deniedPermission);
}

4.demo下载地址

github:https://github.com/MatrixSpring/AndroidPermission

 

5.更新支持AndroidX地址:

github:https://github.com/MatrixSpring/AppPermission

 

2.通过activity中带有的权限请求和回调的方法

1.传入参数

2.工具封装

3.结果返回

4.demo下载地址

 

 

39、Java线程、处理器、执行器与Android运行时权限请求全解析 本文详细解析了Java中的线程、处理器和执行器的基础知识与使用技巧,包括线程间通信、执行器服务管理任务、可调用任务与结果返回等内容。同时深入探讨了Android运行时权限请求机制,涵盖危险权限与正常权限的区别、运行时权限请求流程及处理方法,并提供了完整的代码示例和最佳实践建议,帮助开发者构建高效且安全的应用程序。 阅读详情

相关推荐

39、Java线程、处理器与执行器及Android运行时权限请求全解析

本文深入解析了Java中线程、处理器与执行器的使用,详细介绍了Android运行时权限的请求机制。内容涵盖多线程任务处理、执行器服务、Callable与Runnable任务的区别、Future结果处理、任务调度以及Android危险权限的检查与请求流程。通过代码示例和流程图帮助开发者更好地掌握多线程编程与权限管理的最佳实践。

gpt4scribbler的博客 48

Android 6.0 动态权限申请

本文链接: http://blog.csdn.net/xietansheng/article/details/54315674 1. 概述 Android 6.0 (API 23) 之前应用的权限在安装时全部授予,运行时应用不再需要询问用户。在 Android 6.0 或更高版本对权限进行了分类,对某些涉及到用户隐私的权限可在运行时根据用户的需要动态授予。这样就不需要在安装时被强迫同意某些...

谢TS的博客 4万+

Windows——Nessus安装(无限制)

Nessus手把手图文安装,解除ip限制~

网安小白的博客 9448

Android6.0 危险权限和普通权限

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34248258的博客 147

5分钟搞定阿里云千问大模型API申请:手把手教你获取API Key

本文提供了一份高效的阿里云通义千问大模型API Key获取实战指南。通过清晰的步骤,帮助开发者在五分钟内完成从账号准备、精准导航控制台到创建并验证API Key的全过程,并强调了密钥安全管理和基础调用测试的重要性,助力快速集成AI能力。

ol789012345的博客 1344

六自由度机器人(机械臂)运动学建模及运动规划系列(四)——轨迹规划

本篇介绍了六轴机器人关节空间以及笛卡尔空间轨迹规划的简单方法,并给出了一种几何解法,以简化规划过程,并提供了简单的Matlab轨迹规划函数介绍。

weixin_47849087的博客 5万+

[CM311-1A]-全网最全 Android 用户管理及用户应用权限

安卓系统用户管理 查询添加切换删除用户 安卓系统用户应用权限 Android 用户机制 用户内部外部家目录 创建/切换 多用户流程解析 Android 权限控制以及权限组详解 三层 Android 权限详解 Android 应用程序权限机制 安装一个 APK 的详细过程 权限 安全等级/protectionLevel 分类 AndroidManifest.xml 详解 preferences.xml 详解.........

燃吹 U 客帮 1万+

数字IC后端时序违例修复:setup/hold冲突与时钟树优化实战

时序收敛是数字IC后端设计中最关键的环节之一,直接影响芯片能否在目标频率下稳定工作。建立时间与保持时间的本质是寄存器对数据稳定性的物理约束,而实际工程中,setup违例和hold违例往往此消彼长,冲突的根源在于数据路径与时钟路径的延迟匹配。时钟树综合(CTS)作为连接逻辑与物理的关键步骤,其skew、insertion delay和transition的优化直接决定了时序修复的成败。通过useful skew技术、合理的单元替换和路径结构调整,可以系统性地解决setup/hold冲突,实现时序收敛。本文结合

weixin_28292761的博客 220

android权限字符串,Android的权限处理(一)

一.Android 的权限介绍如果在Android系统中6.0以下的并不需要动态获取,在Android的6.0系统上有的权限需要动态获取,有的权限不危险不需要动态获取,但是都需要在AndroidManifest.xml文件中进行配置!1.动态获取的权限(危险权限,需要在配置文件中配置)(1)需要动态获取的权限组// 摄像头权限Manifest.permission_group.CAMERA;...

weixin_39946274的博客 570

ROS2多线程处理RTSP视频流避坑指南:OpenCV解码丢帧问题解决方案

本文针对ROS2中处理RTSP视频流时OpenCV解码丢帧的常见问题,提供了专业的解决方案。通过深入分析单线程模型的瓶颈,提出并详细拆解了基于生产者-消费者多线程模型的健壮实现方案,有效分离数据采集与处理,从而显著提升视频流的稳定性和流畅度。

weixin_29199873的博客 168

LangGraph 实战教程:搭建一个智能办公多Agent协作平台

只存储必要的信息:不要把所有的原始数据都存储在状态中,比如销售数据可以存储在数据库或向量数据库中,状态中只存储数据的 ID 或摘要。使用类型提示:避免类型错误,提高代码的可维护性。支持增量更新:LangGraph 默认支持状态的增量更新(通过reduce函数),比如messages列表可以通过追加新消息的方式更新,而不是每次都重新创建整个列表。Normal Edge 的定义非常简单,只需要在StateGraph对象(稍后会详细讲解)上调用add_edge# 创建一个 StateGraph 对象。

SuperAGI2025 221

Android 6.0 运行时权限处理解析

Android 6.0 运行时权限处理解析1.概述2.权限的分类及区别   2.1 Google对于Android 6.0 系统权限分为两类:   2.2 普通权限和危险权限的区别:3.代码变化过程   3.1 Android6.0之前直接这样写(已电话拨打为例):   3.2.Android6.0以后就不行啦,我们需要去检测该权限有没有被用户授予过,如果没有则需要申请打电话权限,如果...

weixin_45468727的博客 311

5、自动化代码结构与运维系统的优化

本文探讨了自动化代码结构与运维系统的优化方法,涵盖审批流程的模块化设计、日志记录与工单系统的集成、通知方式的选择、错误处理的策略以及持续改进的实践。同时,深入分析了运维盲目性问题,通过故障案例揭示了关键指标缺失和日志未充分利用的弊端,提出了开发与运维角色转变的必要性。文章还介绍了如何生成有用的系统指标、建立良好的日志习惯以及实施日志聚合,以提升系统的可观测性和可靠性。最终通过总结和流程图展示了优化措施的核心要点,为构建高效、可靠的运维体系提供了指导。

pp12345的博客 71

Android 6.0 运行时权限处理完全解析

转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/50709663; 本文出自:【张鸿洋的博客】 一、概述 随着Android 6.0发布以及普及,我们开发者所要应对的主要就是新版本SDK带来的一些变化,首先关注的就是权限机制的变化。对于6.0的几个主要的变化,查看查看官网的这篇文章http://develope

Hongyang 29万+

【异常】OpenAI提示内容有误 Invalid prompt: your prompt was flagged as potentially violating our usage policy.

用户需优先调整提示内容,确保符合OpenAI的使用政策。若问题持续,建议结合请求ID和具体代码示例联系官方支持。同时,可参考腾讯云、Microsoft Q&A等平台提供的错误处理实践(如重试机制、日志记录)优化代码健壮性。

奶爸的编程之路,也就一周冷个三天 2066

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Android 6 0 运行时权限处理完全解析

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&a

sdfwcc的博客 176

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Android60运行时权限处理完全解析(转载)

Android60运行时权限处理完全解析 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/50709663; 本文出自:【张鸿洋的博客】 一、概述 随着Android 6.0发布以及普及,我们开发者所要应对的主要就是新版本SDK带来的一些变化,首先关注的就是权限机制的变化。...

anyu8718的博客 139

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

上一篇: Android 本地数据存储三 ObjectBox的使用
下一篇: Mac 编译FFmpeg
MatrixGame
博客等级 码龄9年 40粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MatrixGame

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值