为何通过PackageInfo获取权限时丢失WRITE_EXTERNAL_STORAGE?
我遇到一个奇怪的问题:我的AndroidManifest.xml里明明声明了8个权限,其中包含android.permission.WRITE_EXTERNAL_STORAGE,但用代码读取Manifest中的权限列表时,这个权限居然不见了!
先给大家看看我的配置和代码:
我的AndroidManifest.xml权限声明
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.jiyuzhai.xxxx"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.READ_SETTINGS"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="com.android.vending.BILLING"/> <!-- 应用组件部分省略 --> </manifest>
SDK版本配置
ext { compileSdkVersion = 28 minSdkVersion = 17 targetSdkVersion = 28 buildToolsVersion = '28.0.3' }
获取权限的代码
try { PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS); String[] permissions = packageInfo.requestedPermissions; if (permissions == null || permissions.length == 0) { throw new IllegalStateException("You did not register any permissions in the manifest.xml."); } return Collections.unmodifiableList(Arrays.asList(permissions)); } catch (PackageManager.NameNotFoundException e) { throw new AssertionError("Package name cannot be found."); }
运行这段代码后,返回的权限列表里确实没有android.permission.WRITE_EXTERNAL_STORAGE,这是为什么呢?
原因分析
这其实是Android系统的权限机制导致的:
从Android 4.4(API 19)开始,WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE属于同一个权限组(STORAGE)。当你的应用targetSdkVersion >= 19时,只要你在Manifest中声明了READ_EXTERNAL_STORAGE,系统会自动隐含授予WRITE_EXTERNAL_STORAGE权限,不需要单独请求。
而通过PackageManager.GET_PERMISSIONS获取的是应用显式请求且系统认为需要单独列出的权限,对于这种被隐含授予的关联权限,系统不会将其返回在requestedPermissions数组中。你的targetSdkVersion是28,完全符合这个规则,所以就出现了WRITE权限"丢失"的情况。
验证与解决方案
如果你想确认应用是否真的拥有WRITE_EXTERNAL_STORAGE权限,可以用Context.checkSelfPermission()来检查:
int writePermissionStatus = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE); if (writePermissionStatus == PackageManager.PERMISSION_GRANTED) { // 应用确实拥有WRITE权限 }
你会发现返回的是PERMISSION_GRANTED,说明权限其实是存在的,只是没出现在获取的列表里而已。
如果你的业务逻辑必须要在权限列表中包含WRITE_EXTERNAL_STORAGE,其实没有必要——因为系统已经自动处理了权限关联。但如果你非要显式获取到它,可以尝试将targetSdkVersion降到18以下(不推荐,会影响其他功能的兼容性),不过这显然不是合理的解决方案。
正确的做法是理解这个权限机制,通过权限组的角度去处理存储权限,而不是依赖requestedPermissions数组中的每一个权限条目。
内容的提问来源于stack exchange,提问作者zdd

