HarmonyOS实战:一招搞定保存图片到相册

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
实时计算 Flink 版,5000CU*H 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
简介: 本文介绍了在鸿蒙系统中实现保存图片到相册的功能,包括申请权限和使用系统安全控件两种方式。文中详细讲解了如何通过网络请求下载图片并保存为本地文件,以及如何将指定布局生成图片并保存。鸿蒙系统对权限管理较为严格,推荐使用系统提供的安全控件(如 SaveButton)以保护用户隐私,避免手动申请权限。此外,文章还对比了鸿蒙与 Android/iOS 的实现差异,指出鸿蒙在功能实现上更简单,但需注意权限规范以确保项目顺利上线。

前言

保存图片功能几乎是每个应用程序必备的功能之一,当用户遇到喜欢的图片时可以保存到手机相册。那么在鸿蒙中保存图片是否也需要申请用户存储权限以及如何将图片保存到相册,本文将详细讲述怎么保存网络图片,指定布局生成图片保存至相册的功能实现。

实现效果

需求分析

一般在 Android 或 iOS 上保存图片都需要申请应用存储权限,否则将禁止访问应用存储,不能保存图片到磁盘中。在鸿蒙系统中当然也有存储权限,但是鸿蒙系统对于权限管理十分严格,一般情况下,禁止用户申请访问存储权限。但是提供了系统级别的安全控件,不需要用户手动申请权限,用于存储的直接访问。

  1. 可以使用系统提供的安全控件实现权限的直接访问。
  2. 同时也提供申请权限方式进行存储权限的访问。
  3. 使用网络请求将图片转成流,然后保存成图片。

技术实现

申请权限方式

  1. 权限申请
const permissions: Array<Permissions> = [
  'ohos.permission.WRITE_IMAGEVIDEO'
];
const context = getContext(this) as common.UIAbilityContext;
const atManager = abilityAccessCtrl.createAtManager();
await atManager.requestPermissionsFromUser(context, permissions);
  1. 权限判断
PermissionUtil.checkAccessToken(permissions[0]).then((status)=>{
            if (status == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
              FileSaveManager.getPicture(this.imagePath)
            }else{
              PermissionUtil.openPermissionsInSystemSettings(getContext(this) as common.UIAbilityContext)
            }
   })

安全控件方式

SaveButton({ text: SaveDescription.SAVE_IMAGE, buttonType: ButtonType.Normal })
           .fontColor(Color.White)
           .fontWeight(FontWeight.Medium)
           .onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
             if (result == SaveButtonOnClickResult.SUCCESS) {
               try {
                 this.saveImage()
               } catch (error) {
                 console.error("error is " + JSON.stringify(error));
               }
             }
           })

可以看出通过系统安全控件 SaveButton 可以临时访问系统存储,不需要申请任何权限。更好的保护用户隐私安全,这也是鸿蒙官方提倡使用的方式。

网络图片保存

  1. 下载图片,并将数据转化为 ArrayBuffer 类型。
/**
   * 通过http的request方法从网络下载图片资源
   */
  static async getPicture(url:string) {
    http.createHttp()
      .request(url,
        (error: Error, data: http.HttpResponse) => {
          if (error) {
            showShortCenterToast("图片保存失败")
            return;
          }
          // 判断网络获取到的资源是否为ArrayBuffer类型
          if (data.result instanceof ArrayBuffer) {
            FileSaveManager.saveImageToPhoto(data.result as ArrayBuffer)
          }
        }
      )
  }
  1. 保存图片到相册
/**
   * 保存ArrayBuffer到图库
   * @param buffer:图片ArrayBuffer
   * @returns
   */
  static async saveImageToPhoto(buffer: ArrayBuffer | string): Promise<void> {
    const context = getContext() as common.UIAbilityContext; // 获取getPhotoAccessHelper需要的context
    const helper = photoAccessHelper.getPhotoAccessHelper(context); // 获取相册管理模块的实例
    const uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 指定待创建的文件类型、后缀和创建选项,创建图片或视频资源
    const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
    let r =  await fs.write(file.fd, buffer);
    await fs.close(file.fd);
    showShortCenterToast("图片保存成功")
  }

指定布局保存

在 Android 或 iOS 中,经常会遇到需要保存指定样式的布 View 为图片。Android 中则需要使用 View 的绘制,将布局绘制出来后,再进行保存。但是在鸿蒙中实现起来就比较简单。

 1. 将需要保存的 View 布局指定 Id。

