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?
- 编写一些代码来检查 Android 版本,如果超过 29,我们应该为 URI 创建一个新的文件路径吗?
- 让 URI 成为图像的路径(
content
of file
),如果有人想保存它需要创建自己的文件路径
- 还有一些关于如何正确使用 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
代表什么。
我们有一些关于相似词的老问题,但大多数都是关于转换一个或另一个。
我在这里看到的是新更改后 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?
- 编写一些代码来检查 Android 版本,如果超过 29,我们应该为 URI 创建一个新的文件路径吗?
- 让 URI 成为图像的路径(
content
offile
),如果有人想保存它需要创建自己的文件路径 - 还有一些关于如何正确使用 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
代表什么。