在鸿蒙中如何把网络图片保存到相册中

[复制链接]
发表于 2026-10-4 18:37:54 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

在 HarmonyOS NEXT(鸿蒙)应用开发里,"把一张网络图片存进系统相册"不算复杂,但踩坑的人不少:权限配了、签名也做了,跑起来还是报"受限权限未授权",或者在模拟器上保存成功却看不到文件。这篇把整条链路拆开讲一遍,包括权限声明、签名方式的选择、相册媒体库的创建接口,以及真机与模拟器的差异。

一、先说权限:WRITE_IMAGEVIDEO 是受限权限

要往相册写图片,需要申请 ohos.permission.WRITE_IMAGEVIDEO。这个权限比较特殊,它属于"受限权限(ACL 权限)",也就是说仅仅在配置文件里声明还不够,应用必须具备对应的签名等级才能使用。

签名方式跟你的 DevEco Studio 版本直接相关:

  • DevEco Studio 4.0 Release 及以上:可以直接用"自动签名"。
  • 低于 4.0 Release:如果工程里已经用了这类 ACL 权限,就必须改用"手动签名"。

判断依据很简单:配完权限运行时如果弹错提示"该权限为受限权限,未签名无法使用",那就是签名环节没做对。

二、在 module.json5 中声明权限

第一步,在模块的 module.json5 里加权限声明,注意 reason 要引用 $string: 下的说明资源:

{
  "name": "ohos.permission.WRITE_IMAGEVIDEO",
  "reason": "$string:file_reason_desc",
  "usedScene": {
    "when": "always"
  }
}

配置之后运行会报受限权限错误,这是预期现象,下一步处理签名。

三、配置签名

常见版本是 DevEco Studio 5.0.3.100,直接用自动签名即可。操作路径:

  • 进入 File > Project Structure… > Project > SigningConfigs。
  • 勾选 Automatically generates signature。
  • 如果是 HarmonyOS 工程,同时勾选 Support HarmonyOS。
  • 未登录的话先点 Sign In 登录,然后自动完成签名。

低于 4.0 的版本走手动签名,流程可以参照鸿蒙开发者中心的官方说明。

四、保存图片的核心代码

权限就绪后就是业务代码了。整体思路是:先向用户申请权限,成功后拿到相册管理模块实例,用 createAsset 创建一个空图片资源拿到 URI,再把网络流写进这个 URI 对应的文件句柄。

import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import fs from '@ohos.file.fs';
import { http } from '@kit.NetworkKit';
import { promptAction } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  private appContext: common.Context = getContext(this);
  private atManager = abilityAccessCtrl.createAtManager();

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
        Button("保存图片")
          .margin({ top: 10 })
          .onClick(async (event: ClickEvent) => {
            try {
              this.atManager.requestPermissionsFromUser(
                this.appContext, ['ohos.permission.WRITE_IMAGEVIDEO']
              ).then(async () => {
                let context = getContext();
                let phAccessHelper =
                  photoAccessHelper.getPhotoAccessHelper(context);
                let uri = await phAccessHelper.createAsset(
                  photoAccessHelper.PhotoType.IMAGE, 'jpg');
                console.info('createAsset successfully, uri: ' + uri);
                let file = fs.openSync(uri,
                  fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
                let totalSize = 0;
                let httpRequest = http.createHttp();
                httpRequest.on("dataReceive", (data: ArrayBuffer) => {
                  let writeLen = fs.writeSync(file.fd, data);
                  totalSize = totalSize + writeLen;
                });
                httpRequest.requestInStream(
                  'https://example.com/demo.png',
                  { method: http.RequestMethod.GET, connectTimeout: 3000 },
                  httpCode => { console.info('HTTP CODE is ' + httpCode); }
                );
                httpRequest.on("dataEnd", () => {
                  fs.close(file);
                  promptAction.showDialog({
                    title: "下载图片结束,并保存至相册",
                    message: `图片大小{totalSize}字节`
                  });
                });
              });
            } catch (err) {
              console.error('requestPermissionsFromUser call failed! error: ' +
                err.code);
            }
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

五、几个容易忽略的点

  • 10 秒窗口期:createAsset 创建图片文件后,需要在短时间内(文档口径为 10 秒内)写入内容,超时后创建权限会被收回,所以下载要紧跟着创建走。
  • 必须用 requestInStream:大文件走 request 会把完整数据读进内存,on("dataReceive") + fs.writeSync 是边收边写的稳妥写法。
  • 网络权限不用单独配:ohos.permission.INTERNET 不是受限权限,直接在 module.json5 声明即可,不需要额外操作。
  • 真机才看得见:这个功能在真机上运行才能看到相册里保存的图片,模拟器里保存出来是空的,属于环境差异而非代码问题。

把图片地址换成自己服务上的资源,跑通一次就能放心用了。

qidao123.com企服评测-应用市场 编辑提示:本文为 HarmonyOS 图片保存到相册的开发记录整理,代码与接口说明依据官方示例改写,实际接入时请以当前 SDK 文档为准。

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表