介绍
在HarmonyOS里面对于权限的要求是很严格的,在日常的开发中往往又有保存图片或者音频到本地的开发需求,因此我们可以使用非权限的替代方案实现功能,主要就是使用安全控件或者是授权弹框来实现资源的保存。
实现
安全控件
官方链接:文档中心
实现效果
代码实现
import { http } from '@kit.NetworkKit';
import { image } from '@kit.ImageKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';
import { promptAction } from '@kit.ArkUI';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
@Entry
@Component
struct Index {
@State url: string =
'https://qcloud.dpfile.com/pc/TrdZpLN1zkXDV4oN2FH98LdVnvHj694NKQu0_KA3ul4eYxZWRPQ7CJuw-PqyZBS4.jpg'
loadImageWithUrl(url: string) {
let responseCode = http.ResponseCode;
let OutData: http.HttpResponse;
let imagePackerApi = image.createImagePacker();
let packOpts: image.PackingOption = { format: 'image/jpeg', quality: 98 };
let pixelMap: PixelMap | undefined = undefined;
// 确保网络正常
http.createHttp().request(url, {
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 {
OutData = data;
let code: http.ResponseCode | number = OutData.responseCode;
if (responseCode.OK === code) {
let imageData: ArrayBuffer = OutData.result as ArrayBuffer;
let imageSource: image.ImageSource = image.createImageSource(imageData);
class tmp {
height: number = 100
width: number = 100
};
let options: Record<string, number | boolean | tmp> = {
'alphaType': 0, // 透明度
'editable': false, // 是否可编辑
'pixelFormat': 3, // 像素格式
'scaleMode': 1, // 缩略值
'size': { height: 100, width: 100 }
}; // 创建图片大小
imageSource.createPixelMap(options).then((pixelMap1: PixelMap) => {
pixelMap = pixelMap1;
pixelMap.getImageInfo().then((info: image.ImageInfo) => {
console.info('info.width = ' + info.size.width);
}).catch((err: BusinessError) => {
console.error('Failed ' + err);
})
imagePackerApi.packing(pixelMap, packOpts).then(async (buffer: ArrayBuffer) => {
try {
const context = getContext();
let helper = photoAccessHelper.getPhotoAccessHelper(context);
let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png');
let file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
// 写入文件
await fileIo.write(file.fd, buffer);
promptAction.showToast({ message: '已保存至相册!', alignment: Alignment.Center });
// 关闭文件
await fileIo.close(file.fd);
} catch (error) {
console.error('error is ' + JSON.stringify(error));
}
}).catch((error: BusinessError) => {
console.error('Failed to pack the image. And the error is: ' + error);
})
pixelMap.release();
})
}
}
}
)
}
build() {
Column({ space: 20 }) {
Image(this.url)
.width(100)
.height(100)
SaveButton({
icon: SaveIconStyle.FULL_FILLED,
text: SaveDescription.SAVE_IMAGE,
buttonType: ButtonType.Normal
})
.onClick((_event, result) => {
if (result === SaveButtonOnClickResult.SUCCESS) {
this.loadImageWithUrl(this.url as string);
// this.loadImageWithUrl(this.img as string);
} else {
promptAction.showToast({ message: '设置权限失败!', alignment: Alignment.Center });
}
})
}
.width('100%')
.padding({ top: 50, left: 20 })
}
}
授权弹框
官方链接:文档中心
实现效果
代码实现
import { request } from '@kit.BasicServicesKit'
import { fileIo, fileUri } from '@kit.CoreFileKit'
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import { promptAction } from '@kit.ArkUI'
import { Context } from '@kit.AbilityKit'
@Entry
@Component
struct Index {
@State Img: string =
'https://qcloud.dpfile.com/pc/h0jK_DfiFV_fQjL3CQpOVgRTnPIjwQlmZHNHjRv2n3Yrg3bZmogVH6Ln8ywR4Guo.jpg'
@State filePath: string = ''
context: Context = getContext(this)
async downloadPicture() {
// 设置沙箱路径
let filePath = getContext().cacheDir + '/test' + Date.now() + '.png'
// 创建下载任务
const task = await request.downloadFile(getContext(), {
// 设置图片的源地址
url: this.Img,
// 设置图片存储路径
filePath: filePath
})
task.on('complete', async () => {
this.filePath = filePath
this.filePath = fileUri.getUriFromPath(filePath)
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context);
try {
let srcFileUri = filePath;
let srcFileUris: Array<string> = [
fileUri.getUriFromPath(srcFileUri)
];
let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [
{
title: 'test', // 可选
fileNameExtension: 'png',
photoType: photoAccessHelper.PhotoType.IMAGE,
subtype: photoAccessHelper.PhotoSubtype.DEFAULT, // 可选
}
];
let desFileUris: Array<string> =
await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);
let desFile: fileIo.File =
await fileIo.open(desFileUris[0], fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
let srcFile: fileIo.File = await fileIo.open(srcFileUri, fileIo.OpenMode.READ_ONLY);
await fileIo.copyFile(srcFile.fd, desFile.fd);
fileIo.closeSync(srcFile);
fileIo.closeSync(desFile);
fileIo.rmdirSync(filePath)
promptAction.showToast({ message: '保存成功!' })
} catch (err) {
console.error(`failed to create asset by dialog successfully errCode is: ${err.code}, ${err.message}`);
}
})
}
build() {
Column({ space: 20 }) {
Image(this.Img)
.width(100)
.height(100)
Button('保存图片')
.onClick(async () => {
this.downloadPicture()
})
}
.width('100%')
.height('100%')
.padding({ top: 50, left: 30 })
}
}
总结
本文主要介绍了两种可以不用通过申请相册的读、写权限来实现保存图片的替代方案。在功能的实现方面,代码还是很简单,但是由于HarmonyOS对于权限的审核还是很严格,因此,还需要我们在实际的开发过程中,找到更多的可替代方案,希望大家多多交流,早日完善鸿蒙系统的生态!