android - 当我只能处理文件或文件路径时如何处理 SAF?

标签 android file storage-access-framework android-10.0 scoped-storage

背景

在 Android Q 之前,如果我们想获取有关 APK 文件的信息,我们可以使用 WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE访问存储,然后使用 PackageManager.getPackageArchiveInfo文件路径上的函数。

也有类似的情况,比如使用ZipFile class在压缩文件上,可能还有无数的框架 API 和第三方库。

问题

谷歌最近宣布了对 Android Q 的大量限制。

其中之一称为 Scoped Storage ,在访问设备拥有的所有文件时会破坏存储权限。它允许您处理媒体文件,或使用非常受限的存储访问框架 (SAF),它不允许应用程序使用文件 API 和文件路径访问和使用文件。

当 Android Q Beta 2 发布时,它破坏了很多应用程序,包括谷歌。原因是它默认打开,影响所有应用程序,无论它们是否针对 Android Q。

原因是许多应用程序、SDK 和 Android 框架本身 - 都经常使用 File API。在许多情况下,它们也不支持 InputStream 或 SAF 相关的解决方案。这方面的一个例子正是我写的关于 (PackageManager.getPackageArchiveInfo) 的 APK 解析示例。

然而,在 Q beta 3 上,情况发生了一些变化,因此以 Q 为目标的应用程序将具有范围存储,并且有一个标志可以禁用它,并且仍然像往常一样使用正常的存储权限和文件 API。遗憾的是,该标志只是暂时的(阅读 here),因此它推迟了不可避免的 .

我试过的

我已经尝试过并发现了接下来的事情:

  • 使用存储权限确实没有让我读取任何不是媒体文件的文件(我想查找 APK 文件)。就好像文件不存在一样。
  • 使用 SAF,我可以找到 APK 文件,并通过一些解决方法来找到它的真实路径(链接 here),我注意到 File API 可以告诉我文件确实存在,但它无法获得它的大小,并且框架未能通过 getPackageArchiveInfo 使用其路径.写了这篇 here
  • 我试图为文件创建一个符号链接(symbolic link)(链接 here ),然后从符号链接(symbolic link)中读取。它没有帮助。
  • 对于解析APK文件的情况,我尝试寻找替代解决方案。我找到了 2 个使用 File 类( herehere )处理 APK 的 github 存储库,还有一个使用 InputStream ( here )。遗憾的是,使用 InputStream 的那个非常旧,缺少各种功能(例如获取应用程序的名称和图标)并且不会很快更新。此外,拥有一个库需要维护以跟上 future 的 Android 版本,否则将来可能会出现问题,甚至崩溃。

  • 问题
  • 一般来说,有没有办法在使用 SAF 时仍然使用 File API?我不是在谈论根解决方案或只是将文件复制到其他地方。我说的是更可靠的解决方案。
  • 对于APK解析的情况,有没有办法解决框架只提供文件路径作为参数的问题?也许有任何解决方法或使用 InputStream 的方法?
  • 最佳答案

    当我只能处理文件或文件路径时如何处理 SAF?即使您只能将 Java File 对象或路径字符串发送到您无法修改的库函数,也有可能:

    首先,获取您需要处理的文件的 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
        }          
    

    关于android - 当我只能处理文件或文件路径时如何处理 SAF?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56199568/

    相关文章:

    android - 使用存储访问框架请求访问文件夹时,Intent.FLAG_GRANT_PREFIX_URI_PERMISSION 有什么用?

    java - 如何将 Paging 3 从 Kotlin Flow 移植到 Java? - 找不到 PagingDataFlow.create 函数

    android - 将文本文件从 Raspberry Pi 发送到 Android 应用程序

    r - 如何在 R 中省略 file.copy() 的响应?

    python - 换行符 ='' 在 csv 库中意味着什么?

    java - 使用存储访问框架打开特定路径

    android - 我无法在 android 中停止我的媒体播放器?

    java - 如何检查Android应用程序是否进入前台?

    java - 去掉文件路径(home/user/file.txt = file.txt)?

    android - 使用 SAF 访问 Google Drive 时如何刷新内容