Android6.0权限管理以及使用权限该注意的地方

本文详细介绍了Android 6.0 Marshmallow引入的运行时权限管理机制,包括不同版本号(targetSdkVersion)下权限管理的区别、如何处理危险权限(dangerous permission)的请求与撤销、以及Activity和Fragment在权限请求方面的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android 6.0 Marshmallow首次加入了运行时权限管理,这对用户来说,可以更好的了解、控 制 app 涉及到的权限。然而对开发者来说却是一件比较蛋疼的事情,需要兼容适配,并保证程序功能的正常运行。
什么叫运行时权限管理呢?在Android 6.0以下的系统中,当我们在安装应用的时候,该应用就会提示我们这个应用所需要的权限,如果你要安装,那就必须同意赋予所有权限,但是如果不同意,那就只能取消安装了,有点流氓。而且安装完后,你不可以收回这个权限。
而6.0就做到了运行时权限管理,即使安装的时候给了权限,也可以到系统设置里,去关闭该权限。
下面分几种情况来讲,因为运行时权限只有在Android6.0及以上的手机版本才有,所以这里只考虑设备版本大于6.0的手机,低版本的手机在安装时就已经赋予了所有的权限,也不可能收回,就不考虑了,下面的情况只分targetSdkVersion:

  1. targetSDKVersion大于等于23的时候,那么权限是可以被回收(revoke),这里还要分权限,google将权限分为两种,一种是normal permission,另一种是dangerous permission。normal permission是指与用户隐私无关的权限,可以理解为无关紧要的权限,比如说访问网络的权限,对用户来说没什么关系;dangerous permission就是会涉及到用户隐私的权限,例如读取用户手机联系人、短信等等。如果是normal permission的话,那么在安装的时候就会给,而且不会开放接口让用户回收该权限,app会一直拥有该权限,所以不用考虑这种类型的权限。如果是dangerous permission的话,在安装的时候并未授予权限,系统开放接口允许用户回收或者赋予权限。下面是某个应用的权限,第一张图是dangerous permission,可以回收和赋予的。
    这里写图片描述
    点击上面的所有权限,可以查看到该应用所有的权限。
    这是所有的权限,包括normal and dangerous
    那么对于dangerous permission的话,在使用前需要去检查该permission是否已经被授予
checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED

如果该权限已经被授予,那么可继续执行你的代码,如果未授予,则需要向用户询问是否需要授予权限,弹出的框是系统界面,界面如下:
这里写图片描述
调用代码:

requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, 1);

系统询问是否授予权限的页面结束后会有回调

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
   super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 1) {
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
            //your implementations
        }else{
            ToastUtil.show(this, "权限不足,支付失败");
        }
    }
}
  1. 如果targetSdkVersion是小于23的,那么将认为app没有用23新权限测试过,那么继续使用老规则:系统在安装的时候会默认给app赋予所有的权限,app可以照常运行。但是!但是!但是!用户依然可以回收权限,不过此回收非彼回收。先看下关闭权限时弹的页面:
    这里写图片描述
    看到了么,如果targetSDKVersion小于23的话,在关闭权限的时候,会弹一个警告框,告诉你这是旧版的android,关闭会有问题,如果你按拒绝,那么该权限将会关闭,而且界面上,权限的开关会显示关,但是这个权限却没有被回收(nexus 5x的手机亲测,当然其他的机子我也不敢打包票),checkSelfPermission返回granted。我看了下,如果targetSDKVersion等于23的话,系统日志是:
    这里写图片描述
    如果targetSDKVersion是小于23的话,则日志是:
    Permission related app op changed.

不过我猜想如果你要支持runtime permission的话,还是要把targetSDKVersion设为23。如果你的targetSDKVersion是小于23的话,那么还是要加上checkSelfPermission,以防万一,谁知道google会出什么坑。

还有就是权限的话,有分组的概念,看如下图:
这里写图片描述
如果一组中有一个被授予了,那么组内的也会默认被授予。

而且也支持同时申请多个权限,具体情况android developer官网。

下面是stackoverflow问题的网址:
http://stackoverflow.com/questions/36328151/ive-revoke-the-android-permission-but-checkselfpermission-still-return-granted

如有问题和错误的地方请指出。

下面就是要讲一些权限管理注意的地方。
对于权限的话,Activity和Fragment都有自己的requestPermissions和onRequestPermissionsResult回调,但是Activity是有checkSelfPermission,但是fragment是没有的,所以fragment如果想要检查权限,还得调用宿主activity的checkSelfPermission。
对了,平时直接调用checkSelfPermission和requestPermissions会报什么api错误,虽然编译不会通过,但是看着就是烦啊,可以调用ActivityCompat.checkSelfPermission(在supportv4包中)。
先看下Activity的requestSelfPermission这个方法:

public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
    Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
    startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
}

