1. 前言
在鸿蒙HarmonyOS日常开发过程中,经常会遇到需要将图片保存到图库的场景,今天我们就来梳理一下,这样的场景,我们有哪些选择?具体代码该如何写?
开发环境为:
开发工具:DevEco Studio 6.0.1 Release
API版本是:API21
本文所有代码都已使用模拟器测试成功!
本文包含内容如下:

下面我们分别对以上两种方式进行实战代码编写
2. 实战案例
1. 需要申请相册权限
这种方式需要先在工程main目录下的【module.json5】文件中配置如下权限信息:

新增代码如下:
json
//权限放行
"requestPermissions": [
{
//网络权限
"name": "ohos.permission.INTERNET",
},
{
"name": "ohos.permission.READ_IMAGEVIDEO",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
},
"reason": "$string:file_reason_desc"
},
{
"name": "ohos.permission.WRITE_IMAGEVIDEO",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
},
"reason": "$string:file_reason_desc"
}
]
1. 网络图片
如果你有一张网络中的图片需要保存到图库中,那么代码如下:
js
import { abilityAccessCtrl } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import fs from '@ohos.file.fs';
import { http } from '@kit.NetworkKit';
import { promptAction } from '@kit.ArkUI';
/**
* Desc: 案例:保存网络图片到图库(需要申请相册权限)
* Author: 波波老师(vx:javabobo0513)
*/
@Entry
@Component
struct Page01 {
atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
//网络图片地址
@State imageUrl: string = 'https://img0.baidu.com/it/u=3361482875,3939563024&fm=253&fmt=auto&app=138&f=JPEG';
build() {
Column({ space: 15 }) {
//图片
Image(this.imageUrl)
.width('100%')
//下载按钮
Button('保存图片到图库')
.onClick(() => {
try {
let context = getContext(this);
// 申请相册管理模块权限 'ohos.permission.WRITE_IMAGEVIDEO'
this.atManager.requestPermissionsFromUser(context, ['ohos.permission.WRITE_IMAGEVIDEO'])
.then(async () => {
// 权限申请成功,开始保存到图库
// 获取相册管理模块的实例,用于访问和修改相册中的媒体文件
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
// 创建图片资源
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(this.imageUrl, {
method: http.RequestMethod.GET,
connectTimeout: 3000,
}, httpCode => {
console.info('requestInStream HTTP CODE is', httpCode)
});
// 监听下载完成
httpRequest.on("dataEnd", () => {
fs.close(file);
promptAction.showToast({
message: "下载图片结束,并成功保存至相册!",
duration: 5000,
alignment: Alignment.Center,
});
});
});
} catch (err) {
console.error(`requestPermissionsFromUser call Failed! error: ${err.code}`);
promptAction.openToast({
message: `requestPermissionsFromUser call Failed! error: ${err.code}`,
duration: 5000,
alignment: Alignment.Center,
}).catch(() => {
// TODO: Implement error handling.
});
}
})
}
.width('100%')
.height('100%')
}
}
页面效果:

