
HarmonyOS应用开发 - 无受限权限保存资源到媒体库 原创
概述
文档环境
DevEco Studio 版本:DevEco Studio 6.0.0 Release(6.0.0.858)
SDK 版本:6.0.0 (API20)
设备型号:ALT-AL10
系统版本:6.0.0.100
功能简介
- Media Library Kit(媒体文件管理服务)提供了管理相册和媒体文件的能力,包括图片和视频,帮助应用快速构建图片和视频的展示与播放功能。通过Media Library Kit,开发者可以管理相册和媒体文件,包括创建相册、访问和修改相册中的媒体信息。
- 本文将基于媒体文件管理服务向大家介绍无需申请受限权限将图片和视频保存进媒体库的两种方法。
无受限权限保存资源到媒体库
获取支持保存的资源格式
接口:PhotoAccessHelper.getSupportedPhotoFormats
描述:获取媒体库支持的图片或者视频后缀列表。
权限:无。
代码示例:
import { common } from '@kit.AbilityKit'
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import { BusinessError } from '@kit.BasicServicesKit'
@Entry
@ComponentV2
struct Index {
@Local message: string = ''
context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext
phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context)
build() {
Row() {
Column({ space: 20 }) {
Text(this.message)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Button('获取媒体库支持的类型')
.fontSize(20)
.onClick(() => {
this.phAccessHelper.getSupportedPhotoFormats(photoAccessHelper.PhotoType.IMAGE)
.then((imageFormat: Array<string>) => {
this.message += `图片类型: ${JSON.stringify(imageFormat)} \n`
})
.catch((error: BusinessError) => {
console.error(`Failed to getSupportedPhotoFormats. Error code is ${error.code}, message is ${error.message}`)
})
this.phAccessHelper.getSupportedPhotoFormats(photoAccessHelper.PhotoType.VIDEO)
.then((imageFormat: Array<string>) => {
this.message += `视频类型: ${JSON.stringify(imageFormat)} \n`
})
.catch((error: BusinessError) => {
console.error(`Failed to getSupportedPhotoFormats. Error code is ${error.code}, message is ${error.message}`)
})
})
}
.width('100%')
}.height('100%')
}
}
示例截图:
使用安全控件保存媒体库资源
应用集成保存控件后,用户首次(首次安装,首次触发保存)使用保存控件展示弹窗,在点击允许后自动授权,应用会获取一分钟内访问媒体库特权接口的授权。后续使用无需弹窗授权。
组件:SaveButton
描述:安全控件的保存控件。
权限:使用默认样式无需权限,也不需要申请媒体库操作权限。如果需要自定义图标、文本、图标尺寸、图标圆角,以及按压态效果等属性时需要申请受限开放权限ohos.permission.CUSTOMIZE_SAVE_BUTTON。
使用时需注意:
// 默认参数下,图标、文字、背景都存在。
SaveButton()
// 传入参数即表示元素存在,不传入的参数表示元素不存在,如果不传入buttonType,会默认添加ButtonType.Capsule配置,显示图标+背景。
SaveButton({ icon: SaveIconStyle.FULL_FILLED })
// 只显示图标+背景,如果设置背景色高八位的α值低于0x1a,则会被系统强制调整为0xff。
SaveButton({ icon: SaveIconStyle.FULL_FILLED, buttonType: ButtonType.Capsule })
.backgroundColor(0x10007dff)
// 图标、文字、背景都存在,如果设置背景色高八位的α值低于0x1a,则会被系统强制调整为0xff。
SaveButton({ icon: SaveIconStyle.FULL_FILLED, text: SaveDescription.DOWNLOAD, buttonType: ButtonType.Capsule })
.backgroundColor(0x00000000)
// 图标、文字、背景都存在,如果设置宽度小于当前属性组合下允许的最小宽度时,宽度仍为设置值,此时按钮文本信息会自动换行,以保证安全控件显示的完整性。
SaveButton({ icon: SaveIconStyle.FULL_FILLED, text: SaveDescription.DOWNLOAD, buttonType: ButtonType.Capsule })
.fontSize(16)
.width(30)
// 图标、文字、背景都存在,如果设置宽度小于当前属性组合下允许的最小宽度时,宽度仍为设置值,此时按钮文本信息会自动换行,以保证安全控件显示的完整性。
SaveButton({ icon: SaveIconStyle.LINES, text: SaveDescription.QUICK_SAVE_TO_GALLERY, buttonType: ButtonType.Circle })
.fontSize(16)
.size({ width: 30, height: 30 })
// 图标、文字、背景都存在,如果设置宽度小于当前属性组合下允许的最小宽度时,宽度仍为设置值,此时按钮文本信息会自动换行,以保证安全控件显示的完整性。
SaveButton({ icon: SaveIconStyle.LINES, text: SaveDescription.DOWNLOAD_FILE, buttonType: ButtonType.Normal })
.fontSize(16)
.constraintSize({
minWidth: 0,
maxWidth: 30,
minHeight: 0,
maxHeight: 30
})
参考截图:
代码示例(需在resources/resfile/myDog.jpg准备好图片):
方式一:
接口:MediaAssetChangeRequest.createImageAssetRequest
描述:创建图片资产变更请求。
权限:在安全控件授权下,无需申请受限权限。
接口:MediaAssetChangeRequest.createVideoAssetRequest
描述:创建视频资产变更请求。
权限:在安全控件授权下,无需申请受限权限。
接口:PhotoAccessHelper.applyChanges
描述:提交媒体变更请求。
权限:在安全控件授权下,无需申请受限权限。
import { common } from '@kit.AbilityKit'
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import { BusinessError } from '@kit.BasicServicesKit'
@Entry
@ComponentV2
struct Index {
@Local message: string = ''
context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext
phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context)
myDogPicPath: string = this.context.resourceDir + "/myDog.jpg"
build() {
Row() {
Column({ space: 20 }) {
Text(this.message)
.fontSize(20)
.fontWeight(FontWeight.Bold)
SaveButton()
.onClick(() => {
// 如果用户拒绝授权,则不会执行。
let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest =
photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(this.context, this.myDogPicPath);
this.phAccessHelper.applyChanges(assetChangeRequest)
.then(() => {
this.message = assetChangeRequest.getAsset().uri
})
.catch((error: BusinessError) => {
console.error(`Failed to applyChanges. Error code is ${error.code}, message is ${error.message}`)
})
})
}.width('100%')
}.height('100%')
}
}
方式二:
接口:PhotoAccessHelper.createAsset
描述:指定文件类型、后缀和创建选项,创建图片或视频资源。
权限:在安全控件授权下,无需申请受限权限。
import { common } from '@kit.AbilityKit'
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import { BusinessError } from '@kit.BasicServicesKit'
import { fileIo } from '@kit.CoreFileKit'
@Entry
@ComponentV2
struct Index {
@Local message: string = ''
context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext
phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context)
myDogPicPath: string = this.context.resourceDir + "/myDog.jpg"
build() {
Row() {
Column({ space: 20 }) {
Text(this.message)
.fontSize(20)
.fontWeight(FontWeight.Bold)
SaveButton()
.onClick(() => {
// 如果用户拒绝授权,则不会执行。
this.phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg')
.then((uri: string) => {
fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE)
.then((file: fileIo.File) => {
fileIo.copyFile(this.myDogPicPath, file.fd)
.then(() => {
this.message = uri
})
.catch((error: BusinessError) => {
console.error(`Failed to copyFile. Error code is ${error.code}, message is ${error.message}`)
})
.finally(() => {
fileIo.close(file)
.catch((error: BusinessError) => {
console.error(`Failed to closeFile. Error code is ${error.code}, message is ${error.message}`)
})
})
})
.catch((error: BusinessError) => {
console.error(`Failed to openFile. Error code is ${error.code}, message is ${error.message}`)
})
})
.catch((error: BusinessError) => {
console.error(`Failed to createAsset. Error code is ${error.code}, message is ${error.message}`)
})
})
}.width('100%')
}.height('100%')
}
}
示例截图:
使用弹窗授权保存媒体库资源
调用接口拉起保存确认弹窗。用户同意保存后,返回已创建并授予保存权限的uri列表,该列表永久生效(应用退出后,再次冷启动拥有权限),应用可使用该uri写入图片/视频。如果用户拒绝保存,将返回空列表。弹框需要显示应用名称,无法直接获取应用名称,依赖于配置项的label和icon,因此调用此接口时请确保module.json5文件中的abilities标签中配置了label和icon项。
接口:PhotoAccessHelper.showAssetsCreationDialog
描述:调用接口拉起保存确认弹窗。
权限:无需申请受限权限。
代码示例(需在应用沙箱/data/storage/el2/base/haps/entry/files/myDog.jpg准备好图片):
import { common } from '@kit.AbilityKit'
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import { BusinessError } from '@kit.BasicServicesKit'
import { fileIo } from '@kit.CoreFileKit'
@Entry
@ComponentV2
struct Index {
@Local message: string = ''
context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext
phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context)
myDogPicPath: string = this.context.filesDir + "/myDog.jpg"
build() {
Row() {
Column({ space: 20 }) {
Text(this.message)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Button(`保存图片`)
.onClick(() => {
console.log(this.myDogPicPath);
// 指定待保存到媒体库的位于应用沙箱的图片uri。
let srcFileUris: Array<string> = [
this.myDogPicPath
]
// 指定待保存照片的创建选项,包括文件后缀和照片类型,标题和照片子类型可选。
let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [
{
fileNameExtension: 'jpg',
photoType: photoAccessHelper.PhotoType.IMAGE
}
]
// 基于弹窗授权的方式获取媒体库的目标uri。
this.phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs)
.then((uris: Array<string>) => {
this.message = JSON.stringify(uris)
if (uris.length == 0) {
return
}
const uri = uris[0]
fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE)
.then((file: fileIo.File) => {
fileIo.copyFile(this.myDogPicPath, file.fd)
.then(() => {
this.message = uri
})
.catch((error: BusinessError) => {
console.error(`Failed to copyFile. Error code is ${error.code}, message is ${error.message}`)
})
.finally(() => {
fileIo.close(file)
.catch((error: BusinessError) => {
console.error(`Failed to closeFile. Error code is ${error.code}, message is ${error.message}`)
})
})
})
.catch((error: BusinessError) => {
console.error(`Failed to openFile. Error code is ${error.code}, message is ${error.message}`)
})
})
.catch((error: BusinessError) => {
console.error(`Failed to showAssetsCreationDialog. Error code is ${error.code}, message is ${error.message}`)
})
})
}.width('100%')
}.height('100%')
}
}
示例截图:
