HarmonyOS 鸿蒙Next 使用phAccessHelper.showAssetsCreationDialog保存沙箱图片到用户相册失败

发布于 1周前 作者 itying888 最后一次编辑是 5天前 来自 鸿蒙OS

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 ,但是打开手机相册没有这张图片

3 回复

参考以下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))
    }
  } 

 参考:

https://developer.huawei.com/consumer/cn/forum/topic/0202169496587807624?fid=0109140870620153026&pid=0301169587690976074

针对您提到的HarmonyOS 鸿蒙Next系统中使用phAccessHelper.showAssetsCreationDialog保存沙箱图片到用户相册失败的问题,可能的原因及解决方案概述如下:

  1. 权限问题:确保您的应用已正确申请并获得了存储权限及相册访问权限。在鸿蒙系统中,权限管理较为严格,缺少必要权限会导致操作失败。

  2. 沙箱路径问题:检查提供给phAccessHelper.showAssetsCreationDialog方法的图片路径是否正确指向沙箱内的有效文件。路径错误或文件不存在均会导致保存失败。

  3. API使用错误:确认phAccessHelper.showAssetsCreationDialog的调用方式符合鸿蒙系统的API文档要求,包括参数传递和回调处理。

  4. 系统限制:部分鸿蒙系统版本可能存在特定的系统限制或BUG,导致文件保存功能异常。建议检查并更新至最新的系统版本。

  5. 日志诊断:利用鸿蒙开发者工具查看详细的错误日志,这有助于定位问题的具体原因。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。

回到顶部