
回复
@toc
大家好,我是若城。本系列专注于帮助开发者快速实现 HarmonyOS Next 应用中的常用功能,提供即拿即用的代码示例。
本篇文章将详细介绍两种将网络图片保存到相册的实现方法:
让我们开始深入了解这两种方案的具体实现!
重要提醒:此方法在应用上架过程中需要申请 ACL 权限,审核通过率较低。根据实际测试,连续提交 3 次申请均被拒绝。
首先在 module.json5
文件中配置所需权限:
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.READ_IMAGEVIDEO",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
},
"reason": "$string:CAMERA"
},
{
"name": "ohos.permission.WRITE_IMAGEVIDEO",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
},
"reason": "$string:CAMERA"
}
]
导入所需的功能模块:
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';
下载网络图片并保存到相册的完整函数封装:
// 保存图片到相册
async saveFile(url: string) {
this.downLoadImg = true;
try {
// 申请相册管理模块权限 'ohos.permission.WRITE_IMAGEVIDEO'
this.atManager.requestPermissionsFromUser(this.appContext, ['ohos.permission.WRITE_IMAGEVIDEO'])
.then(async () => {
// 权限申请成功,开始保存到图库
let context = getContext();
// 获取相册管理模块的实例,用于访问和修改相册中的媒体文件
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
// 显示下载提示(注意:onClick触发后10秒内通过createAsset接口创建图片文件,10秒后权限收回)
this.promptAction.showToast({
message: '图片下载中....',
duration: 2000
});
// 创建图片资源
let uri = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
let file = fs.openSync(uri, fs.OpenMode.READ_WRITE || fs.OpenMode.CREATE);
let totalSize = 0;
// 创建HTTP请求
let httpRequest = http.createHttp();
// 监听数据接收
httpRequest.on("dataReceive", (data: ArrayBuffer) => {
let writeLen = fs.writeSync(file.fd, data);
totalSize = totalSize + writeLen;
});
// 发起流式请求
httpRequest.requestInStream(url, {
method: http.RequestMethod.GET,
connectTimeout: 3000,
}, httpCode => {
console.info('requestInStream HTTP CODE is', httpCode)
});
// 监听下载完成
httpRequest.on("dataEnd", () => {
fs.close(file);
this.promptAction.showToast({
message: "下载图片结束,并保存至相册",
duration: 2000,
alignment: Alignment.Center,
});
this.downLoadImg = false;
});
});
} catch (err) {
console.error(`requestPermissionsFromUser call Failed! error: ${err.code}`);
this.downLoadImg = false;
}
}
// 下载按钮组件
Column() {
Image($r("app.media.downImg"))
.width(24)
.height(24)
Text('下载')
.fontSize(12)
.fontColor('#FFFFFF')
.margin({ top: 4 })
}
.onClick(() => {
if (this.downLoadImg) {
promptAction.showToast({
message: '正在下载中,请稍后',
duration: 1000,
});
} else {
this.saveFile(this.dataList.pic_url)
}
})
.margin({ right: 32 })
@State dataList: Poem = {
"_id": "68962176fb8dca9bad565162",
"date": "20250810",
"author": "洛尔迦",
"content": "我会走得很远,远过这些山丘,远过这些大海,直到靠近星星。",
"from": "诗人",
"like": 117,
"pic_url": "https://pics.tide.moreless.io/dailypics/FnDB9yZb_8lAL9tvw2Ug3x1AO6Dh?imageView2/1/w/1366/h/768/format/webp",
"share": 114,
"thumb": "https://pics.tide.moreless.io/dailypics/FnDB9yZb_8lAL9tvw2Ug3x1AO6Dh?imageView2/1/w/1366/h/768/format/webp?imageView2/1/w/300/h/300/format/webp"
}
核心要点:上述代码详细展示了如何将网络图片保存到相册的完整流程,函数传参为网络图片的 URL 地址。
第二种方法无需申请相关权限,是官方推荐的实现方式。虽然默认 UI 样式定制性有限,但我们可以通过以下技巧来解决:
Stack
布局,正常编写自定义下载按钮 UISaveButton
默认 UI 进行完全透明化处理引入所需的功能包:
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import fs from '@ohos.file.fs';
import { promptAction } from '@kit.ArkUI';
使用系统提供的 SaveButton
组件:
SaveButton({ icon: SaveIconStyle.FULL_FILLED })
.onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
if (result === SaveButtonOnClickResult.SUCCESS) {
this.saveFile(this.dataList.date)
} else {
this.downLoadImg = false
promptAction.showToast({
message: '设置权限失败!',
duration: 2000
});
}
})
.fontColor('#FFFFFF')
.iconSize(12)
.width(24)
.height(24)
.backgroundColor('#4CD964')
.padding(5)
// 保存图片到相册
async saveFile(url: string) {
this.downLoadImg = true;
promptAction.showToast({
message: '图片下载中',
duration: 1000
});
try {
const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
// 免去权限申请和权限请求等环节,获得临时授权,保存对应图片
let helper = photoAccessHelper.getPhotoAccessHelper(context);
try {
// onClick触发后5秒内通过createAsset接口创建图片文件,5秒后createAsset权限收回
let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
// 使用uri打开文件,可以持续写入内容,写入过程不受时间限制
let file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let content: Uint8Array | undefined = context?.resourceManager.getRawFileContentSync(`${url}.jpg`)
await fs.write(file.fd, content?.buffer);
await fs.close(file.fd);
promptAction.showToast({
message: '图片已保存至相册',
duration: 2000
});
this.downLoadImg = false
} catch (error) {
this.downLoadImg = false
promptAction.showToast({
message: '图片保存失败',
duration: 2000
});
}
} catch (err) {
this.downLoadImg = false
console.error(`create asset failed with error: ${err.code}, ${err.message}`);
}
}
重要说明:第二种方法示例中并未直接使用网络图片,而是使用应用内置图片进行演示。图片需要存放在
rawfile
文件夹中,传递的参数实际上是图片的名称。
特性 | 方法一(权限申请) | 方法二(免权限) |
---|---|---|
权限要求 | 需要申请 ACL 权限 | 无需申请权限 |
上架难度 | 审核严格,通过率低 | 审核容易通过 |
UI 定制性 | 完全自定义 | 受限,需要技巧处理 |
用户体验 | 一键下载 | 需要用户手动授权 |
网络图片支持 | 完整支持 | 需要额外处理 |
开发复杂度 | 中等 | 简单 |
本文详细介绍了 HarmonyOS Next 中实现网络图片保存到相册的两种方案:
通过合理选择实现方案,开发者可以在保证功能完整性的同时,确保应用能够顺利上架。建议在实际开发中根据具体需求和项目特点选择合适的方案。
希望这篇文章能够帮助到正在开发 HarmonyOS Next 应用的朋友们!如果有任何问题,欢迎在评论区交流讨论。