Skip to content

保存媒体到系统媒体库 com.hualuo.zhinian.box.common.mediaexport ​

统一入口 MediaExporter,只干一件事:把图片 / 位图 / GIF / 视频写进系统媒体库。

名称里特意不带「相册」两个字。写入目标是系统媒体库 —— API 29+ 走 MediaStore 的 Pictures/ Movies/,API 24~28 写同名的公共目录再通知媒体扫描。落进去的东西相册 App 和文件管理器都能看到,用途不限于「往相册塞一张图」:生成结果、下载的素材、导出的视频,落盘走的都是这里。

不抛异常、返回可直接 toast 的提示文字,调用方不必写 try/catch。

方法说明
isStoragePermissionGranted(context)低版本保存前先问;没权限就用 Compose 的权限申请器申请,别静默失败
saveImage(context, bytes, mime, folder, fileName)存图片字节;MIME 按字节头判定,扩展名跟着改成一致
saveBitmap(context, bitmap, folder, fileName, format)存位图,默认 PNG 无损
saveGif(context, bytes, folder, fileName)存 GIF
saveVideo(context, bytes, mime, folder, fileName)存视频(MediaStore.Video / Movies/[folder])
saveImageFromUrl(context, url, folder, fileName)下载图片再存(别各写一份下载逻辑)
saveVideoFromUrl(context, url, folder, fileName)下载视频再存;流式写入,不会整个读进内存

folder 是媒体库里的子目录名(图片落 Pictures/[folder],视频落 Movies/[folder]),不是磁盘绝对路径,也不是 URL;目录和文件名都由调用方给,这一层不塞业务默认值。

kotlin
// 权限申请器必须在 Compose 里创建,所以保存动作要留在这里收结果
val permissionLauncher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
    if (granted) save()
}
if (MediaExporter.isStoragePermissionGranted(context)) save()
else permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)

// 保存:拿提示文字直接 toast
PopupPrompt.info(MediaExporter.saveImage(context, bytes, "image/png", "极速生图", fileName))

返回的文案写的还是「已保存到相册」

别因为包名改了就去改这行。面向用户时「相册」才是他认得的说法 —— 包名是给写代码的人看的,toast 是给用户看的,两者不必一致。

别在插件里再建副本

MediaExporter 取代了以前每插件一份的 util/MediaSaver.kt(14 份副本,API 已经开始漂移)。要落盘一律走这里。