针对 Android 10 时的 WRITE_EXTERNAL_STORAGE
Posted
技术标签:
【中文标题】针对 Android 10 时的 WRITE_EXTERNAL_STORAGE【英文标题】:WRITE_EXTERNAL_STORAGE when targeting Android 10 【发布时间】:2021-01-21 01:27:47 【问题描述】:在 AS 中有一个关于 android.permission.WRITE_EXTERNAL_STORAGE
的 lint 警告。警告说,当面向 Android 10 及更高版本时,该权限将不再提供写入权限。删除上述权限仍然可以写入内部存储文件夹Pictures/MY_APP_NAME
以保存图像,但它仅适用于 Android 10 (SDK 29) 和/或更高版本(尚未在 Android R 上测试)。当我在 Android M (SDK 23) 等较低版本上再次对其进行测试时,保存图像停止工作,因此我决定返回 android.permission.WRITE_EXTERNAL_STORAGE
,因此再次出现警告。棉绒是否可能只是误报,在不同情况下错误地诊断出问题?因为目前我的支持 SDK 从 21 开始到最新的 30,但 lint 仅指出在针对 Android 10 (SDK 29) 时不再需要它,并且没有考虑回顾项目的最低 SDK 支持。
【问题讨论】:
can still write in internal storage folder Pictures/MY_APP_NAME
奇怪。请给出文件夹的完整路径。
您仍然可以在 Android 10 中使用 MediaStore、ContentResolver 和 ContentValues 写入 Internal Storage/Pictures/MY_APP_NAME
。
@SiddharthKamaria 是的,我尝试添加 android:maxSdkVersion="29"
但没有删除警告。
@MihaeKheel 很奇怪,即使没有 maxSdkVersion,我的 AS 也没有向我显示 WRITE_EXTERNAL_STORAGE
的 lint 警告。也许尝试重建或使缓存无效?
@SiddharthKamaria 感谢您的指出,但我已经尝试过无效化、清理构建和重建警告仍然存在。也许是因为我们有不同的 AS 版本,我还是在 Canary 版本的 AS 中。
【参考方案1】:
尝试将其添加到您的清单中:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true" //Add this Line
android:label="@string/app_name">
---------<Activity, Sevices or Recivers>----------
</application>
并再次删除READ_EXTERNAL_STORAGE
权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
【讨论】:
不再需要requestLegacyExternalStorage
并且对于 Android 10 来说不是一个好的解决方案,因为如果您想将文件存储在 Internal Storage/Pictures/MY_APP_NAME
中,可以使用 MediaStore、ContentResolver 和 ContentValues 等 API
没有。这是一个很好的解决方案。您可以继续使用经典文件路径。在 Android 11 上,您也可以仅使用经典文件路径写入图片文件夹。不需要 mediastore 和 saf
@blackapps 请阅读developer.android.com/training/data-storage/use-cases
Caution: After you update your app to target Android 11 (API level 30), the system ignores the requestLegacyExternalStorage attribute when your app is running on Android 11 devices, so your app must be ready to support scoped storage and to migrate app data for users on those devices.
另见***.com/questions/63364476/…
是的,旧版请求对 Android 11 设备没有任何作用。但它仍然适用于 Android 10 设备。所以继续使用它我会说,这就是我所说的。【参考方案2】:
解决方法是实际上忽略警告,因为它只是提供信息,因此无害。通过将 maxSdkVersion 设置为 28 无需再担心了。
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
请注意,使用其他答案中所述的 android:requestLegacyExternalStorage 标志不是解决方案,只是一个临时补丁,在 Android 11 (API 30) 中将不再有效,以及未来的版本
更新,澄清一些开发者在 cmets 中表现出的疑惑和困惑:
如果在 Android 10 (API 29) 中使用 requestLegacyExternalStorage 标志,则照常请求 WRITE_EXTERNAL_STORAGE 权限。
标志 requestLegacyExternalStorage 在 Android 11 (API 30) 中没有任何作用,它被完全忽略,并且没有解决方法。
WRITE_EXTERNAL_STORAGE 在 Android 11 (API 30) 中不提供任何权限,它什么都不做,因此在 API 11 中您需要将 maxSdkVersion 设置为 29。
如果在 Android 10 (API 29) 中您也没有使用 requestLegacyExternalStorage,则将 maxSdkVersion 设置为 28而不是 29。
从 Android 11 (API 30) 开始,旧的 File API 可以再次使用,但“仅”在访问公共“共享存储”文件夹(DCIM、音乐等),或您的应用程序“私人”目录。对于其他位置,DocumentFile API 是必需的。
请考虑,Android 11 (API 30) 中的 File API 现在要慢得多,因为已被重构为本质上的包装器。这是为了强制其仅在允许的位置使用。因此,它不再是一个快速的系统文件 API,而只是一个在内部将工作委托给 MediaStore 的包装器。在 Android 11 或更高版本中使用 File API 时,您应该考虑性能损失,因为根据 Android 团队的说法,它会比直接访问 MediaStore 慢 2 到 3 倍。
【讨论】:
这似乎是这里提到的最糟糕的解决方案,因为它会阻止人们使用 Android 10 及更高版本安装应用程序 感谢您的反馈,我很惊讶地看到,developer.android.com/guide/topics/manifest/… 下的文档说无法安装,如果系统更新后重新验证,应用程序甚至会被删除 @Christian 好的,现在我明白你的困惑了。您提到的链接指的是“正如@PerracoLabs 的回答,警告只是信息性的。如果一开始你会阅读他的答案会更好。 https://***.com/a/65477206/6055194
我使用WRITE_EXTERNAL_STORAGE
权限仅用于使用DownloadManager
将.pdf 文件下载到Downloads
和应用程序“私人”目录(这很重要,您可以理解为什么如果您将阅读@PerracoLabs 答案下的讨论)。所以我刚刚为这个权限添加了***别的 SDK,并忽略了作用域存储的标签。
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
附:如果无法识别tools
标签,则必须像这样将xmlns:tools="http://schemas.android.com/tools"
添加到您的AndroidManifest.xml 中来声明它。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.app.my">
但是你必须注意,在它之后onRequestPermissionsResult
函数将不会被Build.VERSION_CODES.Q
和更高版本调用(API 29+)。
所以你必须调用请求权限WRITE_EXTERNAL_STORAGE
只有API低于29。
所以你可以像这样(Kotlin)添加检查写入外部存储功能。
private fun hasWriteStoragePermission(): Boolean
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
return true
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
if (ActivityCompat.checkSelfPermission(activity!!, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
requestPermissions(
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
REQUEST_PERMISSIONS_CODE_WRITE_STORAGE
)
return false
return true
【讨论】:
【参考方案4】:添加行:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:remove="android:maxSdkVersion"/>
并将以下代码添加到AndroidManifest.xml
:
android:requestLegacyExternalStorage="true"
【讨论】:
【参考方案5】:使用 File-apis 吗?
根据@PerracoLabs 的回复,以下更改将使您的应用在运行的设备上运行
-
Android-9 及更低版本
Android-10
Android-11 及以上版本
文件:“AndroidManifest.xml”
//Without this folders will be inaccessible in Android-11 and above devices
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
//Without this entry storage-permission entry will not be visible under app-info permissions list Android-10 and below
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
tools:ignore="ScopedStorage"/>
//Without this entry the folders will remain in-accessible in Android-10, even if WRITE_EXTERNAL_STORAGE as above is present.
<application
android:requestLegacyExternalStorage="true"/>
Java 源码:
在进行文件操作之前不要忘记给予运行时权限。 - Android-10 及以下版本需要。不要为 Android-11 请求运行时权限,Android-10 及更低版本需要请求。
将用户导航到应用权限页面,以允许他使用以下代码启用文件权限(Android-11 及更高版本支持所需):
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && false == Environment.isExternalStorageManager())
Uri uri = Uri.parse("package:" + BuildConfig.APPLICATION_ID);
startActivity(new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri));
【讨论】:
以上是关于针对 Android 10 时的 WRITE_EXTERNAL_STORAGE的主要内容,如果未能解决你的问题,请参考以下文章
运行 googlecast 示例时的 Android ClassNotFoundException