HarmonyOS 鸿蒙Next中动态图片保存至图库报错
HarmonyOS 鸿蒙Next中动态图片保存至图库报错

按照上面的指导,但是出现报错:create moving photo failed with error: 401, Failed to check video resource of moving photo,如何解决?
更多关于HarmonyOS 鸿蒙Next中动态图片保存至图库报错的实战教程也可以访问 https://www.itying.com/category-93-b0.html
尊敬的开发者,您好, 关于您的反馈的问题, 根据您提供的错误信息“create moving photo failed with error: 401, Failed to check video resource of moving photo”,错误码401在HarmonyOS开发中通常表示参数检查失败或参数非法。
结合动态图片开发流程,应重点检查与视频资源相关的参数完整性与有效性,URI格式是否符合规范,同时确保该URI指向的文件存在且未被损坏。 推荐使用以下形式来确保URI格式规范性:
let imageFileUri = 'file://' + context.filesDir + '/imported_photo.jpg';
let videoFileUri = 'file://' + context.filesDir + '/imported_photo.mp4';
后续有任何问题,提供更详细的错误记录和信息有助于帮助您解决问题,欢迎您随时提问。
更多关于HarmonyOS 鸿蒙Next中动态图片保存至图库报错的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
视频资源检查不通过,视频不要超过10秒。