看下这里是直接打开另一个Activity进行操作,还用了startActivityForResult,回调会通过onRequestPermissionResult,我想这个回调应该是在onActivityResult里面处理,然后调这个onRequestPermissionResult函数的。
那么问题来了,如果我在onResume函数中申请某一个权限,调用requestPermissions,那么现象是什么样的呢?
第一次进入页面,弹出申请权限的对话框,如果点击同意,则正常,对话框不会再显示,但是如果第一次点击拒绝,则点击拒绝后又一次弹出对话框来申请权限,如果你一直点拒绝,则对话框一直弹出,这是为什么呢?因为第一次进入页面并执行onResume函数时申请权限,进入另一个页面,弹出对话框,如果你点击拒绝,先是回调onRequestPermissionResult,然后再执行onResume函数,这时又会再一次去检查权限,因为发现无权限,则再一次请求,如是,进入一个循环之中,除非你点同意,否则是个无限循环。所以申请权限最好还是不要写在onResume中,或者加一个标志位判断。
接下来再讲讲Fragment请求权限。

public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
    if (mHost == null) {
        throw new IllegalStateException("Fragment " + this + " not attached to Activity");
    }
    mHost.onRequestPermissionsFromFragment(this, permissions,requestCode);
}

这里看到其实是调用mHost请求权限的方法,mHost就是这个fragment的宿主Activity,所以Fragment请求权限实际上也是通过宿主Activity,当权限结果回调时,activity判断是从Fragment中来的还是从自己Activity中来的,再进行分发结果。

Github上也有一些比较好用的权限库:https://github.com/hotchemi/PermissionsDispatcher

