目录
一、简介
鸿蒙开发中,要将应用获取到的图片保存到本地,需要申请ohos.permission.WRITE_IMAGEVIDEO权限,该权限是受限权限,属于system_basic级别且启用了ACL,需以normal等级申请。仅适用于需要克隆、备份或同步用户公共目录图片/视频的场景,且需通过华为AGC审核。
在非必要的情况下,可以使用安全控件和使用弹窗授权保存媒体库资源。
本文主要对使用弹窗授权保存媒体库资源进行说明。
二、开发步骤
-
指定待保存到媒体库的应用文件uri(需为应用沙箱路径),本文采用的是base64格式解码后保存。
-
指定待保存照片的创建选项,包括文件后缀和照片类型,标题和照片子类型可选。
-
调用showAssetsCreationDialog,基于弹窗授权的方式获取的目标媒体文件uri。
弹框需要显示应用名称,无法直接获取应用名称,依赖于配置项的label和icon,因此调用此接口时请确保module.json5文件中的abilities标签中配置了label和icon项。label值即应用名称值。需要注意的是,图标不受abilities标签中的icon项影响,不支持修改。
-
将应用沙箱的照片内容写入媒体库的目标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