Android 11 URI 用法 (file:// content://)

Android 11 URI usage (file:// content://)

我们有一些关于相似词的老问题,但大多数都是关于转换一个或另一个。

我在这里看到的是新更改后 URI 使用的“正确”行为。让我提供一些背景信息:

Before 当我们获得图像 URI 时,这将是 return file://... 格式。 但是由于新的 OS 权限发生了变化,在我们不应该再使用 WRITE_EXTERNAL_STORAGE 的地方,我们应该使用 getUriForFile(..) 那 return content://... 路径。(Scope Storage usage Android 11 Storage FAQ)

这可以在一些 Android 指南中找到,例如:taken photos guide

“问题”是许多用户习惯于使用裁剪图像的 URI(例如)来创建它的文件并保存它。

现在,有了这些变化,问题来了:

我们应该如何使用URI?

  1. 编写一些代码来检查 Android 版本,如果超过 29,我们应该为 URI 创建一个新的文件路径吗?
  2. 让 URI 成为图像的路径(content of file),如果有人想保存它需要创建自己的文件路径
  3. 还有一些关于如何正确使用 URI 的问题我还没有弄明白。

Obs:问这个,因为Android Image Crop 开源项目交接,我们需要升级Android 10/11 的权限,但现在我们有这个content/file 问题。 More here

编辑: 正如评论所指出的

代码 returning file://(更改后不再有效)

Uri outputFileUri = null;
outputFileUri = Uri.fromFile(
                  new File(context.getExternalCacheDir().getPath(), 
                  "pickImageResult.jpeg")
                );
    

代码 returning content://

outputFileUri = FileProvider.getUriForFile(
                        context,
                        context.getPackageName() + CommonValues.authority,
                        File.createTempFile("pickImageResult", ".jpeg", getImage)
                );

The "problem" is that many users got used to use the URI of a crop image (for example) to create a file of it and save it.

最后,这是您的图书馆,您需要记录您 return 适合的任何 Uri。毕竟,Uri 可以指向:

  • 文件系统上的一个文件 (file)
  • Web 资源(https,或可能 http
  • Android 资源(android.resource
  • 应用中的资产(file://android_asset
  • 一些任意字节集(content

您的库用于图像裁剪。虽然我没有检查实现,但我假设它在应用程序本身内都能正常工作。如果是这样,那么 returning a file Uri 并没有错,如果你想这样做的话。您的代码正在某处写入文件(例如 getCacheDir() on Context)。使用您的库的应用程序必须有权访问该文件,否则您在尝试编写它时会崩溃。通过 Uri.fromFile() 创建的 Uri,对于那个文件,非常好......在那个应用程序中。

Uri.fromFile() 成为问题的地方在于将 Uri 传递给另一个应用程序。但是,您的库用于裁剪图像,而不是与其他应用共享内容。恕我直言,您的工作是将裁剪后的图像返回给应用程序。该应用程序如何处理它取决于该应用程序,受您移交的 Uri 中的任何限制。

您似乎正在考虑的两个选项有不同的问题:

Uri Source Advantages Disadvantages
Uri.fromFile() Cheap, easy Can only be used within the app itself; cannot be passed to other apps
FileProvider Uri can be passed to other apps Requires a library and manifest configuration; cannot readily get to the underlying file

由于恕我直言,图像裁剪器不是图像 共享 解决方案,Uri.fromFile() 似乎是合理的。如果使用您的库的应用想要转身并分享裁剪后的图像,他们会自己设置 FileProvider 并使用 FileProvider.getUriForFile()。唯一的问题是,要么您需要记录文件的写入位置,要么给他们一个选项来告诉您要使用哪个目录——设置 FileProvider 元数据需要这些信息。

有一天,如果您选择更改 API,您可能会考虑 return 使用普通的 File 而不是 Uri。这样,就不会混淆它代表什么了。

但是,最终,这都是您的决定。如果您想使用FileProvider,或者您想将图片上传到您自己的Web 服务器并使用https,那都由您决定。但是,您应该记录您在做什么以及 Uri 代表什么。