马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
在 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 文档为准。 |