最受欢迎的三方库之 picker_utils
作者:桃花镇童长老
- 2025-06-27 安徽
本文字数:9145 字
阅读完需:约 30 分钟
picker_utils (API12+)
🏆简介与推荐
picker_utils 是harmony-utils 拆分出来的一个子库,包含 PickerUtil、PhotoHelper、ScanUtil。
主要解决:当使用 harmony-utils 三方库且未使用 picker 能力时,隐私政策中无需声明相机权限与储存权限。
🌞下载安装
ohpm i @pura/picker_utils
OpenHarmony ohpm 环境配置等更多内容,请参考如何安装 OpenHarmony ohpm 包<br>
📚API 详解 使用案例
📂模块介绍
PickerUtil(拍照、文件选择和保存,工具类)使用案例
PhotoHelper(相册相关,工具类)使用案例
ScanUtil(码工具类(扫码、码图生成、图片识码))使用案例
import { router } from '@kit.ArkUI';
import { DateUtil, FileUtil, ImageUtil, LogUtil, PreferencesUtil, StrUtil, ToastUtil } from '@pura/harmony-utils';
import { DescribeBean } from '../../model/DescribeBean';
import { BusinessError } from '@kit.BasicServicesKit';
import { image } from '@kit.ImageKit';
import { MockSetup } from '@ohos/hamock';
import { TitleBarView } from '../../component/TitleBarView';
import { camera, cameraPicker } from '@kit.CameraKit';
import { picker } from '@kit.CoreFileKit';
import { CameraOptions, PickerUtil } from '@pura/picker_utils';
/**
* 拍照、文件(文件、图片、视频、音频)选择和保存,工具类
*/
@Entry
@Component
struct Index {
private scroller: Scroller = new Scroller();
@State describe: DescribeBean = router.getParams() as DescribeBean;
@State uriStr: string = ''
@State filePath: string = ''; //本地图片path
@State cacheUri: string = ''; //缓存本地Uri,上次保存的Uri。
@MockSetup
mock() {
this.describe = new DescribeBean("PickerUtil", "拍照、文件(文件、图片、视频、音频)选择和保存,工具类");
}
async aboutToAppear(): Promise<void> {
this.cacheUri = PreferencesUtil.getStringSync("picker_cache_uri");
let pixelMap = await ImageUtil.getPixelMapFromMedia($r("app.media.test_as4"))
this.filePath = await ImageUtil.savePixelMap(pixelMap, FileUtil.getFilesDirPath(""), "漂亮小姐姐.png")
LogUtil.error("filePath: " + this.filePath);
}
build() {
Column() {
TitleBarView({ describe: this.describe })
Divider()
Scroll(this.scroller) {
Column() {
Button("cameraEasy()")
.btnStyle()
.onClick(async () => {
PickerUtil.cameraEasy().then((uri) => {
this.uriStr = `调用相机,返回uri:\n${uri}`;
}).catch((err: BusinessError) => {
this.uriStr = `调用相机,异常:\n${JSON.stringify(err)}`;
});
})
Button("camera()")
.btnStyle()
.onClick(async () => {
let options: CameraOptions = {
mediaTypes: [cameraPicker.PickerMediaType.PHOTO],
cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
}
PickerUtil.camera(options).then((result) => {
this.uriStr = `调用相机,返回uri:\n${result.resultUri}`;
}).catch((err: BusinessError) => {
this.uriStr = `调用相机,异常:\n${JSON.stringify(err)}`;
});
})
Button("selectPhoto()")
.btnStyle()
.onClick(() => {
PickerUtil.selectPhoto().then((uris) => {
this.uriStr = `调用相册,返回uris:\n${uris.join('\n')}`;
}).catch((err: BusinessError) => {
this.uriStr = `调用相册,异常:\n${JSON.stringify(err)}`;
});
})
Button("savePhoto()")
.btnStyle()
.onClick(() => {
let imgName = `大漂亮_${DateUtil.getTodayTime()}.png`;
let imgName1 = `小漂亮_${DateUtil.getTodayTime()}.png`;
PickerUtil.savePhoto([imgName, imgName1]).then(async (uris) => {
let uri = uris[0];
this.uriStr = `调用保存图片,返回uris:\n${uri}`
let file = FileUtil.openSync(uri);
FileUtil.copyFile(this.filePath, file.fd).then(() => {
this.uriStr = `保存图片,返回uris:\n${uri}`
ToastUtil.showToast("图片1保存成功");
})
let file1 = FileUtil.openSync(uris[1]);
let pixelMap1 = await ImageUtil.getPixelMapFromMedia($r("app.media.test_as3"))
let packOpts: image.PackingOption = { format: 'image/png', quality: 100 }
ImageUtil.packToFileFromPixelMap(pixelMap1, file1.fd, packOpts).then(() => {
this.uriStr = `保存图片,返回uris:\n${uris[1]}`
ToastUtil.showToast("图片2保存成功");
})
}).catch((err: BusinessError) => {
this.uriStr = `调用保存图片,异常:\n${JSON.stringify(err)}`
})
})
Button("selectDocument()")
.btnStyle()
.onClick(() => {
let options: picker.DocumentSelectOptions = {
maxSelectNumber: 9, //选择媒体文件数量的最大值,默认9。
selectMode: picker.DocumentSelectMode.FILE, //支持选择的资源类型,默认文件
// fileSuffixFilters: ['图片(.png, .jpg)|.png,.jpg', '文档|.txt', '视频|.mp4', '.pdf'], //选择文件的后缀类型['后缀类型描述|后缀类型'](可选) 若选择项存在多个后缀名,则每一个后缀名之间用英文逗号进行分隔(可选),后缀类型名不能超过100,选择所有文件:'所有文件(*.*)|.*';
// defaultFilePathUri: "file://docs/storage/Users/currentUser/Download/com.harmony.utils", //指定选择的文件或者目录路径(可选)
// authMode: true //选择是否对指定文件或目录授权,true为授权,当为true时,defaultFilePathUri为必选参数。
}
PickerUtil.selectDocument(options).then((uris) => {
this.uriStr = `调用文件管理,返回uris:\n${uris.join('\n')}`
}).catch((err: BusinessError) => {
this.uriStr = `调用文件管理,异常:\n${JSON.stringify(err)}`
});
})
Button("saveDocumentEasy()")
.btnStyle()
.onClick(() => {
let fileName = `test_easy_${DateUtil.getTodayTime()}.txt`;
PickerUtil.saveDocumentEasy([fileName]).then((paths) => {
let path = paths[0];
this.cacheUri = FileUtil.getUriFromPath(path);
PreferencesUtil.put("picker_cache_uri", this.cacheUri);
let txtStr = `“harmony-utils 一款高效的OpenHarmony/HarmonyOS工具包,封装了常用工具类,提供一系列简单易用的方法。帮助开发者快速构建鸿蒙应用。\n\n`;
FileUtil.writeEasy(path, txtStr).then(() => {
this.uriStr = `文件保存成功,返回uris:\n${path}`;
ToastUtil.showToast("文件保存成功!");
}).catch((err: BusinessError) => {
this.uriStr = `文件保存,异常:\n${JSON.stringify(err)}`;
})
}).catch((err: BusinessError) => {
this.uriStr = `调用保存文件,异常:\n${JSON.stringify(err)}`;
})
})
Button("saveDocument()")
.btnStyle()
.onClick(() => {
let fileName = `test_${DateUtil.getTodayTime()}.txt`;
PickerUtil.saveDocument({newFileNames:[fileName]}).then((uris) => {
let uri = uris[0];
this.cacheUri = uri
PreferencesUtil.put("picker_cache_uri", this.cacheUri);
let txtStr = `“harmony-utils 一款高效的OpenHarmony/HarmonyOS工具包,封装了常用工具类,提供一系列简单易用的方法。帮助开发者快速构建鸿蒙应用。\n\n`;
FileUtil.writeEasy(uri, txtStr).then(() => {
this.uriStr = `文件保存成功,返回uris:\n${uri}`;
ToastUtil.showToast("文件保存成功!");
}).catch((err: BusinessError) => {
this.uriStr = `文件保存,异常:\n${JSON.stringify(err)}`;
})
}).catch((err: BusinessError) => {
this.uriStr = `调用保存文件,异常:\n${JSON.stringify(err)}`;
})
})
Button("selectAudio()")
.btnStyle()
.onClick(() => {
PickerUtil.selectAudio().then((uris) => {
this.uriStr = `调用文件管理,返回uris:\n${uris.join('\n')}`;
}).catch((err: BusinessError) => {
this.uriStr = `调用文件管理,异常:\n${JSON.stringify(err)}`;
});
})
Button("saveAudio()")
.btnStyle()
.onClick(() => {
let fileName = `AudioViewPicker001.mp3`;
PickerUtil.saveAudio([fileName]).then((uris) => {
let uri = uris[0];
this.uriStr = `音频文件,返回uris:\n${uri}`;
}).catch((err: BusinessError) => {
this.uriStr = `调用保存文件,异常:\n${JSON.stringify(err)}`;
})
})
Text(this.uriStr)
.visibility(StrUtil.isNotEmpty(this.uriStr) ? Visibility.Visible : Visibility.None)
.textStyle()
.margin(12)
Blank().layoutWeight(1)
}
.margin({ top: 5, bottom: 5 })
}
.layoutWeight(1)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
.backgroundColor($r('app.color.main_background'))
}
}
@Styles
function btnStyle() {
.width('90%')
.margin({ top: 10, bottom: 5 })
}
@Styles
function textStyle() {
.width('95%')
.padding(10)
.shadow(ShadowStyle.OUTER_DEFAULT_XS)
.margin({ top: 5, bottom: 10 })
.border({ width: 1, color: Color.Grey, radius: 10, style: BorderStyle.Dashed })
}
复制代码
import { router } from '@kit.ArkUI';
import {
DateUtil,
FileUtil,
ImageUtil,
LogUtil,
PermissionUtil,
StrUtil,
ToastUtil,
WantUtil
} from '@pura/harmony-utils';
import { DescribeBean } from '../../model/DescribeBean';
import { BusinessError } from '@kit.BasicServicesKit';
import { Permissions } from '@kit.AbilityKit';
import { image } from '@kit.ImageKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { MockSetup } from '@ohos/hamock';
import { TitleBarView } from '../../component/TitleBarView';
import { DialogHelper } from '@pura/harmony-dialog';
import { PhotoHelper, PickerUtil } from '@pura/picker_utils';
/**
* 相册选择和保存,工具类
*/
@Entry
@Component
struct Index {
private scroller: Scroller = new Scroller();
@State describe: DescribeBean = router.getParams() as DescribeBean;
@State uriStr: string = ''
@State pixelMap?: image.PixelMap = undefined
@State filePath: string = ''; //本地图片path
@State filePath2: string = ''; //本地图片path
private saveButtonOptions: SaveButtonOptions = { icon: SaveIconStyle.FULL_FILLED, text: SaveDescription.SAVE_IMAGE, buttonType: ButtonType.Capsule } //设置安全控件按钮属性
@MockSetup
mock() {
this.describe = new DescribeBean("PhotoHelper", "相册选择和保存,工具类");
}
async aboutToAppear(): Promise<void> {
let pixelMap = await ImageUtil.getPixelMapFromMedia($r("app.media.test_as4"));
this.filePath = await ImageUtil.savePixelMap(pixelMap, FileUtil.getFilesDirPath(""), "漂亮小姐姐.png");
LogUtil.error("filePath: " + this.filePath);
let pixelMap2 = await ImageUtil.getPixelMapFromMedia($r("app.media.test_as2"));
this.filePath2 = await ImageUtil.savePixelMap(pixelMap2, FileUtil.getFilesDirPath(""), "为梦想窒息.png");
}
onBackPress(): boolean {
return false;
}
build() {
Column() {
TitleBarView({ describe: this.describe })
Divider()
Scroll(this.scroller) {
Column() {
Button("select()-默认使用")
.btnStyle()
.onClick(() => this.selectDefault())
Button("select()-多选")
.btnStyle()
.onClick(() => this.selectMore())
Button("selectEasy()-单选")
.btnStyle()
.onClick(() => this.selectSingle())
Button("save()")
.btnStyle()
.onClick(() => this.save())
Button("showAssetsCreationDialogEasy()")
.btnStyle()
.onClick(() => this.showAssetsCreationDialog())
SaveButton(this.saveButtonOptions)
.onClick(() => this.saveButton())
Button("getPhotoAsset()")
.btnStyle()
.onClick(() => this.getPhotoAsset())
Text(this.uriStr)
.visibility(StrUtil.isNotEmpty(this.uriStr) ? Visibility.Visible : Visibility.None)
.textStyle()
Image(this.pixelMap)
.objectFit(ImageFit.Fill)
.autoResize(true)
.textStyle()
Blank().layoutWeight(1)
}
.margin({ top: 5, bottom: 5 })
.width('100%')
}
.width('100%')
.layoutWeight(1)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
.backgroundColor($r('app.color.main_background'))
}
//相册选择图片
selectDefault(){
PhotoHelper.select().then((result) => {
let uris = result.photoUris;
this.uriStr = `调用相册,返回uris:\n${uris.join('\n')}`;
}).catch((err: BusinessError) => {
this.uriStr = `调用相册,异常:\n${JSON.stringify(err)}`;
});
}
//相册选择图片/视频(多选)
selectMore(){
let options: photoAccessHelper.PhotoSelectOptions = {
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE,
maxSelectNumber: 12,
isPhotoTakingSupported: false,
isSearchSupported: false,
isEditSupported: false,
isOriginalSupported: true
}
PhotoHelper.selectEasy(options).then((uris) => {
this.uriStr = `调用相册,返回uris:\n${uris.join('\n')}`;
}).catch((err: BusinessError) => {
this.uriStr = `调用相册,异常:\n${JSON.stringify(err)}`;
});
}
//相册选择图片(单选)
selectSingle(){
let options: photoAccessHelper.PhotoSelectOptions = {
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
maxSelectNumber: 1,
isOriginalSupported: true,
isPreviewForSingleSelectionSupported: true //单选模式下是否需要进大图预览
}
PhotoHelper.selectEasy(options).then((uris) => {
this.uriStr = `调用相册,返回uris:\n${uris.join('\n')}`;
}).catch((err: BusinessError) => {
this.uriStr = `调用相册,异常:\n${JSON.stringify(err)}`;
});
}
//图片保存进相册(已申请权限使用该方法)
save(){
let ps: Permissions[] = ['ohos.permission.WRITE_IMAGEVIDEO'];
PermissionUtil.requestPermissions(ps).then((result) => {
if (result) {
let imgName = `漂亮小姐姐_${DateUtil.getTodayTime()}`;
PhotoHelper.save(photoAccessHelper.PhotoType.IMAGE, 'jpg', { title: imgName }).then(async (uri) => {
if (uri) {
this.uriStr = `保存图片成功,返回uris:\n${uri}`;
let file = FileUtil.openSync(uri);
FileUtil.copyFile(this.filePath, file.fd).then(() => {
FileUtil.close(file.fd);
ToastUtil.showToast("图片保存成功");
})
}
}).catch((err: BusinessError) => {
this.uriStr = `调用保存图片,异常:\n${JSON.stringify(err)}`;
})
} else {
ToastUtil.showLong("请在设置中打开权限");
WantUtil.toAppSetting();
}
})
}
//弹窗授权保存,图片保存进相册。
showAssetsCreationDialog(){
let uri = FileUtil.getUriFromPath(this.filePath);
let uri2 = FileUtil.getUriFromPath(this.filePath2);
PhotoHelper.showAssetsCreationDialogEasy([uri, uri2]).then((result) => {
this.uriStr = `图片保存成功,返回uris:\n${JSON.stringify(result, null, 2)}`;
DialogHelper.showToast("图片保存成功!");
}).catch((error: BusinessError) => {
this.uriStr = `保存图片失败 ~ code: ${error.code} -·- message: ${error.message}`;
DialogHelper.showToast("图片保存失败!");
});
}
//安全控件保存,图片保存进相册。
saveButton() {
let uri = FileUtil.getUriFromPath(this.filePath);
PhotoHelper.applyChanges(uri).then((result) => {
this.uriStr = `保存图片成功:${result.uri}`;
}).catch((err: BusinessError) => {
this.uriStr = `保存图片失败:${JSON.stringify(err)}`;
});
}
//读取图片/视频的信息
getPhotoAsset(){
PickerUtil.selectPhoto().then(async (uris) => {
if (uris && uris.length > 0) {
PhotoHelper.getPhotoAsset(uris[0]).then((photoAsset) => {
try {
let name = photoAsset?.get(photoAccessHelper.PhotoKeys.DISPLAY_NAME);
let type = photoAsset?.get(photoAccessHelper.PhotoKeys.PHOTO_TYPE);
let title = photoAsset?.get(photoAccessHelper.PhotoKeys.TITLE.toString());
let size = photoAsset?.get(photoAccessHelper.PhotoKeys.SIZE.toString());
let with1 = photoAsset?.get(photoAccessHelper.PhotoKeys.WIDTH.toString());
let height = photoAsset?.get(photoAccessHelper.PhotoKeys.HEIGHT.toString());
let date = photoAsset?.get(photoAccessHelper.PhotoKeys.DATE_TAKEN.toString());
let orientation = photoAsset?.get(photoAccessHelper.PhotoKeys.ORIENTATION.toString());
this.uriStr = `图片信息:\n文件名:${name}\n文件类型:${type}\n文件大小:${size}\n图片宽度:${with1}\n图片高度:${height}\n拍摄日期:${date}\n文件标题:${title}\n图片文件的方向:${orientation}`
} catch (err) {
LogUtil.error("读取图片信息失败:" + JSON.stringify(err));
}
photoAsset?.getThumbnail((err, pixelMap) => {
if (err) {
LogUtil.error("缩略图-异常:" + JSON.stringify(err));
return;
}
this.pixelMap = pixelMap;
})
}).catch((err: BusinessError) => {
this.uriStr = `读取图片异常:\n${JSON.stringify(err)}`;
});
} else {
ToastUtil.showToast("请选择图片");
}
}).catch((err: BusinessError) => {
this.uriStr = `异常:\n${JSON.stringify(err)}`;
});
}
}
@Styles
function btnStyle() {
.width('90%')
.margin({ top: 10, bottom: 5 })
}
@Styles
function textStyle() {
.width('95%')
.padding(10)
.shadow(ShadowStyle.OUTER_DEFAULT_XS)
.margin({ top: 5, bottom: 10 })
.border({ width: 1, color: Color.Grey, radius: 10, style: BorderStyle.Dashed })
}
复制代码
🍎沟通与交流🙏
使用过程中发现任何问题都可以提 Issue 给我们;
当然,我们也非常欢迎你给我们发 PR 。
🌏开源协议
本项目基于 Apache License 2.0 ,在拷贝和借鉴代码时,请大家务必注明出处。
划线
评论
复制
发布于: 2025-06-27阅读数: 400

桃花镇童长老
关注
还未添加个人签名 2025-05-14 加入
还未添加个人简介
评论