You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

高版本Android如何获取与getExternalStoragePublicDirectory一致的路径

问题原因说明

你之前用getExternalFilesDir()返回的是应用专属外部存储目录,路径为/Android/data/[应用包名]/files/Pictures/...,和你需要的公共相册Pictures目录下的Tackle Box文件夹不是同一路径,自然无法正常读写原来的图片。

从Android 10(API 29)开始,官方禁止直接访问公共存储的File路径,必须通过MediaStore API操作公共媒体文件,对应实现方案如下:


步骤1:配置清单权限

在AndroidManifest.xml中添加对应权限:

<!-- 读取外部存储,Android13以下生效 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- 写入外部存储,Android9以下生效 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<!-- Android13及以上读取图片权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" />

<application
    ...
    <!-- Android10兼容配置,可选但建议添加 -->
    android:requestLegacyExternalStorage="true">
    ...
</application>

步骤2:写入图片到公共Tackle Box目录

// 构造图片元数据
val imageValues = ContentValues().apply {
    put(MediaStore.Images.Media.DISPLAY_NAME, "示例图片.jpg")
    put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
    // 指定存储路径为公共Pictures/Tackle Box
    put(MediaStore.Images.Media.RELATIVE_PATH, "${Environment.DIRECTORY_PICTURES}/Tackle Box/")
    put(MediaStore.Images.Media.IS_PENDING, 0)
}

// 插入到MediaStore获取图片Uri
val imageUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageValues)
// 写入图片数据
imageUri?.let { uri ->
    contentResolver.openOutputStream(uri)?.use { outputStream ->
        // 此处写入你的Bitmap/图片字节流,示例:
        // targetBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
    }
}

步骤3:读取Tackle Box目录下的所有图片

val projection = arrayOf(
    MediaStore.Images.Media._ID,
    MediaStore.Images.Media.DISPLAY_NAME
)
// 筛选路径包含Pictures/Tackle Box的图片
val selection = "${MediaStore.Images.Media.RELATIVE_PATH} LIKE ?"
val selectionArgs = arrayOf("%${Environment.DIRECTORY_PICTURES}/Tackle Box/%")
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC"

contentResolver.query(
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
    projection,
    selection,
    selectionArgs,
    sortOrder
)?.use { cursor ->
    val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
    while (cursor.moveToNext()) {
        val imageId = cursor.getLong(idColumn)
        // 拿到图片Uri,直接加载即可,不需要本地File路径
        val loadUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageId)
        // 示例用Glide加载:
        // Glide.with(context).load(loadUri).into(targetImageView)
    }
}

低版本兼容(API 28及以下)

如果需要兼容Android 9及以下版本,可以保留原File逻辑单独适配:

val targetDir = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
    File(
        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
        "Tackle Box"
    ).apply { if (!exists()) mkdirs() }
} else {
    // 高版本走MediaStore逻辑,不需要获取File路径
    null
}

内容的提问来源于stack exchange,提问作者JRowan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 03:06:04