鸿蒙开发——使用弹窗授权保存媒体库资源

目录

一、简介

二、开发步骤

三、代码示例

四、安全控件


一、简介

鸿蒙开发中,要将应用获取到的图片保存到本地,需要申请ohos.permission.WRITE_IMAGEVIDEO权限,该权限是受限权限,属于system_basic级别且启用了ACL,需以normal等级申请。仅适用于需要克隆、备份或同步用户公共目录图片/视频的场景,且需通过华为AGC审核。

在非必要的情况下,可以使用安全控件和使用弹窗授权保存媒体库资源。

本文主要对使用弹窗授权保存媒体库资源进行说明。

二、开发步骤

  1. 指定待保存到媒体库的应用文件uri(需为应用沙箱路径),本文采用的是base64格式解码后保存。

  2. 指定待保存照片的创建选项,包括文件后缀和照片类型,标题和照片子类型可选。

  3. 调用showAssetsCreationDialog,基于弹窗授权的方式获取的目标媒体文件uri。

    弹框需要显示应用名称,无法直接获取应用名称,依赖于配置项的label和icon,因此调用此接口时请确保module.json5文件中的abilities标签中配置了label和icon项。label值即应用名称值。需要注意的是,图标不受abilities标签中的icon项影响,不支持修改。

  4. 将应用沙箱的照片内容写入媒体库的目标uri。

三、代码示例

具体代码参考如下 :

TypeScript 复制代码
import { util } from "@kit.ArkTS";
import { fileIo, fileUri } from "@kit.CoreFileKit";
import { photoAccessHelper } from "@kit.MediaLibraryKit";
import { BusinessError } from "@ohos.base";

const TAG: string = 'SavaBase64Picture';

export class SavaBase64Picture {
  /**
   * base64ToArrayBuffer base6解码
   * */
  private async base64ToArrayBuffer(base64Str: string): Promise<ArrayBuffer> {
    //去掉头部,此处只针对了image做处理
    const pureBase64: string = base64Str.replace(/^data:image\/[a-zA-Z+]+;base64,/, '');
    const base64 = new util.Base64Helper()
    const unit8Array: Uint8Array = await base64.decode(pureBase64);
    return unit8Array.buffer.slice(0, unit8Array.byteLength);
  }

  /**
   * saveBase64ToSandBox 保存图片到沙箱
   * */
  private async saveBase64ToSandBox(base64str: string, fileName: string): Promise<string> {
    try {
      const imageBuffer: ArrayBuffer = await this.base64ToArrayBuffer(base64str);
      const context = AppStorage.get('context_.currentUse') as Context;
      const dirPath: string = context.cacheDir;
      const filePath: string = `${dirPath}/${fileName}`
      const file: fileIo.File = await fileIo.open(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE);
      await fileIo.write(file.fd, imageBuffer);
      await fileIo.close(file.fd);
      return filePath;
    } catch (err) {
      console.error(TAG, `saveBase64ToSandBox err:${err?.message}`);
      return ''
    }
  }

  /**
   * saveImageByDialog 拉起弹框保存图片
   * */
  private async saveImageByDialog(base64Str: string, base64Type: string, fileName: string) {
    try {
      if (!base64Str) {
        console.error(TAG, `dont have base64Str`);
        return;
      }
      const context: Context = getContext();
      const phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
      let filePath: string = await this.saveBase64ToSandBox(base64Str, fileName);
      let srcFileUri: string = fileUri.getUriFromPath(filePath);
      let srcFileUris: string[] = [srcFileUri];
      let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [
        {
          title: 'text',
          fileNameExtension: base64Type,
          photoType: photoAccessHelper.PhotoType.IMAGE
        }
      ];
      let desFileUris: Array<string> = await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);
      let desFile: fileIo.File = await fileIo.open(desFileUris[0], fileIo.OpenMode.READ_WRITE);
      let srcFile: fileIo.File = await fileIo.open(srcFileUri, fileIo.OpenMode.READ_WRITE);
      // 检查文件是否存在
      fileIo.accessSync(desFileUris[0])
      fileIo.accessSync(srcFileUri)
      fileIo.copyFile(srcFile.fd, desFile.fd).then(() => {
        console.info(TAG, 'copyFile success');
      }).catch((err: BusinessError) => {
        console.error(TAG, `copyFile err:${err?.message}`);
      }).finally(() => {
        fileIo.close(srcFile);
        fileIo.close(desFile);
      })

    } catch (err) {
      console.error(TAG, `saveImageByDialog err:${err?.message}`);
    }
  }

  /**
   * start 开始函数
   * */
  async start(data: Record<string, string>): Promise<void> {
    //   假设参数格式:data Recode<string,JSONValueType>= {"parameter":"{type":"png","base64data":"data:image/png;base64,xxxx..."}"}
    let parameter: string = data['parameter'] as string;
    let base64Obj: Record<string, string> = JSON.parse(parameter) as Record<string, string>;
    let base64Str: string = base64Obj['base64data'] as string;
    let base64Type: string = base64Obj['type'] as string;
    let fileName: string = `image_${Date.now()},${base64Type}`;
    await this.saveImageByDialog(base64Str, base64Type, fileName);
  }
}

常见的FAQ:如何通过安全控件、弹窗授权实现媒体资源保存-行业常见问题-运动健康类行业实践-场景化知识 - 华为HarmonyOS开发者

四、安全控件

安全控件可以参考以下链接,这里不做过多解释:

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/photoaccesshelper-savebutton

相关推荐
caimouse1 小时前
reactos编码规范
c语言·开发语言
小雨下雨的雨3 小时前
井字棋AI机器人实现详解 - Minimax算法实战-鸿蒙PC Electron框架完成
前端·人工智能·算法·华为·electron·鸿蒙
xieliyu.5 小时前
Java算法精讲:双指针(三)
java·开发语言·算法
CryptoPP6 小时前
快速对接东京证券交易所API数据:实战指南与代码示例
开发语言·人工智能·windows·python·信息可视化·区块链
ZC跨境爬虫6 小时前
跟着 MDN 学JavaScript day_7:数学运算与逻辑判断实战测试
开发语言·前端·javascript·学习·ecmascript
fangdengfu1237 小时前
ES分析系统各个服务日志占用量
java·前端·elasticsearch
阳区欠7 小时前
【LangChain】LLM基础介绍
开发语言·python·langchain
Jinkxs8 小时前
Java 跨域14-Java 与区块链(Hyperledger)集成
java·开发语言·区块链
不爱吃糖的程序媛8 小时前
鸿蒙服务卡片实战:为新华字典应用添加桌面快捷查询卡片
华为·harmonyos
JustHappy8 小时前
古法编程秘籍(六):程序到底是怎么跑起来的?从 IO 到中断,一次讲明白
前端·后端·全栈