WRITE_EXTERNAL_STORAGE 定位时 Android 10
WRITE_EXTERNAL_STORAGE when targeting Android 10
关于 android.permission.WRITE_EXTERNAL_STORAGE
,AS 中有一个 lint 警告。警告说,当目标 Android 10 及以上时,该权限将不再提供写访问权限。取消该权限仍然可以写入内部存储文件夹Pictures/MY_APP_NAME
以保存图像,但它只适用于Android 10(SDK 29)and/or以上(尚未在[上测试过AndroidR)。当我在 Android M (SDK 23) 等较低版本上再次测试时,保存图像停止工作,所以我决定 return android.permission.WRITE_EXTERNAL_STORAGE
因此警告再次出现。棉绒是否可能只是误报,错误地诊断了不同情况下的问题?因为目前我的支持 SDK 从 21 开始到最新的 30 但 lint 只指出当目标 Android 10 (SDK 29) 时不再需要它并且没有考虑回顾项目的最小 SDK支持。
尝试将此添加到您的清单中:
<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" />
解决方法是实际上忽略该警告,因为它只是提供信息,因此无害。通过设置 maxSdkVersion 到 28 就不用担心了。
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
请注意,使用其他答案中所述的 android:requestLegacyExternalStorage 标志不是解决方案,只是一个临时补丁,它将不再有效Android 11 (API 30),以及未来的版本
更新,澄清一些开发者在评论中表现出的疑惑和困惑:
如果在 Android 10 (API 29) 中使用 requestLegacyExternalStorage 标志然后像往常一样请求 WRITE_EXTERNAL_STORAGE 权限。
标志 requestLegacyExternalStorage 在 Android 11 (API 30) 中没有任何作用, 它被完全忽略,并且没有解决方法。
WRITE_EXTERNAL_STORAGE 在 Android 11 (API 30) 中不给予任何特权,它什么都不做,因此在 API 11 你需要将 maxSdkVersion 设置为 29.
If in Android 10 (API 29) 你也没有使用 requestLegacyExternalStorage 然后将 maxSdkVersion 设置为 28 而不是 29.
开始于Android11(API30),较旧的文件API 可以再次使用,但“仅”在访问 public“共享存储”文件夹(DCIM、音乐等)或您的应用“私人”目录时使用。对于其他位置,需要 DocumentFile API。
考虑到文件 API 现在在 Android 11 (API 30) 中要慢得多,因为已经被重构成为本质上的包装器。这是为了仅在允许的位置强制使用它。所以,不再是一个快速的系统文件 API,只是一个在内部将工作委托给 MediaStore 的包装器。在 Android 11 或更高版本中使用文件 API 时,您应该考虑性能损失,因为根据 Android 团队的说法,它比直接访问 MediaStore 慢 2 到 3 倍.
正如@PerracoLabs 所回答的那样,该警告仅供参考。如果一开始你会阅读他的回答会更好。
我使用 WRITE_EXTERNAL_STORAGE
权限 仅用于将 .pdf 文件下载到 Downloads
和应用程序“私人”目录 使用 DownloadManager
(这很重要,如果您阅读@PerracoLabs 回答下的讨论,您就会明白为什么)。所以我刚刚为此权限添加了最高级别的 SDK,并忽略了范围存储的标签。
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
P.S。如果无法识别 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+)中被调用。
所以你必须只为 API 低于 29.
调用请求权限 WRITE_EXTERNAL_STORAGE
所以你可以像这样添加检查写入外部存储功能(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
}
添加行:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:remove="android:maxSdkVersion"/>
并将以下代码添加到 AndroidManifest.xml
:
android:requestLegacyExternalStorage="true"
使用 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.permission.WRITE_EXTERNAL_STORAGE
,AS 中有一个 lint 警告。警告说,当目标 Android 10 及以上时,该权限将不再提供写访问权限。取消该权限仍然可以写入内部存储文件夹Pictures/MY_APP_NAME
以保存图像,但它只适用于Android 10(SDK 29)and/or以上(尚未在[上测试过AndroidR)。当我在 Android M (SDK 23) 等较低版本上再次测试时,保存图像停止工作,所以我决定 return android.permission.WRITE_EXTERNAL_STORAGE
因此警告再次出现。棉绒是否可能只是误报,错误地诊断了不同情况下的问题?因为目前我的支持 SDK 从 21 开始到最新的 30 但 lint 只指出当目标 Android 10 (SDK 29) 时不再需要它并且没有考虑回顾项目的最小 SDK支持。
尝试将此添加到您的清单中:
<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" />
解决方法是实际上忽略该警告,因为它只是提供信息,因此无害。通过设置 maxSdkVersion 到 28 就不用担心了。
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
请注意,使用其他答案中所述的 android:requestLegacyExternalStorage 标志不是解决方案,只是一个临时补丁,它将不再有效Android 11 (API 30),以及未来的版本
更新,澄清一些开发者在评论中表现出的疑惑和困惑:
如果在 Android 10 (API 29) 中使用 requestLegacyExternalStorage 标志然后像往常一样请求 WRITE_EXTERNAL_STORAGE 权限。
标志 requestLegacyExternalStorage 在 Android 11 (API 30) 中没有任何作用, 它被完全忽略,并且没有解决方法。
WRITE_EXTERNAL_STORAGE 在 Android 11 (API 30) 中不给予任何特权,它什么都不做,因此在 API 11 你需要将 maxSdkVersion 设置为 29.
If in Android 10 (API 29) 你也没有使用 requestLegacyExternalStorage 然后将 maxSdkVersion 设置为 28 而不是 29.
开始于Android11(API30),较旧的文件API 可以再次使用,但“仅”在访问 public“共享存储”文件夹(DCIM、音乐等)或您的应用“私人”目录时使用。对于其他位置,需要 DocumentFile API。
考虑到文件 API 现在在 Android 11 (API 30) 中要慢得多,因为已经被重构成为本质上的包装器。这是为了仅在允许的位置强制使用它。所以,不再是一个快速的系统文件 API,只是一个在内部将工作委托给 MediaStore 的包装器。在 Android 11 或更高版本中使用文件 API 时,您应该考虑性能损失,因为根据 Android 团队的说法,它比直接访问 MediaStore 慢 2 到 3 倍.
正如@PerracoLabs 所回答的那样,该警告仅供参考。如果一开始你会阅读他的回答会更好。
我使用 WRITE_EXTERNAL_STORAGE
权限 仅用于将 .pdf 文件下载到 Downloads
和应用程序“私人”目录 使用 DownloadManager
(这很重要,如果您阅读@PerracoLabs 回答下的讨论,您就会明白为什么)。所以我刚刚为此权限添加了最高级别的 SDK,并忽略了范围存储的标签。
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
P.S。如果无法识别 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+)中被调用。
所以你必须只为 API 低于 29.
WRITE_EXTERNAL_STORAGE
所以你可以像这样添加检查写入外部存储功能(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
}
添加行:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:remove="android:maxSdkVersion"/>
并将以下代码添加到 AndroidManifest.xml
:
android:requestLegacyExternalStorage="true"
使用 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)); }