feat(file): 添加图片保存到系统相册功能

- 在 FileSDK 中新增 saveImageToGallery 方法用于将图片文件保存到系统照片库
- 支持 Android Q 及以上版本使用 MediaStore API 安全存储图片
- 对于旧版 Android 系统使用兼容方案将图片复制到 Pictures 目录
- 在 WebView 组件下载完成后自动将图片文件保存到相册
- 仅当图片未被保存到相册时才显示文件打开选项以避免重复操作
这个提交包含在:
XuqmGroup 2026-06-10 12:39:40 +08:00
父节点 1e7193add3
当前提交 ff13b54d9e
共有 2 个文件被更改,包括 46 次插入1 次删除

查看文件

@ -3,11 +3,13 @@ package com.xuqm.sdk.file
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.webkit.MimeTypeMap
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
@ -269,6 +271,46 @@ object FileSDK {
return target
}
/**
* Saves an image file to the system photo gallery (MediaStore).
* Returns true if the file is an image and was saved successfully.
*/
fun saveImageToGallery(context: Context, file: File): Boolean {
val mimeType = MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(file.extension.lowercase()) ?: return false
if (!mimeType.startsWith("image/")) return false
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
runCatching {
val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, file.name)
put(MediaStore.Images.Media.MIME_TYPE, mimeType)
put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
put(MediaStore.Images.Media.IS_PENDING, 1)
}
val uri = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values
) ?: return false
context.contentResolver.openOutputStream(uri)?.use { out ->
file.inputStream().use { it.copyTo(out) }
}
values.clear()
values.put(MediaStore.Images.Media.IS_PENDING, 0)
context.contentResolver.update(uri, values, null, null)
true
}.getOrDefault(false)
} else {
@Suppress("DEPRECATION")
runCatching {
val picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
picturesDir.mkdirs()
val dest = uniqueFile(picturesDir, file.name)
file.copyTo(dest)
context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(dest)))
true
}.getOrDefault(false)
}
}
fun openFile(context: Context, file: File) {
val mimeType = MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(file.extension.lowercase())

查看文件

@ -272,9 +272,12 @@ fun XWebViewView(
runCatching {
FileSDK.saveBlobDownload(context, b64, filename, config.downloadDestination)
}.onSuccess { file ->
// For image files, save to the system gallery (相册) so they appear in Photos
val savedToGallery = runCatching { FileSDK.saveImageToGallery(context, file) }.getOrDefault(false)
withContext(Dispatchers.Main) {
dispatchDownloadEvent("__xwvDownloadDone", url, ",success:true")
FileSDK.openFile(context, file)
// Only open with file viewer when not saved to gallery (e.g. zip, docx)
if (!savedToGallery) FileSDK.openFile(context, file)
}
}.onFailure { e ->
withContext(Dispatchers.Main) {