外观
保存媒体到系统媒体库 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 已经开始漂移)。要落盘一律走这里。