背景
在 Android Q 之前,如果我们想获取有关 APK 文件的信息,我们可以使用写外部存储 https://developer.android.com/reference/android/Manifest.permission.html#WRITE_EXTERNAL_STORAGE and 读外部存储 https://developer.android.com/reference/android/Manifest.permission.html#READ_EXTERNAL_STORAGE访问存储,然后使用PackageManager.getPackageArchiveInfo https://developer.android.com/reference/android/content/pm/PackageManager.html#getPackageArchiveInfo(java.lang.String,%20int)文件路径上的函数。
类似的情况也存在,例如使用压缩文件类 https://developer.android.com/reference/java/util/zip/ZipFile在压缩文件上,可能还有无数的框架 API 和第三方库。
问题
谷歌最近宣布了对 Android Q 的大量限制。
其中之一称为范围存储 https://developer.android.com/preview/privacy/scoped-storage,这会在访问设备拥有的所有文件时破坏存储权限。它可以让您处理媒体文件,或使用非常有限的存储访问框架(SAF https://developer.android.com/guide/topics/providers/document-provider),它不允许应用程序使用文件 API 和文件路径访问和使用文件。
当Android Q Beta 2发布时,它破坏了很多应用程序,包括谷歌的应用程序。原因是它默认打开,影响所有应用程序,无论它们是否针对 Android Q。
原因是许多应用程序、SDK 和 Android 框架本身 - 都经常使用文件 API。在许多情况下,它们也不支持 InputStream 或 SAF 相关的解决方案。一个例子就是我写的 APK 解析示例 (PackageManager.getPackageArchiveInfo)。
然而,在 Q beta 3 上,情况发生了一些变化,因此目标 Q 的应用程序将具有范围存储,并且有一个标志可以禁用它,但仍然像往常一样使用正常的存储权限和文件 API。遗憾的是,该标志只是暂时的(读here https://www.xda-developers.com/google-gives-developers-more-time-android-q-scoped-storage/),所以它推迟了不可避免的事情。
我尝试过的
我已经尝试并发现了接下来的事情:
使用存储权限确实不允许我读取任何非媒体文件的文件(我想找到 APK 文件)。就好像这些文件不存在一样。
使用 SAF,我可以找到 APK 文件,并通过一些解决方法来找到其真实路径(链接here https://issuetracker.google.com/issues/132825438),我注意到文件 API 可以告诉我文件确实存在,但它无法获取其大小,并且框架无法使用其路径getPackageArchiveInfo
。写过这个here https://issuetracker.google.com/issues/132481545
我尝试创建一个到该文件的符号链接(链接here https://stackoverflow.com/questions/34608249/android-create-symbolic-link-in-the-app/56107194#56107194),然后从符号链接中读取。这没有帮助。
对于解析APK文件的情况,我尝试寻找替代解决方案。我找到了 2 个使用 File 类处理 APK 的 github 存储库(here https://github.com/jaredrummler/APKParser and here https://github.com/hsiafan/apk-parser),以及使用 InputStream 的一种(here https://github.com/joakime/android-apk-parser)。遗憾的是,使用 InputStream 的版本非常旧,缺少各种功能(例如获取应用程序的名称和图标),并且不会很快更新。此外,拥有一个库需要维护以跟上Android的未来版本,否则将来可能会出现问题,甚至崩溃。
问题
一般来说,有没有办法在使用 SAF 时仍然使用 File API ?我不是在谈论根解决方案或只是将文件复制到其他地方。我正在谈论一个更可靠的解决方案。
对于APK解析的情况,有没有办法克服框架只提供文件路径作为参数的问题?可能有任何解决方法或使用 InputStream 的方法吗?
当我只能处理文件或文件路径时如何处理 SAF?即使您只能发送 Java 文件对象或无法修改的库函数的路径字符串,这是可能的:
首先,获取您需要处理的文件的 Uri(字符串形式,类似于“content://...”),然后:
try {
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r"); // may get FileNotFoundException here
// Obtain file descriptor:
int fd = parcelFileDescriptor.getFd(); // or detachFd() if we want to close file in native code
String linkFileName = "/proc/self/fd/" + fd;
// Call library function with path/file string:
someFunc(/*file name*/ linkFileName);
// or with File parameter
otherFunc(new File(linkFileName));
// Finally, if you did not call detachFd() to obtain the file descriptor, call:
parcelFileDescriptor.close();
// Otherwise your library function should close file/stream...
} catch (FileNotFoundException fnf) {
fnf.printStackTrace(); // or whatever
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)