<think>好的,我现在需要解决用户的问题:如何通过Android命令行查看指定UID的权限。首先,用户提到了使用命令行,所以我应该集中在adb或者终端命令上,而不是通过Android应用的代码或者UI操作。 用户的问题是关于权限的,而Android中的权限通常与应用的包名和其声明的权限有关,但这里用户直接提到了UID。我需要回忆一下Android系统中UID和权限的关系。每个应用安装时会被分配一个唯一的UID,权限是在安装时由用户授予的,并记录在系统的某个地方。 首先,我应该想到的是pm(包管理器)命令,因为pm常用于管理包和权限。但pm通常需要包名,而不是直接使用UID。所以可能需要找到将UID转换为包名的方法,然后再查看该包的权限。 接下来,用户可能需要先根据UID找到对应的包名。Android中每个应用有一个唯一的UID,但系统应用和普通应用的UID可能不同。可以通过adb shell进入设备,然后执行命令查看所有已安装的应用及其对应的UID。例如,使用`ps`命令可以查看当前运行的进程及其UID,或者查看`/data/system/packages.list`文件,这个文件列出了包名、UID等信息。例如: ``` adb shell cat /data/system/packages.list | grep <uid> ``` 找到对应的包名后,再使用`pm dump <包名>`来查看该包的权限信息。或者使用`pm list permissions -g -u`等命令来列出权限,但可能需要过滤出特定包的信息。 另外,还有dumpsys包的信息。例如,`dumpsys package <包名>`会输出大量信息,包括授予的权限。不过同样需要先获取包名。 可能还有一种方法是通过appops命令,该命令用于管理应用的操作权限。例如,`adb shell appops get <包名>`可以查看某个包的各种权限设置。但这仍然需要包名。 所以步骤可能是:1)根据UID找到包名;2)使用包名查看其权限。 另外,是否有直接通过UID查询权限的命令呢?可能没有现成的,但可以通过组合命令实现。比如,先用UID找到包名,再用包名查询权限。 例如: 1. 查找包名: ``` adb shell "cat /data/system/packages.list | grep ' <UID>$'" ``` 这里假设UID是该行的最后一列,所以用grep搜索以UID结尾的行,从而提取包名。 2. 获取权限: ``` adb shell pm dump <包名> | grep -A 1 'granted permissions:' ``` 或者更精确地解析输出。 此外,Android权限分为普通权限和危险权限,安装时自动授予或需要运行时请求。已授予的权限可以在pm dump中查看。 可能需要考虑用户是否有root权限,因为访问某些文件如packages.list可能需要root。如果设备未root,可能无法直接读取该文件。此时,是否有其他方法?比如通过pm list packages --uid <UID>来查找包名?例如: ``` adb shell pm list packages --uid <UID> ``` 这可能更可靠且不需要root权限。测试一下这个命令是否存在。在较新的Android版本中,pm list packages支持选项,如--uid参数。例如: ``` pm list packages --uid <uid> ``` 这会列出对应UID的包名。例如,如果UID为10123,执行该命令会输出类似“package:com.example.app uid:10123”的内容。 一旦有了包名,就可以用pm dump或者dumpsys package来查看权限。 总结步骤: 1. 使用`pm list packages --uid <UID>`获取包名。 2. 使用`dumpsys package <包名>`或`pm dump <包名>`查看该包的权限信息。 在输出中查找“grantedPermissions”或者类似的字段,即可看到已授予的权限。 例如: ``` adb shell dumpsys package com.example.app | grep "granted=" ``` 或者更详细地解析整个输出,找到权限部分。 如果用户没有root权限,这种方法应该是可行的,因为pm和dumpsys命令不需要root,只需要adb调试权限。 另外,还可以使用appops来查看具体权限的状态: ``` adb shell appops get <包名> ``` 这会列出各个权限的允许状态,如COARSE_LOCATION、CAMERA等。 所以,最终的解决方案可能是: 通过UID找到包名,然后通过包名查看权限。 现在需要验证这些步骤是否正确。例如,假设用户的UID是10086,可以执行: ``` adb shell pm list packages --uid 10086 ``` 然后得到包名,例如com.test.app。 接着: ``` adb shell dumpsys package com.test.app | grep "android.permission" ``` 或者更准确地,查找已授予的权限: 在dumpsys package的输出中,会有类似这样的部分: ``` grantedPermissions: android.permission.INTERNET android.permission.ACCESS_NETWORK_STATE ``` 所以可以用grep来提取这些行。 或者使用: ``` adb shell pm list permissions -g -d | grep <包名> ``` 不过这可能不太直接。 另外,参考站内引用中的内容,用户可能需要了解如何通过命令行操作,所以应尽量给出具体的命令示例。 因此,综合以上思考,回答应该是: 步骤1:根据UID查找对应的包名: ``` adb shell pm list packages --uid <UID> ``` 步骤2:使用包名查看已授予的权限: ``` adb shell dumpsys package <包名> | grep "grantedPermissions" ``` 或者更详细的解析: ``` adb shell dumpsys package <包名> ``` 然后在输出中查找“grantedPermissions”部分。 例如,完整的命令链可能是: ``` adb shell pm list packages --uid 10086 | cut -d ':' -f 2 | xargs -I {} adb shell dumpsys package {} | grep "grantedPermissions" ``` 不过需要注意多个包可能共享同一个UID的情况,但通常每个应用有唯一的UID,除非是共享UID的情况,但这种情况较少,用户可能需要特殊处理。 另外,需要注意Android版本差异,某些命令可能在旧版本中不可用,比如`pm list packages --uid`是否在所有版本中都支持。例如,在较老的Android版本中可能没有这个选项,这时候可能需要用其他方法,比如通过`ps`命令找到进程的UID,然后根据进程名找到包名,或者解析packages.list文件。 如果用户无法使用`pm list packages --uid`,替代方法是: ``` adb shell cat /data/system/packages.list | grep ' <UID>$' ``` 这里假设最后一列是UID,例如: com.example.app 1000 0 /data/user/0/com.example.app default 这里的第二列(1000)是UID。所以正确的grep应该匹配第二列: 不过实际上,packages.list的格式是: 包名 用户ID 调试标志 数据目录等。 所以正确的grep应该是匹配第二个字段: 例如,使用awk: ``` adb shell "cat /data/system/packages.list | awk '\$2 == <UID> {print \$1}'" ``` 但需要注意的是,这个文件可能需要root权限才能访问。如果设备没有root,用户可能无法执行该命令。因此,推荐优先使用pm命令,无需root。 所以总结,回答的核心步骤是: 1. 使用pm命令根据UID找到包名。 2. 使用dumpsys或pm dump查看该包的权限。 最后,生成相关问题,例如关于如何查看应用的UID,或者如何授予权限等。</think>[用户可见层] 要查看Android系统中指定UID的权限,可以按照以下步骤操作: ### 步骤1:通过UID查找对应的应用包名 使用`pm list packages`命令结合UID过滤: ```bash adb shell pm list packages --uid <目标UID> ``` 例如: ```bash adb shell pm list packages --uid 10123 ``` 输出示例: ``` package:com.example.app uid:10123 ``` 其中`com.example.app`即为该UID对应的包名[^1]。 ### 步骤2:查看该应用的权限详情 通过`dumpsys package`命令获取权限信息: ```bash adb shell dumpsys package <包名> | grep "grantedPermissions" ``` 或直接查看完整权限列表: ```bash adb shell dumpsys package <包名> ``` 在输出中搜索以下字段: - **grantedPermissions**:已授予的权限列表 - **requestedPermissions**:应用声明的所有权限 ### 替代方法:通过`appops`查看权限状态 若需检查运行时权限的开关状态: ```bash adb shell appops get <包名> ``` 此命令会列出所有权限(如定位、摄像头等)的当前状态(允许/拒绝)。 ### 示例完整流程 ```bash # 假设目标UID为10123 adb shell pm list packages --uid 10123 # 输出包名后,查看权限 adb shell dumpsys package com.example.app | grep -A 10 "grantedPermissions" ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值