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

目录

一、简介

二、开发步骤

三、代码示例

四、安全控件


一、简介

鸿蒙开发中,要将应用获取到的图片保存到本地,需要申请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

相关推荐
电化学仪器白超2 小时前
③YT讨论
开发语言·python·单片机·嵌入式硬件
listhi5202 小时前
基于MATLAB的平板小孔应力集中问题有限元分析程序
开发语言·matlab
b2077212 小时前
Flutter for OpenHarmony 身体健康状况记录App实战 - 数据导出实现
python·flutter·harmonyos
承渊政道2 小时前
C++学习之旅【C++拓展学习之反向迭代器实现、计算器实现以及逆波兰表达式】
c语言·开发语言·c++·学习·visual studio
froginwe112 小时前
SQLite 表达式详解
开发语言
泰勒疯狂展开2 小时前
Vue3研学-组件的生命周期
开发语言·前端·vue
froginwe112 小时前
JSON 语法详解
开发语言
Charlie_lll2 小时前
学习Three.js–基于GeoJSON绘制2D矢量地图
前端·three.js
XYCMS2 小时前
PHP 外贸网站标题怎么用英文分割生成带杠号“-”的短网址
开发语言·php