【HarmonyOS NEXT】实现网络图片保存到手机相册

devtools/2024/10/21 11:53:26/

【问题描述】
给定一个网络图片的地址,实现将图片保存到手机相册

【API】

phAccessHelper.showAssetsCreationDialog

【官方文档】
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-photoaccesshelper-V5#showassetscreationdialog12

【完整代码】

import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import util from '@ohos.util';
import { fileUri } from '@kit.CoreFileKit';
import fs, { ReadOptions } from '@ohos.file.fs';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { dataSharePredicates } from '@kit.ArkData';
import { promptAction } from '@kit.ArkUI';@Entry
@Component
struct SaveAlbum {@State message: string = 'Hello World';url1: string = "https://img20.360buyimg.com/img/jfs/t1/241153/31/4968/64736/65e53e56Fd3868b6e/b595d41ca8447ea4.jpg";url2: string ="https://upfile-drcn.platform.hicloud.com/ptTJ5B1eJ6k-d45UmOTF0Q.FYlVoBLGO3P9jZfjPUtqh2Cry9mQBzJButWu-okMhg2Xsd4zaoBTVAAsA08DPk1Vn7VFa1Mpl1Dp112CNKhEBjd4a9kP2NCKrQUpgq0HP_E3uqofnQ.6099200.png";build() {Column({ space: 30 }) {Text('保存到相册').fontSize(30)Column() {Text(this.url1)Button("保存").onClick(() => {this.downloadAndSave(this.url1)})}.margin({ top: 15, bottom: 15 })Column() {Text(this.url2)Button("保存").onClick(() => {this.downloadAndSave(this.url2);})}.margin({ top: 15, bottom: 15 })}.justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).height('100%').width('100%')}downloadAndSave(url: string) {const arr = url.split('.')const type = arr[arr.length -1]httpDownload(url, type).then((result: DownloadResult) => {if (result.isSuccess) {promptAction.showToast({ message: "下载成功" })} else {console.error("失败:" + result.msg);promptAction.showToast({ message: "下载失败❌,请查看日志" })}})}
}interface DownloadResult {isSuccess: boolean,msg: string
}async function httpDownload(imgUrl: string, imgType: string): Promise<DownloadResult> {return new Promise((resolve, reject) => {http.createHttp().request(imgUrl, async (error: BusinessError, data: http.HttpResponse) => { // 下载失败if (error) {return resolve({ isSuccess: false, msg: "下载失败" });} // 数据格式不正确if ((data.result instanceof ArrayBuffer) == false) {return resolve({ isSuccess: false, msg: "图片保存失败:数据流不支持" });} // 保存到Cache目录下let imageBuffer: ArrayBuffer = data.result as ArrayBuffer;const newFileName = util.generateRandomUUID() + "." + imgType;const newFilePath = getContext().cacheDir + "/" + newFileName;const newFileUri = fileUri.getUriFromPath(newFilePath);let file: fs.File = await fs.open(newFileUri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);await fs.write(file.fd, imageBuffer);await fs.close(file);console.info("文件路径:" + newFileUri); // 保存成功 // resultData.status = 3; // return resolve(resultData);saveImageToAsset(newFileUri, imgType).then(() => { // 保存成功return resolve({ isSuccess: true, msg: "保存成功" });}).catch((error: Error) => { // 保存失败return resolve({ isSuccess: false, msg: "保存失败:" + error.message });});});})
}async function saveImageToAsset(uri: string, nameExtension: string): Promise<void> {console.info('ShowAssetsCreationDialogDemo: ' + uri);try {let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(getContext()); // 获取需要保存到媒体库的位于应用沙箱的图片/视频urilet srcFileUris: Array<string> = [uri];let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [{title: 'test2', // 可选fileNameExtension: nameExtension,photoType: photoAccessHelper.PhotoType.IMAGE, // 可选,支持:普通图片、动态图片subtype: photoAccessHelper.PhotoSubtype.DEFAULT,}];let desFileUris: Array<string> = await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);console.info('showAssetsCreationDialog success, data is ' + desFileUris);if (desFileUris.length == 0) { // 用户拒绝保存throw (new Error("用户拒绝保存"))}await createAssetByIo(uri, desFileUris[0]);return Promise.resolve();} catch (err) {console.error('showAssetsCreationDialog failed, errCode is ' + err.code + ', errMsg is ' + err.message);return Promise.reject(err);}
}let context = getContext(this);
const createAssetByIo = async (sourceFilePath: string, targetFilePath: string) => {try {console.log(`context.fileDir ===> ${context.filesDir}`)let srcFile: fs.File = fs.openSync(sourceFilePath, fs.OpenMode.READ_ONLY);let targetFile: fs.File = await fs.open(targetFilePath, fs.OpenMode.READ_WRITE);let bufSize = 14096;let readSize = 0;let buf = new ArrayBuffer(bufSize);let readOptions: ReadOptions = { offset: readSize, length: bufSize };let readLen = fs.readSync(srcFile.fd, buf, readOptions);while (readLen > 0) {readSize += readLen;fs.writeSync(targetFile.fd, buf, { length: readLen });readOptions.offset = readSize;readLen = fs.readSync(srcFile.fd, buf, readOptions);}fs.closeSync(srcFile);fs.closeSync(targetFile);} catch (error) {console.error(`createAssetByIo :: error , msg is ${error} `);}
}

【效果图】

【其它问题】
关于授权窗,没显示图片缩略图的问题,官方有答复是下载最新版本的IDE
在这里插入图片描述


http://www.ppmy.cn/devtools/113240.html

相关文章

re题(24)BUUFCTF-[WUSTCTF2020]level1

BUUCTF在线评测 (buuoj.cn) 放到ida 这是下载的文本 逻辑比较简单&#xff0c;写个脚本 p[198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000] for i in range(1,20):if (i & 1) ! 0 :p[i-1]chr(p[i-1] >> i)…

expect自动登录ssh,ftp

expect是一种能够按照脚本内容里面设定的方式与交互式程序进行“会话”的程序。根据脚本内容&#xff0c;Expect可以知道程序会提示或反馈什么内容以及 什么是正确的应答。它是一种可以提供“分支和嵌套结构”来引导程序流程的解释型脚本语言。 shell功能很强大,但是不能实现有…

苹果发布新款iPhone 16,与Apple Intelligence配套:查看功能和价格

在2024年9月9日&#xff08;星期一&#xff09;的苹果Glowtime活动中&#xff0c;Apple在其位于加利福尼亚州库比蒂诺总部的Apple Park发布了新款iPhone 16。 苹果公司首席执行官蒂姆库克在2024年9月9日&#xff08;星期一&#xff09;于加利福尼亚州库比蒂诺的Apple Park校园…

目标检测经典算法的个人理解

one stage 1、RCNN -> Fast-RCNN&#xff1a;RPN部分从用传统的算法 -> 用深度学习网络来实现。 2、Fast-RCNN -> Faster-RCNN&#xff1a;从先选region再求Feature -> 先求Feature再选region。 two stage 1、SSD&#xff08;2016&#xff09;&#xff1a;VGG做…

【系统架构设计师-2010年真题】案例分析-答案及详解

更多内容请见: 备考系统架构设计师-核心总结索引 文章目录 【材料1】【问题 1】(7 分)【问题 2】(13 分)【问题 3】(6 分)【材料2】【问题 1】(8 分)【问题 2】(13 分)【问题 3】(4 分)【材料3】【问题 1】(共 7 分)【问题 2】(共 10 分)【问题 3】(共 8 分)【材料4】【问题 1…

MYSQL数据库基础篇——MYSQL的安装与使用

一.下载并安装MYSQL 下载mysql&#xff0c;地址MySQL,进行如下操作​​​​&#xff1a; ​​​ 安装好后&#xff0c;接下来配置信息&#xff1a; 这里选择第一个&#xff0c;当然&#xff0c;有可能你的版本下的MYSQL并没有这个选项&#xff0c;那么我们可以选择Custom&…

Leetcode面试经典150题-350.两个数组的交集II

题目比较简单&#xff0c;散散心吧 这个题竟然是349更简单的版本&#xff0c;可以先看看349题的解法&#xff1a; Leetcode面试经典150题-349.两个数组的交集-CSDN博客 349会了&#xff0c;这个也就会了 解法都在代码里&#xff0c;不懂就留言或者私信 class Solution {/…

基于SpringBoot+Vue+MySQL的网上甜品蛋糕售卖店管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 在数字化浪潮的推动下&#xff0c;我们设计了一款基于SpringBoot后端框架、Vue前端框架及MySQL数据库的网上甜品蛋糕售卖店管理系统。该系统旨在帮助甜品蛋糕店实现线上线下的无缝对接&#xff0c;提升运营效率与顾客体验。通过…