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" />

解决方法是实际上忽略该警告,因为它只是提供信息,因此无害。通过设置 maxSdkVersion28 就不用担心了。

<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 权限。

  • 标志 requestLegacyExternalStorageAndroid 11 (API 30) 中没有任何作用, 它被完全忽略,并且没有解决方法。

  • WRITE_EXTERNAL_STORAGEAndroid 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 的回复,以下更改将使您的应用程序在设备上运行 运行

  1. Android-9 及以下
  2. Android-10
  3. 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 来源:

  1. 在进行文件操作之前,不要忘记授予运行时权限。 - Android-10 及以下需要。不要请求 Android-11 的运行时权限,它们将被请求 Android-10 及以下。

  2. 将用户导航到应用程序权限页面,以允许他使用以下代码启用文件权限(需要 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));
     }