适配SDK30后Android11从Downloads文件夹获取APK包名报错
问题根因
你遇到的空指针是context.getPackageManager().getPackageArchiveInfo()返回null导致的,核心原因是Android 11及以上的权限隔离机制:
- 你自己的应用确实拥有公共Downloads目录下该APK文件的访问权限,所以可以正常创建File实例、读取文件大小
- 但你把文件路径直接传给系统服务
PackageManager时,PackageManager本身并没有权限访问你应用可访问的公共目录文件,因此无法解析APK的包信息,直接返回null
解决方案
方案1:将APK拷贝到应用内部沙箱后解析(无需引入第三方依赖,兼容性最好)
你可以先把公共目录下的APK文件拷贝到应用私有目录(比如context.getFilesDir()下的临时目录),再把私有目录下的文件路径传给getPackageArchiveInfo即可正常解析,系统服务有权限访问应用私有目录下的文件。
示例代码:
private static String getPackageNameForAPK(final String publicFilePath, Context context) { // 1. 先把公共目录的APK拷贝到应用私有目录 File publicApkFile = new File(publicFilePath); File tempApkFile = new File(context.getFilesDir(), "temp_parse.apk"); try (FileInputStream fis = new FileInputStream(publicApkFile); FileOutputStream fos = new FileOutputStream(tempApkFile)) { byte[] buffer = new byte[1024 * 4]; int len; while ((len = fis.read(buffer)) != -1) { fos.write(buffer, 0, len); } fos.flush(); } catch (IOException e) { e.printStackTrace(); return null; } // 2. 解析私有目录的APK PackageInfo info = context.getPackageManager().getPackageArchiveInfo(tempApkFile.getAbsolutePath(), 0); // 解析完成后删除临时文件 tempApkFile.delete(); if (info != null) { return info.packageName; } return null; }
方案2:直接解析APK的Manifest二进制内容
如果不想做文件拷贝,可以引入轻量的APK解析库,直接在应用进程内读取APK文件的Manifest内容提取包名,不需要调用系统PackageManager服务,也就不存在权限问题。
额外排查点
如果上面的方案还是返回null,先检查两个点:
- 下载的文件是否真的是完整的APK文件,有没有下载损坏
- 保存的文件名是否带有
.apk后缀,没有后缀的情况下getPackageArchiveInfo也会解析失败
内容的提问来源于stack exchange,提问作者Richard
相关产品推荐
相关产品推荐