2. 本地图片
如果你想将工程中【media】目录里的图片保存到图库中,那么代码如下:
js
import { abilityAccessCtrl } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import fs from '@ohos.file.fs';
import { promptAction } from '@kit.ArkUI';
/**
* Desc: 案例:保存本地图片到图库(需要申请相册权限)
* Author: 波波老师(vx:javabobo0513)
*/
@Entry
@Component
struct Page03 {
atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
@State image: Resource = $r('app.media.cat')
build() {
Column({ space: 15 }) {
//图片
Image(this.image)
.width('100%')
//下载按钮
Button('保存图片到图库')
.onClick(() => {
try {
let context = getContext(this);
// 申请相册管理模块权限 'ohos.permission.WRITE_IMAGEVIDEO'
this.atManager.requestPermissionsFromUser(context, ['ohos.permission.WRITE_IMAGEVIDEO'])
.then(async () => {
//获取指定资源ID对应的媒体文件内容,使用同步方式返回
let img = context.resourceManager.getMediaContentSync(this.image.id)
// 获取相册管理模块的实例,用于访问和修改相册中的媒体文件
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
// 指定文件类型、后缀和创建选项,创建图片或视频资源
let uri = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
// openSync:以同步方法打开文件
let file = fs.openSync(uri, fs.OpenMode.READ_WRITE || fs.OpenMode.CREATE);
// 写入文件,file.fd:文件的文件描述符
fs.writeSync(file.fd, img.buffer);
// 关闭文件
await fs.close(file);
promptAction.showToast({
message: "图片成功保存至相册!",
duration: 5000,
alignment: Alignment.Center,
});
});
} catch (err) {
console.error(`requestPermissionsFromUser call Failed! error: ${err.code}`);
promptAction.openToast({
message: `requestPermissionsFromUser call Failed! error: ${err.code}`,
duration: 5000,
alignment: Alignment.Center,
}).catch(() => {
// TODO: Implement error handling.
});
}
})
}
.width('100%')
.height('100%')
}
}
如果你想将工程中【rawfile】目录里的图片保存到图库中,那么代码如下:
js
import { abilityAccessCtrl } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import fs from '@ohos.file.fs';
import { promptAction } from '@kit.ArkUI';
/**
* Desc: 案例:保存本地图片到图库(需要申请相册权限)
* Author: 波波老师(vx:javabobo0513)
*/
@Entry
@Component
struct Page03 {
atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
@State image: Resource = $rawfile('cat.jpg')
// @State image: Resource = $r('app.media.cat')
build() {
Column({ space: 15 }) {
//图片
Image(this.image)
.width('100%')
//下载按钮
Button('保存图片到图库')
.onClick(() => {
try {
let context = getContext(this);
// 申请相册管理模块权限 'ohos.permission.WRITE_IMAGEVIDEO'
this.atManager.requestPermissionsFromUser(context, ['ohos.permission.WRITE_IMAGEVIDEO'])
.then(async () => {
//获取resources/rawfile目录下对应的rawfile文件内容,使用同步形式返回
let img = context.resourceManager.getRawFileContentSync('cat.jpg')
// 权限申请成功,开始保存到图库
// 获取相册管理模块的实例,用于访问和修改相册中的媒体文件
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
// 指定文件类型、后缀和创建选项,创建图片或视频资源
let uri = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
// openSync:以同步方法打开文件
let file = fs.openSync(uri, fs.OpenMode.READ_WRITE || fs.OpenMode.CREATE);
// file.fd:文件的文件描述符
fs.writeSync(file.fd, img.buffer);
fs.close(file);
promptAction.showToast({
message: "图片成功保存至相册!",
duration: 5000,
alignment: Alignment.Center,
});
});
} catch (err) {
console.error(`requestPermissionsFromUser call Failed! error: ${err.code}`);
promptAction.openToast({
message: `requestPermissionsFromUser call Failed! error: ${err.code}`,
duration: 5000,
alignment: Alignment.Center,
}).catch(() => {
// TODO: Implement error handling.
});
}
})
}
.width('100%')
.height('100%')
}
}
页面效果:

