一、Picker
Picker是系统提供的文件选择器,可以拉起系统图库界面,让用户自行选择待分享的资源。
| 特点 | 说明 |
|---|---|
| 无需权限 | 不需要申请存储权限 |
| 适用范围 | 界面UIAbility,使用窗口组件触发 |
| 支持类型 | 图片、视频(音频需使用AudioViewPicker) |
适用场景
-
用户分享图片、视频
-
选择头像上传
-
选择图片进行编辑
-
选择视频进行播放
二、导入模块
import { fileIo } from '@kit.CoreFileKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
三、创建选择选项
3.1 PhotoSelectOptions参数
| 参数 | 类型 | 说明 |
|---|---|---|
maxSelectNumber |
number | 最大可选择文件数量 |
MIMEType |
PhotoViewMIMETypes | 媒体文件类型 |
isPhotoTakingSupported |
boolean | 是否支持拍照 |
3.2 配置示例
// 创建图片-音频类型文件选择选项实例
const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
// 配置可选的媒体文件类型和最大数目
photoSelectOptions.maxSelectNumber = 5; // 最多选择5个文件
photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE; // 图片+视频
photoSelectOptions.isPhotoTakingSupported = true; // 支持拍照
3.3 PhotoViewMIMETypes枚举
| 枚举值 | 说明 |
|---|---|
IMAGE_TYPE |
仅图片 |
VIDEO_TYPE |
仅视频 |
IMAGE_VIDEO_TYPE |
图片和视频 |
四、拉起图库选择器
4.1 调用select接口
// 创建图库选择器实例
const photoViewPicker = new photoAccessHelper.PhotoViewPicker();
// 拉起图库界面进行文件选择
const result = await photoViewPicker.select(photoSelectOptions);
// 文件选择成功后,返回PhotoSelectResult结果集
console.info('选择成功,返回结果: ' + JSON.stringify(result));
console.info('选择的文件数量: ' + result.photoUris.length);
// 更新选中的URI列表
this.selectedUris = result.photoUris;
// 设置默认选中第一个URI用于读取操作
if (this.selectedUris.length > 0) {
this.selectedUriForRead = this.selectedUris[0];
}
4.2 PhotoSelectResult结果集
| 属性 | 类型 | 说明 |
|---|---|---|
photoUris |
Array<string> | 选中的文件URI列表 |
五、指定URI读取文件数据
注意:不能在picker的回调里直接使用此uri进行打开文件操作。需要定义一个全局变量保存uri,使用一个按钮去触发打开文件。
打开文件获取fd
try {
const file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY);
console.info('file fd: ' + file.fd);
return { fd: file.fd, file: file };
} catch (error) {
console.error('openSync failed with err: ' + error);
return null;
}
读取文件数据
try {
const buffer = new ArrayBuffer(bufferSize);
const readLen = fileIo.readSync(fileObj.fd, buffer);
console.info('readSync data to file succeed and buffer size is:' + readLen);
return { data: buffer, length: readLen };
} catch (error) {
console.error('readSync failed with err: ' + error);
return null;
}
5.4 完整示例
// 保存URI
@State selectedUris: Array<string> = [];
@State selectedUriForRead: string = '';
// 选择文件后
async selectFiles() {
const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
photoSelectOptions.maxSelectNumber = 5;
photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
const photoViewPicker = new photoAccessHelper.PhotoViewPicker();
const result = await photoViewPicker.select(photoSelectOptions);
this.selectedUris = result.photoUris;
if (this.selectedUris.length > 0) {
this.selectedUriForRead = this.selectedUris[0];
}
}
// 按钮触发读取文件
async readSelectedFile() {
if (!this.selectedUriForRead) {
console.error('No file selected');
return;
}
// 1. 打开文件
const file = fileIo.openSync(this.selectedUriForRead, fileIo.OpenMode.READ_ONLY);
// 2. 获取文件大小
const stat = fileIo.statSync(this.selectedUriForRead);
const bufferSize = stat.size;
// 3. 读取文件内容
const buffer = new ArrayBuffer(bufferSize);
const readLen = fileIo.readSync(file.fd, buffer);
console.info(`读取成功,大小: ${readLen} 字节`);
// 4. 关闭文件
fileIo.closeSync(file.fd);
}
六、指定URI获取图片或视频资源
6.1 创建MediaAssetDataHandler
export class MediaAssetDataHandler implements photoAccessHelper.MediaAssetDataHandler<ArrayBuffer> {
private callback?: (data: ArrayBuffer) => void;
constructor(callback?: (data: ArrayBuffer) => void) {
this.callback = callback;
}
// 使用箭头函数确保this引用不会丢失
onDataPrepared = (data: ArrayBuffer) => {
if (data === undefined) {
console.error('Error occurred when preparing data');
return;
}
console.info('on image data prepared');
if (this.callback) {
this.callback(data);
}
};
}
6.2 获取媒体资源
static async getMediaResourceByUri(uri: string, context: common.Context,
callback?: (data: ArrayBuffer) => void): Promise<void> {
try {
// 1. 创建PhotoAccessHelper实例
const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
// 2. 创建查询条件
const predicates: dataSharePredicates.DataSharePredicates =
new dataSharePredicates.DataSharePredicates();
predicates.equalTo(photoAccessHelper.PhotoKeys.URI, uri);
// 3. 设置查询选项
const fetchOptions: photoAccessHelper.FetchOptions = {
fetchColumns: [photoAccessHelper.PhotoKeys.TITLE],
predicates: predicates
};
// 4. 查询资产
const fetchResult = await phAccessHelper.getAssets(fetchOptions);
const photoAsset = await fetchResult.getFirstObject();
if (photoAsset) {
console.info('getAssets photoAsset.uri : ' + photoAsset.uri);
console.info('title : ' + photoAsset.get(photoAccessHelper.PhotoKeys.TITLE));
// 5. 设置请求选项
const requestOptions: photoAccessHelper.RequestOptions = {
deliveryMode: photoAccessHelper.DeliveryMode.HIGH_QUALITY_MODE,
};
// 6. 请求图片数据
await photoAccessHelper.MediaAssetManager.requestImageData(
context, photoAsset, requestOptions, new MediaAssetDataHandler(callback)
);
console.info('requestImageData successfully');
} else {
console.error('No asset found for URI: ' + uri);
}
// 7. 关闭查询结果
fetchResult.close();
} catch (err) {
console.error('getMediaResourceByUri failed with err: ' + err);
}
}
七、注意事项
7.1 权限说明
| 项目 | 说明 |
|---|---|
| Picker本身 | 无需申请任何权限 |
| 地理位置信息 | 如果需要获取EXIF中的地理位置信息,需申请ohos.permission.MEDIA_LOCATION权限 |
7.2 文件读取限制
-
select返回的uri权限是只读权限 -
不能在picker的回调里直接使用uri进行打开文件操作
-
需要定义全局变量保存uri,通过按钮等组件触发读取
7.3 隐私保护
出于对用户隐私安全的保护,对媒体资源EXIF中的地理位置和拍摄参数信息 做了去隐私化处理。如果需要获取被去隐私化的EXIF信息,需要申请ohos.permission.MEDIA_LOCATION权限。
7.4 音频文件
当需要读取和保存音频文件 时,请使用AudioViewPicker(音频选择器对象)。
鸿蒙PhotoViewPicker通过拉起系统图库让用户选择图片/视频资源,无需申请存储权限,选择后返回文件URI,再通过fileIo接口读取文件数据,适用于头像选择、图片分享等场景。