HarmonyOS鸿蒙Next中储存图片到相册,一段时间内重复弹窗提示的问题如何解决

HarmonyOS鸿蒙Next中储存图片到相册,一段时间内重复弹窗提示的问题如何解决 【问题描述】:

需要实现createAssetWithShortTermPermission的效果,但是不会将图片传到沙箱,可以给一个demo吗?

【问题现象】:

目前用的官方文档的代码,每次点击都会出现弹窗


更多关于HarmonyOS鸿蒙Next中储存图片到相册,一段时间内重复弹窗提示的问题如何解决的实战教程也可以访问 https://www.itying.com/category-93-b0.html

8 回复

使用PhotoAccessHelper需要申请受限权限,该权限不仅在moduile.json5文件中申请也需要在AGC后台进行申请;

  • ohos.permission.READ_IMAGEVIDEO
  • ohos.permission.WRITE_IMAGEVIDEO

建议:使用SaveButton控件进行图片保存至媒体库中

SaveButton简述:“安全控件的保存控件。应用集成保存控件后,用户首次使用保存控件展示弹窗,在点击允许后自动授权,应用会获取一分钟内访问媒体库特权接口的授权。后续使用无需弹窗授权。

相关文档:【SaveButton_示例】

更多关于HarmonyOS鸿蒙Next中储存图片到相册,一段时间内重复弹窗提示的问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


【问题分析】

我刚验证了一下使用createAssetWithShortTermPermission弹窗一直弹起的原因是因为没有获取到权限ohos.permission.SHORT_TERM_WRITE_IMAGEVIDEO,所以每次都会弹起弹窗

【解决方案】

在module.json5中申请权限使用就能实现5分钟内不弹起授权弹窗,SHORT_TERM_WRITE_IMAGEVIDEO是一个需要用户授权的权限,没有特殊情况建议楼主使用安全控件来保存【SaveButton_示例】

cke_8951.png

{
  "name": 'ohos.permission.SHORT_TERM_WRITE_IMAGEVIDEO',
  "reason": "$string:app_name",
  "usedScene": {

  }
}

【示例代码】

async example(phAccessHelper: photoAccessHelper.PhotoAccessHelper) {
  console.info('createAssetWithShortTermPermissionDemo.');

  try {
    let photoCreationConfig: photoAccessHelper.PhotoCreationConfig = {
      title: '123456',
      fileNameExtension: 'jpg',
      photoType: photoAccessHelper.PhotoType.IMAGE,
      subtype: photoAccessHelper.PhotoSubtype.DEFAULT,
    };

    let resultUri: string = await phAccessHelper.createAssetWithShortTermPermission(photoCreationConfig);
    let resultFile: fileIo.File = fileIo.openSync(resultUri, fileIo.OpenMode.READ_WRITE);
    // 实际场景请使用真实的uri和文件大小。
    let srcFile: fileIo.File = fileIo.openSync("file://test.jpg", fileIo.OpenMode.READ_ONLY);
    let bufSize: number = 2000000;
    let readSize: number = 0;
    let buf = new ArrayBuffer(bufSize);
    let readLen = fileIo.readSync(srcFile.fd, buf, {
      offset: readSize,
      length: bufSize
    });
    if (readLen > 0) {
      readSize += readLen;
      fileIo.writeSync(resultFile.fd, buf, { length: readLen });
    }
    fileIo.closeSync(srcFile);
    fileIo.closeSync(resultFile);
  } catch (err) {
    console.error('createAssetWithShortTermPermission failed, errCode is ' + err.code + ', errMsg is ' + err.message);
  }

}
Button('相册').onClick(async (event: ClickEvent) => {
  await this.example(photoAccessHelper.getPhotoAccessHelper(this.getUIContext().getHostContext()))
})

【参考文档】

受限开放权限-应用权限列表-应用权限管控-程序访问控制-安全-系统 - 华为HarmonyOS开发者

根据您的需求,要实现createAssetWithShortTermPermission的效果(避免重复弹窗授权)且不经过沙箱路径,可通过鸿蒙系统的**安全控件(SaveButton)**方案实现。 参考:SaveButton-安全-ArkTS组件-ArkUI(方舟UI框架)-应用框架 - 华为HarmonyOS开发者

总的来说,HarmonyOS是一款非常优秀的操作系统,期待它能在未来带给我们更多惊喜!

尊敬的开发者您好,

由于图片保存涉及到安全性能问题,所以要限制临时权限的赋予时间,在用户"同意"后的5min之内,同一个应用再次调用接口,支持无需弹框确认自动返回已授权的uri给应用,支持应用保存图片/视频。如果您需要demo,能否提供更详细的业务场景以及交互流程?

要么点击一次批量储存到相册,要么只能点一次弹窗一次;

