在安卓10上,READ_EXTERNAL_STORAGE无法正常工作。

7

我正在尝试将照片发送到服务器,但只有在Android 10上无法访问照片。已经发出了READ_EXTERNAL_STORAGE请求,在设置中点击了“允许”,允许访问存储。

清单文件

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

片段

private fun haveStoragePermission() =
    ActivityCompat.checkSelfPermission(requireActivity(), Manifest
       .permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED

private fun requestPermission() {
  if (!haveStoragePermission()) {
     val permissions = arrayOf(
          Manifest.permission.READ_EXTERNAL_STORAGE
     )
     ActivityCompat.requestPermissions(requireActivity(), permissions, STORAGE_REQUEST_PERMISSION)
  }
}

文件路径会在日志中显示。它是绝对路径,例如 file:///emulated/0/...photo.jpg ,这很方便,因为你可以立即将其上传到服务器,但是 Picasso 和服务器无法接受照片,或者更准确地说是似乎不允许读取(Picasso 由于错误显示占位符)。只有在清单文件中添加 requestLegacyExternalStorage 属性时,此代码才能正常工作。然后一切都能正常工作,但是此属性在 Android 11 中已经被移除了。我不知道为什么在 Android 10 上不起作用,尽管在测试设备上的 7、8、6 上都正常。

//Get images code
private fun getAllShownImagesPath(activity: Activity): ArrayList<String> {
    val listOfAllImages = ArrayList<String>()
    val uri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    val projection = arrayOf(
        MediaColumns.DATA,
        MediaStore.Images.Media.BUCKET_DISPLAY_NAME
    )
    val cursor = activity.contentResolver.query(
        uri, projection, null,
        null,"${MediaStore.Images.Media.DATE_TAKEN} DESC"
    )
    val columnIndexData = cursor!!.getColumnIndexOrThrow(MediaColumns.DATA)
    while (cursor.moveToNext()) {
        val absolutePathOfImage = cursor.getString(columnIndexData)
        listOfAllImages.add("file://$absolutePathOfImage")
    }
    return listOfAllImages
}
2个回答

10

如果要使该代码正常工作,则需要在清单文件中添加requestLegacyExternalStorage。

因此,在清单文件的<application>元素中添加android:requestLegacyExternalStorage="true"

然后一切都可以正常工作,但是这个属性在Android 11中已经消失了。

在Android 11+中,READ_EXTERNAL_STORAGE 在很大程度上与Android 9及以下版本中的工作方式相同。不过,仍然有一些区域是禁止访问的。

Google 希望您不再考虑文件和文件系统,而是使用存储访问框架(例如ACTION_OPEN_DOCUMENT)。


好的,我会保留Legacy属性。我曾经使用Intent.ACTION_PICK来获取照片并将其路径从content://...更改为绝对路径(从file:///...)。然后Picasso可以显示照片,但它也没有上传到服务器。但是感谢您的答案,我以为Android 11不再支持requestLegacyExternalStorage。 - Janey Springs
@JaneySprings:“然后Picasso可以显示照片”-- Picasso可以显示content Uri值。 “但它也没有上传到服务器”-- 有一些使用Uri上传内容的方法,例如这个用于OkHttp和Retrofit的方法 - CommonsWare

1
默认情况下,针对Android 10及更高版本的应用程序被赋予了对外部存储器的范围访问权限,或者称为范围存储。这样的应用程序可以查看外部存储设备中的文件,而无需请求任何与存储相关的用户权限。但是,您可以在活动xml中添加以下属性以回退到旧行为。
android:requestLegacyExternalStorage="true" 但是,这种方法不会长期可用。您必须根据新规格进行处理。有关详细信息,请参见https://developer.android.com/about/versions/10/privacy/changes

2
据我从文档中了解到,READ_EXTERNAL_STORAGE 应该只在 Android 9 及以下的设备上请求,但是对于 Android 10 呢?我只想显示来自相册的所有照片并选择一些上传到服务器。我可以添加 requestLegacyExternalStorage,但我希望应用程序能在 Android 11 及更高版本上运行。 - Janey Springs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接