Column() {
    //布局样式
  } 
.id("root")
  1. 通过 id 将 View 保存成图片。
componentSnapshot.get("photo", (error: Error, pixmap: image.PixelMap) => {
                  if (error) {
                    console.log("error: " + JSON.stringify(error))
                    return;
                  }
                  const  packOpts : image.PackingOption = { format:"image/jpeg", quality:98 };
                  imagePackerApi.packing(pixmap, packOpts).then( async (data : ArrayBuffer) => {
                    FileSaveManager.saveImageToPhoto(data)
                  }).catch((error : BusinessError) => {
                    console.error('Failed to pack the image. And the error is: ' + error);
                  })
                })

总结

对比 Android 或 iOS 来说,鸿蒙在实现功能上相对简单,比较容易上手。但是鸿蒙对于用户权限的获取要求比较严格,正式上线一般都需要使用系统提供的安全组件访问应用程序的相册或存储,日常开发中需要十分注意,以免影响项目的正常上线。

目录
相关文章
|
11天前
|
定位技术 UED
70. [HarmonyOS NEXT 实战案例九] 旅游景点网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的旅游景点网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的旅游景点应用。
28 1
|
11天前
|
容器
69.[HarmonyOS NEXT 实战案例九] 旅游景点网格布局(上)
本教程将详细讲解如何使用HarmonyOS NEXT中的GridRow和GridCol组件实现旅游景点网格布局。通过网格布局,我们可以以美观、规整的方式展示各种旅游景点信息,为用户提供良好的浏览体验。
24 1
|
11天前
|
UED
68.[HarmonyOS NEXT 实战案例八] 电影票务网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的电影票务网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的电影票务应用。
31 1
|
11天前
|
开发者 容器
67.[HarmonyOS NEXT 实战案例八] 电影票务网格布局(上)
在移动应用开发中,电影票务应用是一个常见的场景,用户可以通过应用查看正在热映的电影信息,并进行选座购票等操作。本教程将详细讲解如何使用HarmonyOS NEXT的GridRow和GridCol组件实现电影票务应用中的电影列表网格布局,帮助开发者掌握网格布局的基本用法和实现技巧。
23 1
|
11天前
|
UED
66.[HarmonyOS NEXT 实战案例七] 健身课程网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的健身课程网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的健身课程应用。
20 1
|
11天前
|
设计模式 UED
65. [HarmonyOS NEXT 实战案例七] 健身课程网格布局(上)
本教程将介绍如何使用HarmonyOS NEXT的GridRow和GridCol组件实现健身课程的网格布局展示。健身课程网格布局是一种常见的UI设计模式,适用于展示各种健身课程信息,包括课程名称、教练信息、课程时长、难度级别等。通过网格布局,用户可以快速浏览多个课程,并根据自己的需求选择合适的课程。
26 1
|
11天前
|
设计模式 容器
61.[HarmonyOS NEXT 实战案例五] 社交应用照片墙网格布局(上)
社交应用中的照片墙是一种常见的UI设计模式,它以网格形式展示用户的照片集合,让用户可以浏览、分享和互动。本教程将详细讲解如何使用HarmonyOS NEXT的GridRow和GridCol组件实现一个美观、灵活的社交应用照片墙网格布局。 在本教程中,我们将学习如何设计照片墙的数据结构、如何使用GridRow和GridCol组件创建网格布局、如何实现照片卡片,以及如何处理不同尺寸的照片。通过本教程,你将掌握使用GridRow和GridCol组件实现复杂网格布局的技巧。
22 1
|
11天前
64.[HarmonyOS NEXT 实战案例六] 餐饮菜单网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的餐饮菜单网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的餐饮菜单应用。
17 0
|
11天前
|
存储
63.[HarmonyOS NEXT 实战案例六] 餐饮菜单网格布局(上)
在移动应用开发中,餐饮类应用的菜单展示是一个常见的需求。一个设计良好的菜单布局不仅能够清晰地展示菜品信息,还能提升用户的点餐体验。本教程将详细讲解如何使用HarmonyOS NEXT的GridRow和GridCol组件实现一个美观实用的餐饮菜单网格布局。
24 0
|
11天前
|
UED
62. [HarmonyOS NEXT 实战案例五] 社交应用照片墙网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的社交应用照片墙网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的社交应用照片墙。
21 0