3. 注意点
该方式缺点是:需要申请相册权限,应用上架时 ACL 权限审核较为严格,审核通过率较低,所以这里不推荐这种方式
2. 无需申请相册权限-推荐
这种方式不需要申请相关权限,所以没有第一种方式的缺点,也是官方推荐的方式。唯一的缺点就是默认的UI样式比较丑,下面我们用案例代码来感受一下
注意:此种方式只需要在【module.json5】文件中配置【ohos.permission.INTERNET】权限即可,不需要配置【ohos.permission.READ_IMAGEVIDEO】和【ohos.permission.WRITE_IMAGEVIDEO】权限
1. 网络图片
如果你有一张网络中的图片需要保存到图库中,那么代码如下:
js
import { common } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { promptAction } from '@kit.ArkUI';
import { http } from '@kit.NetworkKit';
import fileIo from '@ohos.file.fs';
/**
* Desc: 案例:保存网络图片到图库(不需要申请相册权限)
* Author: 波波老师(vx:javabobo0513)
*/
@Entry
@Component
struct Page04 {
//网络图片地址
@State imageUrl: string = 'https://img0.baidu.com/it/u=3361482875,3939563024&fm=253&fmt=auto&app=138&f=JPEG';
build() {
Column({ space: 15 }) {
//图片
Image(this.imageUrl)
.width('100%')
//下载按钮(免去权限申请和权限请求等环节,获得临时授权,保存对应图片)
SaveButton({ icon: SaveIconStyle.FULL_FILLED, text: SaveDescription.SAVE_IMAGE })
.onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
if (result === SaveButtonOnClickResult.SUCCESS) {
try {
const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
// 使用 request 下载图片并在回调函数中保存图片到相册
http.createHttp().request(this.imageUrl,
{
method: http.RequestMethod.GET,
connectTimeout: 60000,
readTimeout: 60000
},
async (error: BusinessError, data: http.HttpResponse) => {
if (error) {
console.error(`http reqeust failed with. Code: ${error.code}, message: ${error.message}`);
} else {
if (http.ResponseCode.OK === data.responseCode) {
let imageBuffer: ArrayBuffer = data.result as ArrayBuffer;
try {
// 获取相册管理模块的实例,用于访问和修改相册中的媒体文件
let helper = photoAccessHelper.getPhotoAccessHelper(context);
// 指定文件类型、后缀和创建选项,创建图片或视频资源
let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg')
// openSync:以同步方法打开文件
let file = fileIo.openSync(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE)
// 写入文件,file.fd:文件的文件描述符
await fileIo.write(file.fd, imageBuffer);
// 关闭文件
await fileIo.close(file.fd);
promptAction.openToast({
message: '图片已成功保存至相册!',
duration: 4000
});
} catch (error) {
console.error("error is " + JSON.stringify(error))
promptAction.openToast({
message: "error is " + JSON.stringify(error),
duration: 4000
});
}
} else {
console.error("error occurred when image downloaded!")
promptAction.showToast({ message: 'error occurred when image downloaded!' });
}
}
})
} catch (err) {
console.error(`create asset failed with error: ${err.code}, ${err.message}`);
}
} else {
promptAction.openToast({
message: '设置权限失败!',
duration: 5000
});
}
})
.width(130)
.height(35)
}
.width('100%')
.height('100%')
}
}
2. 本地图片
如果你想将工程【rawfile】目录中的图片保存到图库中,那么代码如下:
js
import { common } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import fs from '@ohos.file.fs';
import { promptAction } from '@kit.ArkUI';
/**
* Desc: 案例:保存本地图片到图库(不需要申请相册权限)
* Author: 波波老师(vx:javabobo0513)
*/
@Entry
@Component
struct Page02 {
//图片名称
@State imageName: string = 'cat.jpg'
build() {
Column({ space: 15 }) {
//图片
Image($rawfile(this.imageName))
.width('100%')
//下载按钮(免去权限申请和权限请求等环节,获得临时授权,保存对应图片)
SaveButton({ icon: SaveIconStyle.FULL_FILLED, text: SaveDescription.SAVE_IMAGE })
.onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
if (result === SaveButtonOnClickResult.SUCCESS) {
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('rawfile/' + this.imageName)
await fs.write(file.fd, content?.buffer);
await fs.close(file.fd);
promptAction.openToast({
message: '图片已成功保存至相册!',
duration: 4000
});
} catch (error) {
promptAction.openToast({
message: '图片保存至相册失败:' + JSON.stringify(error),
duration: 4000
});
}
} catch (err) {
console.error(`create asset failed with error: ${err.code}, ${err.message}`);
}
} else {
promptAction.openToast({
message: '设置权限失败!',
duration: 5000
});
}
})
.width(130)
.height(35)
}
.width('100%')
.height('100%')
}
}
图片存放路径如下:

如果你想将工程【media】目录中的图片保存到图库中,那么代码如下:
js
import { common } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import fs from '@ohos.file.fs';
import { promptAction } from '@kit.ArkUI';
/**
* Desc: 案例:保存本地图片到图库(不需要申请相册权限)
* Author: 波波老师(vx:javabobo0513)
*/
@Entry
@Component
struct Page02 {
//图片名称
@State image: Resource = $r('app.media.cat')
build() {
Column({ space: 15 }) {
//图片
Image(this.image)
.width('100%')
//下载按钮
SaveButton({ icon: SaveIconStyle.FULL_FILLED, text: SaveDescription.SAVE_IMAGE })
.onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
console.log('result======1=' + result)
console.log('result======2=' + JSON.stringify(result))
if (result === SaveButtonOnClickResult.SUCCESS) {
try {
const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
// 免去权限申请和权限请求等环节,获得临时授权,保存对应图片
let helper = photoAccessHelper.getPhotoAccessHelper(context);
try {
// 指定文件类型、后缀和创建选项,创建图片或视频资源。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.getMediaContentSync(this.image.id)
// 写入文件,file.fd:文件的文件描述符
await fs.write(file.fd, content?.buffer);
// 关闭文件
await fs.close(file.fd);
promptAction.openToast({
message: '图片已成功保存至相册!',
duration: 4000
});
} catch (error) {
promptAction.openToast({
message: '图片保存至相册失败:' + JSON.stringify(error),
duration: 4000
});
}
} catch (err) {
console.error(`create asset failed with error: ${err.code}, ${err.message}`);
}
} else {
promptAction.openToast({
message: '设置权限失败!',
duration: 5000
});
}
})
.width(130)
.height(35)
}
.width('100%')
.height('100%')
}
}
图片存放路径如下:

页面效果如下:

3. 小结
本文通过实战小案例代码演示了两种保存图片到图库的方式,大家可以根据自己项目的实际情况选择一种方式实现图片保存操作。
最后,希望这篇文章能够帮助到各位朋友!如果有任何问题,欢迎在评论区交流讨论!