HarmonyOS鸿蒙Next中在不申请写入权限(ohos.permission.WRITE_IMAGEVIDEO)的情况下,把图片保存至相册
HarmonyOS鸿蒙Next中在不申请写入权限(ohos.permission.WRITE_IMAGEVIDEO)的情况下,把图片保存至相册
在不申请写入权限(ohos.permission.WRITE_IMAGEVIDEO)的情况下,把图片保存至相册
麻烦提供一下Demo,谢谢
3 回复
参考demo:
//Constants.ets
export const BASE64_IMAGE_STR = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QBYRXhpZgAATU0AKgAAAAgAAgESAAMAAAABAAEAAIdpAAQAAAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAACPKADAAQAAAABAAADWQAAAAD/7QA4UGhvdG9zaG9wIDMuMA'
因文件太大,请自行准备......
```javascript
//SaveImageUtil.ets
/**
* 保存图片工具类
*/
import { BusinessError, request } from '[@kit](/user/kit).BasicServicesKit'
import { common } from '[@kit](/user/kit).AbilityKit'
import { buffer } from '[@kit](/user/kit).ArkTS'
import { fileIo as fs, fileUri } from '[@kit](/user/kit).CoreFileKit'
import { photoAccessHelper } from '[@kit](/user/kit).MediaLibraryKit'
import { FileUtil } from './FileUtil'
/**
* 保存文件到应用沙箱
* [@param](/user/param) image 图片url或base64
* [@param](/user/param) dirPath 保存文件夹路径
* [@param](/user/param) fileName 保存文件名
*/
async function saveImageToApplication(image: string, dirPath: string, fileName: string): Promise<SaveImageResultVo> {
return new Promise(async (resolve: Function, reject: Function) => {
if (!fs.accessSync(dirPath)) {
fs.mkdirSync(dirPath)
}
if (image.startsWith('http')) {
// 如果是网络图片,则下载图片
try {
request
.downloadFile(this.context, { url: image, filePath: `${dirPath}/${fileName}` })
.then((downloadTask) => {
console.debug(`image => 保存图片到应用沙盒`)
downloadTask
.on('complete', () => {
// 图片下载完成
let vo = new SaveImageResultVo
vo.errorCode = 0
resolve(vo)
})
downloadTask
.on('fail', (err: number) => {
let vo = new SaveImageResultVo
vo.errorCode = err
resolve(vo)
})
})
.catch((error: BusinessError) => {
reject(error)
})
} catch (err) {
reject(err)
}
} else {
// base64图片
let content = image
if (image.startsWith('data:')) {
// 如果是data:,则截取,后的数据
content = image.split(',')[1]
}
try {
const decodeBuff = buffer.from(content, 'base64').buffer
FileUtil.writeBufferToFile(dirPath, fileName, decodeBuff)
let vo = new SaveImageResultVo
vo.errorCode = 0
resolve(vo)
} catch (err) {
reject(err)
}
}
})
}
/**
* 保存图片到相册
* [@param](/user/param) path 图片路径
* [@param](/user/param) title 标题
* [@param](/user/param) extension 文件扩展名
* [@returns](/user/returns)
*/
async function saveImageToAlbum(path: string, title?: string, extension?: string): Promise<boolean> {
return new Promise(async (resolve: Function, reject: Function) => {
try {
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context)
let srcFileUri: Array<string> = [fileUri.getUriFromPath(path)]
let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [
{
title: '保存图片',
fileNameExtension: extension ? extension : 'jpg',
photoType: photoAccessHelper.PhotoType.IMAGE,
subtype: photoAccessHelper.PhotoSubtype.DEFAULT
}
]
let desFileUris: Array<string> = await phAccessHelper.showAssetsCreationDialog(srcFileUri, photoCreationConfigs)
if (desFileUris.length > 0) {
for (let index = 0; index < desFileUris.length; index++) {
FileUtil.copyFileContentTo(srcFileUri[index], desFileUris[index])
}
resolve(true)
} else {
resolve(false)
}
} catch (err) {
reject(err)
}
})
}
export class SaveImageResultVo {
errorCode: number = 0
}
export default new SaveImageUtil()
//FileUtil.ets
import fs, { ReadOptions, WriteOptions } from '[@ohos](/user/ohos).file.fs'
import { util } from '[@kit](/user/kit).ArkTS'
import { common } from '[@kit](/user/kit).AbilityKit'
class FileUtil {
private context = getContext(this) as common.UIAbilityContext
/**
* 将内容写入文件
* [@param](/user/param) dirPath 文件及路径
* [@param](/user/param) fileName 文件名称
* [@param](/user/param) content 内容
*/
writeContentToFile(dirPath: string, fileName: string, content: string) {
if (!fs.accessSync(dirPath)) {
// 如果文件夹不存在,则先创建文件夹
fs.mkdirSync(dirPath)
}
let file = fs.openSync(`${dirPath}/${fileName}`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
fs.writeSync(file.fd, content)
fs.closeSync(file)
}
/**
* 保存文件
* [@param](/user/param) dirPath
* [@param](/user/param) fileName
* [@param](/user/param) buf
*/
writeBufferToFile(dirPath: string, fileName: string, buf: ArrayBuffer) {
if (!fs.accessSync(dirPath)) {
// 如果文件夹不存在,则先创建文件夹
fs.mkdirSync(dirPath)
}
let file = fs.openSync(`${dirPath}/${fileName}`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
fs.writeSync(file.fd, buf)
fs.closeSync(file)
}
/**
* 读取文件内容
* [@param](/user/param) filePath 文件路径
* [@returns](/user/returns) 文件内容
*/
readContentFromFile(filePath: string): string {
let result = ''
if (fs.accessSync(filePath)) {
let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY)
let bufSize = 4096
let readSize = 0
let buf = new ArrayBuffer(bufSize)
let readOptions: ReadOptions = {
offset: readSize,
length: bufSize
}
let readLen = fs.readSync(file.fd, buf, readOptions)
result = util.TextDecoder.create('utf-8').decodeWithStream(new Uint8Array(buf))
while (readLen > 0) {
readSize += readLen
readOptions.offset = readSize
readLen = fs.readSync(file.fd, buf, readOptions)
result += util.TextDecoder.create('utf-8').decodeWithStream(new Uint8Array(buf))
}
fs.closeSync(file)
}
return result
}
/**
* 复制文件内容到目标文件
* [@param](/user/param) srcFilePath 源文件路径
* [@param](/user/param) destFilePath 目标文件路径
*/
copyFileContentTo(srcFilePath: string, destFilePath: string) {
let srcFile = fs.openSync(srcFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
let destFile = fs.openSync(destFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
// 读取源文件内容并写入至目的文件
let bufSize = 4096;
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;
let writeOptions: WriteOptions = {
length: readLen
};
fs.writeSync(destFile.fd, buf, writeOptions);
readOptions.offset = readSize;
readLen = fs.readSync(srcFile.fd, buf, readOptions);
}
// 关闭文件
fs.closeSync(srcFile);
fs.closeSync(destFile);
}
/**
* 删除文件
* [@param](/user/param) filePath 文件路径
*/
deleteFile(filePath: string) {
if (fs.accessSync(filePath)) {
fs.rmdirSync(filePath)
}
}
/**
* 将Raw中的文件复制到应用沙盒中
* [@param](/user/param) rawFilePath Raw中文件路径
* [@param](/user/param) destDirPath 目标文件夹路径
* [@param](/user/param) fileName 文件名
*/
copyRawFileToApplicationStorage(rawFilePath: string, destDirPath: string, fileName: string) {
if (!fs.accessSync(destDirPath)) {
// 如果文件夹不存在,则先创建文件夹
fs.mkdirSync(destDirPath)
}
let srcFile = this.context.resourceManager.getRawFdSync(rawFilePath)
let dest = fs.openSync(`${destDirPath}/${fileName}`, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
let bufSize = 4096
let buf = new ArrayBuffer(bufSize)
let off = 0, len = 0, readLength = 0
while (len = fs.readSync(srcFile.fd, buf, { offset: srcFile.offset + off, length: bufSize })) {
readLength += len
fs.writeSync(dest.fd, buf, { offset: off, length: len })
off = off + len
if ((srcFile.length - readLength) < bufSize) {
bufSize = srcFile.length - readLength
}
}
fs.close(dest.fd)
}
}
export default new FileUtil()
//Index.ets
import { SaveImageResultVo, SaveImageUtil } from './SaveImageUtil'
import { common } from '[@kit](/user/kit).AbilityKit';
import { BusinessError, request } from '[@kit](/user/kit).BasicServicesKit';
import { BASE64_IMAGE_STR } from './Constants';
import { fileIo } from '[@kit](/user/kit).CoreFileKit';
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Index {
private context = getContext(this) as common.UIAbilityContext
build() {
Column() {
Button('保存网络图片到应用沙盒')
.width('100%')
.height(40)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.onClick(async () => {
console.debug(`image => 保存网络图片到应用沙盒`)
let dirPath = this.context.cacheDir
let fileName = 'temp2.jpg'
if (fileIo.accessSync(`${dirPath}/${fileName}`)) {
fileIo.rmdirSync(`${dirPath}/${fileName}`)
}
try {
let result: SaveImageResultVo = await SaveImageUtil.saveImageToApplication(
// 'https://wx3.sinaimg.cn/mw690/006N8b3Kgy1hqe7d2hfboj31jk267h17.jpg'
`http://gips0.baidu.com/it/u=3602773692,1512483864&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280`
, dirPath, fileName
)
if (0 == result.errorCode) {
// 图片保存成功
console.debug(`image => 保存图片到应用沙盒成功`)
SaveImageUtil
.saveImageToAlbum(`${dirPath}/${fileName}`)
.then(result => {
if (result) {
console.debug(`image => 保存图片到相册成功`)
} else {
console.debug(`image => 用户拒绝授权`)
}
})
.catch(error => {
console.error('image => 保存图片到相册异常:')
})
}
} catch (err) {
console.error(err, `image => 保存图片到应用沙盒异常:`)
}
})
Button('保存BASE64图片到应用沙盒')
.width('100%')
.height(40)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.margin({ top: 15 })
.onClick(() => {
console.debug(`image => 保存网络图片到应用沙盒`)
let dirPath = this.context.cacheDir
let fileName = 'temp2.jpg'
if (fileIo.accessSync(`${dirPath}/${fileName}`)) {
fileIo.rmdirSync(`${dirPath}/${fileName}`)
}
SaveImageUtil
.saveImageToApplication(BASE64_IMAGE_STR, dirPath, fileName)
.then(data => {
if (0 == data.errorCode) {
console.debug(`image => 保存图片到应用沙盒成功`)
} else {
console.debug(`image => 保存图片到应用沙盒失败:${data.errorCode}`)
}
})
.catch(error => {
console.error(`image => 保存图片到应用沙盒异常:`)
})
})
}
.padding(15)
.height('100%')
.width('100%')
}
}
更多关于HarmonyOS鸿蒙Next中在不申请写入权限(ohos.permission.WRITE_IMAGEVIDEO)的情况下,把图片保存至相册的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,若不申请ohos.permission.WRITE_IMAGEVIDEO
权限,无法直接将图片保存至系统相册。系统相册的写入操作需要该权限以确保数据安全和隐私保护。若未申请权限,尝试保存图片将导致权限拒绝异常。开发者需在应用中明确请求该权限,并在用户授权后方可进行写入操作。
在HarmonyOS鸿蒙Next中,若未申请ohos.permission.WRITE_IMAGEVIDEO
权限,无法直接将图片保存至相册。系统出于安全考虑,限制了对相册的写入操作。建议在应用中使用ohos.permission.WRITE_IMAGEVIDEO
权限声明,并在运行时动态申请权限,以确保合规性和用户隐私。若用户拒绝权限,可引导用户手动保存图片至其他目录。