把附件下载后去掉.txt,放resource目录下的resfile(没有建一个)里,跑下面代码就可以在相册生成动态图片。
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { common } from '@kit.AbilityKit';
// ...
@Entry
@Component
export struct Scene1 {
@State statusMessage: string = '';
@State imageSource: string = '';
saveButtonOptions: SaveButtonOptions = {
icon: SaveIconStyle.FULL_FILLED,
text: SaveDescription.SAVE_IMAGE,
buttonType: ButtonType.Capsule
}// Set properties of SaveButton.
// ...
build() {
NavDestination() {
Column({ space: 20 }) {
SaveButton(this.saveButtonOptions)
.onClick(async (event, result: SaveButtonOnClickResult) => {
if (result == SaveButtonOnClickResult.SUCCESS) {
try {
let context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
// Ensure that the assets specified by imageFileUri and videoFileUri exist.
let imageFileUri = 'file://' + context.resourceDir + '/hello.jpeg';
let videoFileUri = 'file://' + context.resourceDir + '/sea.mp4';//加载的视频不要超过10秒
let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest =
photoAccessHelper.MediaAssetChangeRequest.createAssetRequest(context,
photoAccessHelper.PhotoType.IMAGE, 'jpg', {
title: 'moving_photo',
subtype: photoAccessHelper.PhotoSubtype.MOVING_PHOTO
});
assetChangeRequest.addResource(photoAccessHelper.ResourceType.IMAGE_RESOURCE, imageFileUri);
assetChangeRequest.addResource(photoAccessHelper.ResourceType.VIDEO_RESOURCE, videoFileUri);
await phAccessHelper.applyChanges(assetChangeRequest);
this.statusMessage = 'create moving photo successfully, uri: ' + assetChangeRequest.getAsset().uri;
console.info('create moving photo successfully, uri: ' + assetChangeRequest.getAsset().uri);
} catch (err) {
this.statusMessage = `create moving photo failed with error: ${err.code}, ${err.message}`;
console.error(`create moving photo failed with error: ${err.code}, ${err.message}`);
}
} else {
this.statusMessage = 'SaveButtonOnClickResult create moving photo failed';
console.error('SaveButtonOnClickResult create moving photo failed');
}
})
// ...
}
.width('100%')
.height('100%')
}
.title('Save Moving Photo')
}
}
1. 代码逻辑解析
代码片段使用了华为 photoAccessHelper API(基于 HarmonyOS 文档),核心流程如下:
// 1. 创建动态照片请求(类型为 IMAGE,子类型为 MOVING_PHOTO)
const changeRequest = photoAccessHelper.MediaAssetChangeRequest.createAssetRequest(
context,
photoAccessHelper.PhotoType.IMAGE, // 资源类型:图片
imageExtension,
{
title: util.generateRandomUUID(),
subtype: photoAccessHelper.PhotoSubtype.MOVING_PHOTO // 动态照片类型
}
);
// 2. 添加资源(关键步骤)
changeRequest.addResource(
photoAccessHelper.ResourceType.IMAGE_RESOURCE,
{ file: '/data/storage/el2/.../1779351671492.jpg' } // 图片资源路径
);
changeRequest.addResource(
photoAccessHelper.ResourceType.VIDEO_RESOURCE,
{ file: '/data/storage/el2/.../1779351671492.mp4' } // 视频资源路径
);
// 3. 提交请求(触发报错)
await photoAccessHelper.applyChanges(changeRequest);
2. 关键报错点
- 错误码
401:在 HarmonyOS 中,401通常表示 权限不足 或 资源未通过安全校验。 - 错误信息:
Failed to check video resource of moving photo
明确指向 视频资源检查失败,说明问题出在VIDEO_RESOURCE的处理环节。
3. 可能原因分析
| 可能原因 | 具体说明 |
|---|---|
| 权限缺失 | 未声明 ohos.permission.WRITE_MEDIA 或 ohos.permission.READ_MEDIA 权限,导致无法访问视频资源。 |
| 视频路径无效 | file 路径指向的视频文件不存在、格式不支持(如非 MP4),或路径权限不足(如 el2 路径需沙箱访问)。 |
| 动态照片类型不匹配 | MOVING_PHOTO 要求同时提供图片和视频资源,但视频资源可能不符合规范(如时长、分辨率)。 |
| API 使用不合规 | 未按文档要求初始化 photoAccessHelper,或 context 未正确传递(如 Activity 上下文)。 |
4. 解决方案建议
✅ 步骤 1:检查权限声明
在 module.json5 中添加必要权限:
{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.WRITE_MEDIA",
"reason": "保存动态照片需要写入媒体库"
},
{
"name": "ohos.permission.READ_MEDIA",
"reason": "读取视频资源需要权限"
}
]
}
}
✅ 步骤 2:验证视频资源
- 确保视频文件路径有效(通过
fileAPI 检查文件是否存在)。 - 确认视频格式为 MP4(HarmonyOS 动态照片通常要求 H.264 编码)。
- 检查路径是否属于应用沙箱(如
context.filesDir路径)。
✅ 步骤 3:参考官方文档规范
- 动态照片需同时提供 图片(.jpg) 和 视频(.mp4),且两者需为同一内容(如视频截图与视频匹配)。
- 严格按文档示例构造
createAssetRequest参数(官方文档链接)。
✅ 步骤 4:调试建议
- 在
addResource后添加日志,确认视频文件路径是否可读:
console.log("Video file exists:", await file.exists(videoPath));
- 捕获更详细的错误信息:
catch (err) {
console.error("Detailed error:", JSON.stringify(err));
}
总结
该报错的核心是 视频资源校验失败,需优先排查 权限、路径有效性、视频格式 三方面问题。
401 错误在 HarmonyOS 中多与权限相关,建议先确保权限声明完整,并验证视频资源的合规性。
(注:动态照片功能需同时满足图片和视频的规范,缺一不可)
你好,错误码401可能权限不足,使用安全控件保存动态照片资源,无需申请相册管理模块权限’ohos.permission.WRITE_IMAGEVIDEO’,允许用户通过点击按钮临时获取存储权限,并将资源直接保存到指定的媒体库路径,使得操作更为便捷。详情请参考SaveButton
不要写死沙箱目录,而是根据context去获取沙箱路径,参考示例:
SaveButton(this.saveButtonOptions)
.onClick(async (event, result: SaveButtonOnClickResult) => {
if (result == SaveButtonOnClickResult.SUCCESS) {
try {
let context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
// Ensure that the assets specified by imageFileUri and videoFileUri exist.
let imageFileUri = 'file://' + context.filesDir + '/create_moving_photo.jpg';
let videoFileUri = 'file://' + context.filesDir + '/create_moving_photo.mp4';
...
})
这个报错:
401, Failed to check video resource of moving photo
本质上不是权限问题,
而是:
你传入的 mp4 不符合“动态照片(Moving Photo)”规范。
⸻
HarmonyOS 的:
PhotoSubtype.MOVING_PHOTO
并不是:
“随便一张 jpg + 一个 mp4”
拼起来就行。
系统会校验:
- 视频编码
- 时长
- 分辨率
- metadata
- 图片与视频关联信息
如果不符合规范,
就会:
Failed to check video resource
⸻
最常见原因有这些:
1、mp4 不是系统支持的编码(最常见)
建议:
H264 + AAC
很多:
- HEVC
- AV1
- 特殊编码
会失败。
⸻
2、视频时长不符合
Moving Photo 不是普通长视频。
一般要求:
- 很短的视频
- 通常几秒内
如果:
- 视频太长
- 空视频
- 0帧视频
也会失败。
⸻
3、jpg 和 mp4 不匹配
动态照片要求:
- 图片封面
- 视频内容
属于同一拍摄资源。
如果:
- 随便找个 jpg
- 再随便找个 mp4
很多时候校验过不了。
⸻
4、mp4 文件路径不合法
你这里:
file://xxx.mp4
注意:
必须是真实可访问文件。
很多人:
- 文件不存在
- 还没 flush
- 没有读权限
- 临时文件被删
也会触发这个错误。
建议先验证:
fileIo.accessSync(path)
是否真存在。
⸻
5、不是“动态照片源文件”
这个特别关键。
HarmonyOS Moving Photo:
更偏向:
“系统动态照片格式”。
不是:
“普通图片 + 普通视频”。
所以:
最稳的方式是:
使用系统拍摄生成的动态照片资源。
而不是业务自己拼。
⸻
你这个场景里,
我怀疑最大概率是:
mp4 本身不符合 Moving Photo 规范。
⸻
建议这样排查:
先用系统相机拍一张:
动态照片
然后:
导出:
- jpg
- mp4
再替换你自己的资源测试。
如果系统资源能成功,
说明:
你的 mp4 格式有问题。
⸻
另外再注意:
图片和视频:
最好:
- 同尺寸
- 同拍摄比例
- 同来源
不要:
64x64 jpg + 1920x1080 mp4
这种。
⸻
一句话总结:
HarmonyOS 的 Moving Photo 不是简单 jpg+mp4 拼接,系统会校验视频资源是否合法;你这个 401 大概率是 mp4 编码、时长、metadata 或资源匹配不符合动态照片规范导致的。
if (result == SaveButtonOnClickResult.SUCCESS) {
try {
let context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
// Ensure that the assets specified by imageFileUri and videoFileUri exist.
let imageFileUri = 'file://' + context.filesDir + '/create_moving_photo.jpg';
let videoFileUri = 'file://' + context.filesDir + '/create_moving_photo.mp4';
let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest =
photoAccessHelper.MediaAssetChangeRequest.createAssetRequest(context,
photoAccessHelper.PhotoType.IMAGE, 'jpg', {
title: 'moving_photo',
subtype: photoAccessHelper.PhotoSubtype.MOVING_PHOTO
});
官方实例大概也是这意思啊,
你好,开发建议:完全复制文档中的示例代码,准备资源文件上传到应用沙箱目录,仅替换jpg和mp4文件名,再验证是否可以保存动态图片。
看着像是文件路径有问题,打码的那段是注释了还是有前缀,建议用
getContext().filesDir
获取文件路径
HarmonyOS 鸿蒙Next中动态图片保存至图库报错,通常因未正确使用 PhotoAccessHelper API(如未传入有效 Uri 或未添加写权限 ohos.permission.WRITE_IMAGEVIDEO)。需确保动态图片格式为系统支持的 HEIF/PNG 序列,并使用 ImagePacker 或 Picture.createCopy 方法生成符合系统标准的资源。检查文件路径是否合法并调用 MediaAssetManager 进行保存。
报错“401, Failed to check video resource of moving photo”表明动态照片创建时无法校验视频资源。通常原因是传入的视频 URI 对应的文件不符合要求或不可访问。请检查以下几点:
- 视频格式:动态照片的视频部分要求 MP4 格式(H.264/H.265 编码),且时长需在 0.5 秒 ~ 3 秒之间(部分接口限制为 0.5~1.5 秒)。确认视频符合该约束。
- URI 有效性:确保 videoUri 指向应用沙箱内的已有文件(如通过临时路径创建并写入),且 未被删除或移动。若使用
file:///路径,请确认文件读写权限正常。 - 预备资源文件大小/参数:视频分辨率建议与图片适配,过高分辨率可能导致校验失败。尝试使用 1920×1080 或更低分辨率。
- URI 格式:需使用正确的 URI 格式,如通过
fileUri.getUriFromPath()获取。避免传入媒体库 URI(media://)而应使用真实文件路径。 - 视频完整性:确保视频数据已完全写入并关闭文件句柄后,再调用
createMovingPhoto。
若上述检查均无误,可尝试用官方示例中的视频参数重新生成视频片段,以排除视频编码问题。

