鸿蒙中 PhotoViewPicker:选择图片或视频

一、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接口读取文件数据,适用于头像选择、图片分享等场景。

相关推荐
独特的螺狮粉3 小时前
云隙一言:鸿蒙Flutter框架 实现的随机名言应用
开发语言·flutter·华为·架构·开源·harmonyos
Utopia^5 小时前
鸿蒙flutter第三方库适配 - 图片拼图工具
flutter·华为·harmonyos
星释5 小时前
鸿蒙Flutter实战:29.优先使用联合插件开发鸿蒙化插件
flutter·华为·harmonyos·鸿蒙
特立独行的猫a5 小时前
OpenHarmony平台移植 gifsicle:C/C++ 三方库适配实践(Lycium / tpc_c_cplusplus)
c语言·c++·harmonyos·openharmony·三方库适配·lycium
不爱吃糖的程序媛5 小时前
鸿蒙三方库适配读懂 `README_zh.md`:中文适配说明里每段在说什么?
华为·harmonyos
见山是山-见水是水7 小时前
鸿蒙flutter第三方库适配 - 文件加密工具
flutter·华为·harmonyos
key_3_feng7 小时前
HarmonyOS 6.0 健康食谱应用开发方案
华为·harmonyos
麒麟ZHAO8 小时前
鸿蒙flutter第三方库适配 - 文件对比工具
数据库·redis·flutter·华为·harmonyos
互联网散修8 小时前
零基础鸿蒙应用开发第三十四节:MVVM架构下的商品管理登录页
架构·harmonyos·mvvm·登录