HarmonyOS 鸿蒙Next 使用phAccessHelper.showAssetsCreationDialog保存沙箱图片到用户相册失败
HarmonyOS 鸿蒙Next 使用phAccessHelper.showAssetsCreationDialog保存沙箱图片到用户相册失败
let filePath = getContext(this).getApplicationContext().cacheDir +
'/xxxx.jpg'
url = fileUri.getUriFromPath(filePath)
console.log(url)
let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [{
title: 'test2', // 可选
fileNameExtension: 'jpg',
photoType: photoAccessHelper.PhotoType.IMAGE,
subtype: photoAccessHelper.PhotoSubtype.DEFAULT, // 可选
}];
let desFileUris: Array<string> =
await photoAccessHelper.getPhotoAccessHelper(getContext(this)).showAssetsCreationDialog([url], photoCreationConfigs)
console.info('showAssetsCreationDialog success, data is ' + desFileUris);
使用这段代码保存图片提示成功, 并返回保存成功的路径: file: //media/Photo/13/xxx/test2.jpg ,但是打开手机相册没有这张图片
参考以下demo:
import { http } from '[@kit](/user/kit).NetworkKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
import util from '[@ohos](/user/ohos).util';
import { fileUri } from '[@kit](/user/kit).CoreFileKit';
import fs, { ReadOptions } from '[@ohos](/user/ohos).file.fs';
import { photoAccessHelper } from '[@kit](/user/kit).MediaLibraryKit';
import { promptAction } from '[@kit](/user/kit).ArkUI';
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Index1 {
[@State](/user/State) message: string = 'Hello World';
url1: string = "https://xxx/65e53e56Fd3868b6e/b595d41ca8447ea4.jpg";
url2 : string = "https://xxxx/2CNKhEBjd4a9kP2NCKrQUpgq0HP_E3uqofnQ.6099200.png";
build() {
Column (){
Column() {
Text(this.url1)
Button ("保存")
.onClick(()=>{
this.downloadAndSave(this.url1, "jpg")
})
}
.margin({top: 15, bottom :15})
Column() {
Text(this.url2)
Button ("保存")
.onClick(()=>{
this.downloadAndSave(this.url2, "png");
})
}
.margin({top: 15, bottom :15})
}
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.height('100%')
.width('100%')
}
downloadAndSave (url: string, type: string) {
httpDownload(url, type).then((result: DownloadResult)=>{
if (result.isSuccess) {
promptAction.showToast({message : "下载成功"
})
} else {
console.error("失败:" + result.msg);
promptAction.showToast({message : "下载失败❌,请查看日志" })
}
})
}
}
interface DownloadResult { isSuccess: boolean, msg: string }
async function httpDownload (imgUrl: string, imgType: string) : Promise<DownloadResult> {
return new Promise((resolve, reject) => {
http.createHttp().request(imgUrl, async (error: BusinessError, data: http.HttpResponse) => {
// 下载失败
if (error) {
return resolve({ isSuccess: false, msg : "下载失败"});
}
// 数据格式不正确
if ((data.result instanceof ArrayBuffer) == false) {
return resolve({ isSuccess: false, msg : "图片保存失败:数据流不支持"});
}
// 保存到Cache目录下
let imageBuffer: ArrayBuffer = data.result as ArrayBuffer;
const newFileName = util.generateRandomUUID() + "." + imgType;
const newFilePath = getContext().cacheDir + "/" + newFileName;
const newFileUri = fileUri.getUriFromPath(newFilePath);
let file: fs.File = await fs.open(newFileUri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
await fs.write(file.fd, imageBuffer);
await fs.close(file); console.info("文件路径:" + newFileUri);
saveImageToAsset(newFileUri, imgType).then(()=>{
// 保存成功
return resolve({ isSuccess: true, msg : "保存成功"});
}).catch((error: Error)=> {
// 保存失败
return resolve({ isSuccess: false, msg : "保存失败:" + error.message });
});
});
})
}
async function saveImageToAsset(uri: string, nameExtension : string) : Promise<void> {
console.info('ShowAssetsCreationDialogDemo: ' + uri);
try {
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(getContext());
// 获取需要保存到媒体库的位于应用沙箱的图片/视频uri
let srcFileUris: Array<string> = [uri];
let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [
{
title: 'test2',
fileNameExtension: nameExtension,
photoType: photoAccessHelper.PhotoType.IMAGE,
subtype: photoAccessHelper.PhotoSubtype.DEFAULT,
}];
let desFileUris: Array<string> = await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);
console.info('showAssetsCreationDialog success, data is ' + desFileUris);
if (desFileUris.length == 0) {
// 用户拒绝保存
throw(new Error("用户拒绝保存"))
}
await createAssetByIo(uri, desFileUris[0]);
return Promise.resolve();
} catch (err) {
console.error('showAssetsCreationDialog failed, errCode is ' + err.code + ', errMsg is ' + err.message);
return Promise.reject(err);
}
}
let context = getContext(this);
const createAssetByIo = async (sourceFilePath: string, targetFilePath: string) => {
try {
console.log(`context.fileDir ===> ${context.filesDir}`)
let srcFile: fs.File = fs.openSync(sourceFilePath, fs.OpenMode.READ_ONLY);
let targetFile: fs.File = await fs.open(targetFilePath, fs.OpenMode.READ_WRITE);
let bufSize = 14096;
let readSize = 0;
let buf = new ArrayBuffer(bufSize);
let readOptions: ReadOptions = { offset: readSize, length: bufSize };
let readLen = fs.readSync(srcFile.fd, buf, readOptions);
while (readLen > 0) {
readSize += readLen;
fs.writeSync(targetFile.fd, buf, { length: readLen });
readOptions.offset = readSize;
readLen = fs.readSync(srcFile.fd, buf, readOptions);
}
fs.closeSync(srcFile);
fs.closeSync(targetFile);
} catch (error) {
console.error(`createAssetByIo :: error , msg is ${error} `);
}
}
因为showAssetsCreationDialog只是确认弹窗,用户同意保存后,授予保存权限,保存写入数据需要用户自己实现。所以只是获取到了uri,还没有存放到相册,需要将desFileUris拷贝到url中。
参考这个函数,获取到uri后将多个文件存放到相册中:
async syncToSysAlbum(fileType: photoAccessHelper.PhotoType, extension: string, ...filePath: string[]) {
//此处获取的phAccessHelper实例为全局对象,后续使用到phAccessHelper的地方默认为使用此处获取的对象,如未添加此段代码报phAccessHelper未定义的错误请自行添加
let context = getContext(this);
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
try {
const srcFileUris: string[] = []
filePath.forEach((path) => {
srcFileUris.push(path)
})
const config: photoAccessHelper.PhotoCreationConfig[] = []
config.push({
title: 'background', // 可选
fileNameExtension: extension,
photoType: fileType,
subtype: photoAccessHelper.PhotoSubtype.DEFAULT, // 可选
})
console.log("syncToSysAlarm fileUri:" + json.stringify(srcFileUris) + ",config:" + json.stringify(config))
const desFileUris = await phAccessHelper.showAssetsCreationDialog(srcFileUris, config)
console.debug(`目标图片 uri is : ${JSON.stringify(desFileUris)}`)
if (desFileUris.length > 0) {
for (let index = 0; index < desFileUris.length; index++) {
this.copyFileContentTo(srcFileUris[index], desFileUris[index])
}
}
} catch (err) {
console.log("syncToSysAlarm filePath:" + filePath + ",error:" + json.stringify(err))
}
}
参考:
针对您提到的HarmonyOS 鸿蒙Next系统中使用phAccessHelper.showAssetsCreationDialog
保存沙箱图片到用户相册失败的问题,可能的原因及解决方案概述如下:
-
权限问题:确保您的应用已正确申请并获得了存储权限及相册访问权限。在鸿蒙系统中,权限管理较为严格,缺少必要权限会导致操作失败。
-
沙箱路径问题:检查提供给
phAccessHelper.showAssetsCreationDialog
方法的图片路径是否正确指向沙箱内的有效文件。路径错误或文件不存在均会导致保存失败。 -
API使用错误:确认
phAccessHelper.showAssetsCreationDialog
的调用方式符合鸿蒙系统的API文档要求,包括参数传递和回调处理。 -
系统限制:部分鸿蒙系统版本可能存在特定的系统限制或BUG,导致文件保存功能异常。建议检查并更新至最新的系统版本。
-
日志诊断:利用鸿蒙开发者工具查看详细的错误日志,这有助于定位问题的具体原因。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。