在HarmonyOS鸿蒙Next中,储存图片到相册后出现重复弹窗,通常是由于权限管理或媒体库扫描机制引起。请检查应用是否在短时间内多次调用媒体库接口,或触发了相册的重复刷新。确保使用正确的媒体库API,并遵循单次写入、避免循环调用的最佳实践。同时,确认应用已获取并妥善管理了必要的存储权限。

根据你的描述,核心问题在于使用 createAssetWithShortTermPermission 接口时,每次调用都会触发系统权限弹窗。这通常是由于权限管理策略导致的。

问题分析: createAssetWithShortTermPermission 接口设计为短期权限访问。在 HarmonyOS Next 中,系统对相册等敏感数据的访问权限管理非常严格。即使你已经授权过,系统也可能在特定条件下(如应用后台运行一段时间后)要求重新确认,或者接口的某些调用方式会触发重新授权流程。

解决方案:

  1. 检查并优化权限请求时机:确保你的应用在首次需要写入相册时,已经通过 requestPermissionsFromUser 正确申请并获得了 ohos.permission.WRITE_IMAGEVIDEO 权限。createAssetWithShortTermPermission 本身不负责申请这个长期权限,它依赖于应用已有权限的上下文。

  2. 使用长期权限接口替代:如果你的场景是应用主动保存图片到相册(用户明确知晓且操作),更推荐使用长期权限模型。

    • 先确保应用已获得 ohos.permission.WRITE_IMAGEVIDEO 权限。
    • 使用 PhotoAccessHelper.getPhotoAccessHelper() 获取 helper 实例。
    • 使用 createAsset() 方法直接创建媒体资源(图片)。这个方法在应用持有长期权限的情况下,不会在每次调用时触发弹窗。
  3. 短期权限接口的正确使用场景createAssetWithShortTermPermission 主要适用于“由其他应用拉起、临时处理并返回结果”的短生命周期场景(例如分享接收后快速保存)。在应用主流程中频繁保存图片,使用此接口确实可能导致重复弹窗。

示例代码(长期权限模型):

import photoAccessHelper from '@ohos.file.photoAccessHelper';
import fs from '@ohos.file.fs';

async function saveImageToAlbum(context: common.Context, imageUri: string) {
  try {
    // 1. 获取PhotoAccessHelper实例
    let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
    
    // 2. 指定要保存到的相册名称(例如"MyApp"),如果不存在会创建
    let albumName = 'MyApp';
    let albumFetchOptions: photoAccessHelper.AlbumFetchOptions = {
      selections: `album_name = ?`,
      selectionArgs: [albumName],
    };
    let albumFetchResult: photoAccessHelper.FetchResult<photoAccessHelper.Album> = await phAccessHelper.getAlbums(albumFetchOptions);
    let targetAlbum: photoAccessHelper.Album;
    if (albumFetchResult.getCount() > 0) {
      // 相册已存在
      targetAlbum = await albumFetchResult.getFirstObject();
    } else {
      // 创建新相册
      targetAlbum = await phAccessHelper.createAlbum(albumName);
    }

    // 3. 准备要保存的图片文件(这里假设imageUri是应用沙箱内的临时文件路径)
    let file = fs.openSync(imageUri, fs.OpenMode.READ_ONLY);
    let stat = fs.statSync(imageUri);
    
    // 4. 使用长期权限接口创建媒体资源
    let displayName = `IMG_${Date.now()}.jpg`; // 自定义文件名
    let createAssetRequest: photoAccessHelper.CreateAssetRequest = {
      album: targetAlbum, // 可选项,指定相册。如果为undefined,则保存到默认相册。
      displayName: displayName,
      relativePath: photoAccessHelper.PhotoViewConstants.DEFAULT_RELATIVE_PATH, // 默认路径
    };
    let photoAsset: photoAccessHelper.PhotoAsset = await phAccessHelper.createAsset(createAssetRequest);
    
    // 5. 将图片数据写入创建的资源
    let assetFd = await photoAsset.open('rw');
    await fs.copyFile(file.fd, assetFd.fd);
    fs.closeSync(file);
    await assetFd.close();
    
    console.info('Save image to album successfully, URI:', photoAsset.uri);
  } catch (err) {
    console.error('Failed to save image to album. Error:', err);
  }
}

关键点:

  • 确保应用已声明并动态申请了 ohos.permission.WRITE_IMAGEVIDEO 权限。
  • 使用 getPhotoAccessHelper(context).createAsset() 接口。
  • 通过 Album 管理可以将图片保存到指定相册,提升用户体验。

如果确实需要使用短期权限接口且希望减少弹窗,需要仔细设计应用架构,确保该接口仅在明确的、短暂的跨应用交互场景中调用,并做好用户预期管理。但根据你的描述,改为长期权限模型是更直接有效的解决方案。

回到顶部