鸿蒙应用ArkTS开发- 选择图片、文件和拍照功能实现

devtools/2024/11/13 15:35:31/

前言

在使用App的时候,我们经常会在一些社交软件中聊天时发一些图片或者文件之类的多媒体文件,那在鸿蒙原生应用中,我们怎么开发这样的功能呢? 本文会给大家对这个功能点进行讲解,我们采用的是拉起系统组件来进行图片、文件的选择,拉起系统相机进行拍照的这样一种实现方式。

创建多媒体Demo工程

我们使用Empty 模板创建一个Demo工程。

创建MediaBean 实体类

在src->main->ets 下面创建bean文件夹,在文件夹下创建MediaBean.ts文件

/*** 多媒体数据类*/
export class MediaBean {/*** 文件名称*/public fileName: string;/*** 文件大小*/public fileSize: number;/*** 文件类型*/public fileType: string;/*** 本地存储地址*/public localUrl: string;
}

创建MediaHelper工具类

在src->main->ets 下面创建helper 文件夹,在文件夹下创建MediaHelper.ts文件

MediaHelper.ts 完整代码如下:

import common from '@ohos.app.ability.common';
import picker from '@ohos.file.picker';
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
import wantConstant from '@ohos.ability.wantConstant';
import { MediaBean } from '../bean/MediaBean';
import { StringUtils } from '../utils/StringUtils';
import { Log } from '../utils/Log';/*** 多媒体辅助类*/
export class MediaHelper {private readonly TAG: string = 'MediaHelper';private mContext: common.Context;constructor(context: common.Context) {this.mContext = context;}/*** 选择图片*/public selectPicture(): Promise<MediaBean> {try {let photoSelectOptions = new picker.PhotoSelectOptions();photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;photoSelectOptions.maxSelectNumber = 1;let photoPicker = new picker.PhotoViewPicker();return photoPicker.select(photoSelectOptions).then((photoSelectResult) => {Log.info(this.TAG, 'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(photoSelectResult));if (photoSelectResult && photoSelectResult.photoUris && photoSelectResult.photoUris.length > 0) {let filePath = photoSelectResult.photoUris[0];Log.info(this.TAG, 'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + filePath);return filePath;}}).catch((err) => {Log.error(this.TAG, 'PhotoViewPicker.select failed with err: ' + err);return err;}).then(async (filePath) => {const mediaBean = await this.buildMediaBean(filePath);return mediaBean;});} catch (err) {Log.error(this.TAG, 'PhotoViewPicker failed with err: ' + err);return Promise.reject(err);}}/*** 选择文件*/public selectFile(): Promise<MediaBean> {try {let documentSelectOptions = new picker.DocumentSelectOptions();let documentPicker = new picker.DocumentViewPicker();return documentPicker.select(documentSelectOptions).then((documentSelectResult) => {Log.info(this.TAG, 'DocumentViewPicker.select successfully, DocumentSelectResult uri: ' + JSON.stringify(documentSelectResult));if (documentSelectResult && documentSelectResult.length > 0) {let filePath = documentSelectResult[0];Log.info(this.TAG, 'DocumentViewPicker.select successfully, DocumentSelectResult uri: ' + filePath);return filePath;}}).catch((err) => {Log.error(this.TAG, 'PhotoViewPicker.select failed with err: ' + err);return err;}).then(async (filePath) => {const mediaBean = await this.buildMediaBean(filePath);return mediaBean;});} catch (err) {Log.error(this.TAG, 'PhotoViewPicker failed with err: ' + err);return Promise.reject(err);}}/*** 拍照*/public async takePhoto(context: common.UIAbilityContext): Promise<MediaBean> {let want = {'uri': '','action': wantConstant.Action.ACTION_IMAGE_CAPTURE,'parameters': {},};return context.startAbilityForResult(want).then((result) => {Log.info(this.TAG, `startAbility call back , ${JSON.stringify(result)}`);if (result.resultCode === 0 && result.want && StringUtils.isNotNullOrEmpty(result.want.uri)) {//拍照成功Log.info(this.TAG, 'takePhoto successfully, takePhotoResult uri: ' + result.want.uri);return result.want.uri;}}).catch((error) => {Log.info(this.TAG, `startAbility error , ${JSON.stringify(error)}`);return error;}).then(async (uri: string) => {const mediaBean = await this.buildMediaBean(uri);return mediaBean;});}/*** 封装多媒体实体类** @param uri 文件路径*/private async buildMediaBean(uri: string): Promise<MediaBean> {if (StringUtils.isNullOrEmpty(uri)) {return null;}const mediaBean: MediaBean = new MediaBean();mediaBean.localUrl = uri;await this.appendFileInfoToMediaBean(mediaBean, uri);return mediaBean;}/*** 通过Uri查找所选文件信息,插入到MediaBean中* @param mediaBean* @param uri*/private async appendFileInfoToMediaBean(mediaBean: MediaBean, uri: string) {if (StringUtils.isNullOrEmpty(uri)) {return;}let fileList: Array<mediaLibrary.FileAsset> = [];const parts: string[] = uri.split('/');const id: string = parts.length > 0 ? parts[parts.length - 1] : '-1';try {let media = mediaLibrary.getMediaLibrary(this.mContext);let mediaFetchOptions: mediaLibrary.MediaFetchOptions = {selections: mediaLibrary.FileKey.ID + '= ?',selectionArgs: [id],uri: uri};let fetchFileResult = await media.getFileAssets(mediaFetchOptions);Log.info(this.TAG, `fileList getFileAssetsFromType fetchFileResult.count = ${fetchFileResult.getCount()}`);fileList = await fetchFileResult.getAllObject();fetchFileResult.close();await media.release();} catch (e) {Log.error(this.TAG, "query: file data  exception ");}if (fileList && fileList.length > 0) {let fileInfoObj = fileList[0];Log.info(this.TAG, `file id = ${JSON.stringify(fileInfoObj.id)} , uri = ${JSON.stringify(fileInfoObj.uri)}`);Log.info(this.TAG, `file fileList displayName = ${fileInfoObj.displayName} ,size = ${fileInfoObj.size} ,mimeType = ${fileInfoObj.mimeType}`);mediaBean.fileName = fileInfoObj.displayName;mediaBean.fileSize = fileInfoObj.size;mediaBean.fileType = fileInfoObj.mimeType;}}
}

MediaHelper 类定义了5个方法,

  • selectPicture 提供选择图片功能

     我们通过系统组件 picker.PhotoViewPicker 来进行图片选择,通过配置PhotoSelectOptions,指定选择的MIMEType类型(这里PhotoViewMIMETypes.IMAGE_TYPE 图片类型) 、选择的图片最大数量 maxSelectNumber ,这里我们实现单选功能,数值设置为1即可。使用photoPicker.select 拉起系统组件进行选择,然后在回调中获取图片的uri。
    
  • selectFile 提供选择文件功能

    选择文件的功能,我们通过系统组件 picker.DocumentViewPicker来进行文件选择,代码基本是跟图片选择是一样的,区别在于DocumentSelectOptions,目前api9并没有配置项提供,具体关注后续的api版本情况。

  • takePhoto 提供拍照功能

    拍照的功能,我们也是拉起相机来进行拍照的,我们使用 startAbilityForResult 方法 + 配置拉起action (wantConstant.Action.ACTION_IMAGE_CAPTURE)的方式拉起系统相机,拍照结束后,在then中接收返回的数据,我们通过返回码result.resultCode 来判断是否进行了拍照,如果状态值===0,说明进行了拍照,我们再使用result.want.uri获取拍照后的照片uri。

  • buildMediaBean 内部方法,提供MediaBean对象封装

    这个方法的作用主要是封装一个多媒体实体类,并触发appendFileInfoToMediaBean 获取Uri对应文件的一些文件信息。代码很简单,相信大家一目了然。

  • appendFileInfoToMediaBean 内部方法,提供追加查询所选文件的文件信息的功能

    这个方法的作用主要是通过uri查询文件的详细信息,包括文件名称、文件大小、文件类型。通过Uri获取文件ID。使用mediaLibrary.getMediaLibrary获取media对象。配置MediaFetchOptions,主要是ID,通过文件ID来查找文件对象。使用media.getFileAssets查询文件对象结果,这里可以是批量操作,得到一个FetchFileResult对象。遍历FileAsset数组,得到文件信息。

    这里列下FileAsset的一些字段:

通过系统组件选择图片、文件或者拍照之后,系统只是简单的返回一个文件的Uri,如果我们需要展示文件的名称、文件大小、文件类型,需要通过appendFileInfoToMediaBean 方法另外去获取。

API标记弃用问题

上面的代码,在api9实测是可以正常使用的,但是有一些API被标记为过期,有一些在官方文档注明即将停用,但是我没有找到可以平替的API,如果有读者知道的,麻烦评论区告诉我一声,谢谢。

  1. ohos.app.ability.wantConstant

    官方提示让我们切换到 ohos.app.ability.wantConstant这个类下,可是我们用到wantConstant.Action,这个Action在 ohos.app.ability.wantConstant中没有定义,我在SDK中也没有找到Action在哪一个类中定义;

  2. mediaLibrary.getMediaLibrary.getFileAssets

    我们需要使用getMediaLibrary获取多媒体对象,调用getFileAssets查询文件的多媒体信息,官方提示让我们使用ohos.file.picker,奇怪的是picker中没有getFileAssets 相关的方法,不知道官方基于什么考虑,可能后续API10会增加相应方法支持吧。那我们通过picker只能拿到一个文件的Uri,文件名称、文件大小这些常规的文件相关的数据都拿不到,那功能都无法开发,这也是我之前的一个疑问。

动态申请多媒体访问权限

我们读取文件的多媒体信息需要申请一个多媒体的读取权限 ohos.permission.READ_MEDIA,这个权限需要在

module.json5中添加配置requestPermissions,在该节点下配置READ_MEDIA权限,具体如下图:

由于这个READ_MEDIA权限需要进行动态权限申请,因为还需要我们进行动态权限申请代码逻辑开发,这里由于篇幅原因,我就不过多赘述,后续如果对这块动态权限申请有不明白的地方,我再重新写一篇文章介绍,讲下动态申请权限,跳转系统权限设置页配置权限这些功能具体如何实现。

这次的Demo,我们直接安装后,在系统设置中找到应用,把对应的权限开启即可(绕过权限动态申请)。

实现选择图片显示功能

下面我们编写UI页面,使用我们上面的MediaHelper工具类选择图片、拍照,并将图片显示出来。

我们在Index.ets文件中放三个按钮,以及显示文件名称、大小、文件类型以及文件路径、显示图片的控件。
完整的代码如下:

import common from '@ohos.app.ability.common';
import { MediaBean } from '../bean/MediaBean';
import { MediaHelper } from '../helper/MediaHelper';@Entry
@Component
struct Index {@State mediaBean: MediaBean = new MediaBean();private mediaHelper: MediaHelper = new MediaHelper(getContext());build() {Row() {Column() {Text('选择图片').textAlign(TextAlign.Center).width(200).fontSize(16).padding(10).margin(20).border({ width: 0.5, color: '#ff38f84b', radius: 15 }).onClick(() => {this.handleClick(MediaOption.Picture)})Text('选择文件').textAlign(TextAlign.Center).width(200).fontSize(16).padding(10).margin(20).border({ width: 0.5, color: '#ff38f84b', radius: 15 }).onClick(() => {this.handleClick(MediaOption.File)})Text('拍照').textAlign(TextAlign.Center).width(200).fontSize(16).padding(10).margin(20).border({ width: 0.5, color: '#ff38f84b', radius: 15 }).onClick(() => {this.handleClick(MediaOption.TakePhoto)})Divider().width('100%').height(0.5).color('#ff99f6a2').margin({ top: 20 }).padding({ left: 20, right: 20 })Text(`文件名称: ${this.mediaBean.fileName ? this.mediaBean.fileName : ''}`).textAlign(TextAlign.Center).width('100%').fontSize(16).margin(10)Text(`文件大小: ${this.mediaBean.fileSize ? this.mediaBean.fileSize : ''}`).textAlign(TextAlign.Center).width('100%').fontSize(16).margin(10)Text(`文件类型: ${this.mediaBean.fileType ? this.mediaBean.fileType : ''}`).textAlign(TextAlign.Center).width('100%').fontSize(16).margin(10)Text(`文件Uri: ${this.mediaBean.localUrl ? this.mediaBean.localUrl : ''}`).textAlign(TextAlign.Center).width('100%').fontSize(16).margin(10)Image(this.mediaBean.localUrl).width(300).height(300).backgroundColor(Color.Grey)}.width('100%').height('100%')}.height('100%')}async handleClick(option: MediaOption) {let mediaBean: MediaBean;switch (option) {case MediaOption.Picture:mediaBean = await this.mediaHelper.selectPicture();break;case MediaOption.File:mediaBean = await this.mediaHelper.selectFile();break;case MediaOption.TakePhoto:mediaBean = await this.mediaHelper.takePhoto(getContext() as common.UIAbilityContext);break;default:break;}if (mediaBean) {this.mediaBean = mediaBean;}}
}enum MediaOption {Picture = 0,File = 1,TakePhoto = 2
}

打包测试

打包安装到真机上,需要我们给项目配置签名信息。我们点击File -> Project Structure ->Project ,选择 Signing Configs面板,勾选 Support HarmonyOS 跟Automatically generate signature,自动生成调试签名,生成完毕后,运行安装到手机上。

注意:由于我们没有实现多媒体读取权限动态申请权限,因此需要在手机系统设置-应用中找到该应用,开启多媒体权限,该权限默认是禁止的,开启后再打开应用操作即可。运行的具体的效果如文章开头贴图展示一般。

鸿蒙全栈开发全新学习指南

也为了积极培养鸿蒙生态人才,让大家都能学习到鸿蒙开发最新的技术,针对一些在职人员、0基础小白、应届生/计算机专业、鸿蒙爱好者等人群,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线[包含了大APP实战项目开发]。

本路线共分为四个阶段:

第一阶段:鸿蒙初中级开发必备技能

第二阶段:鸿蒙南北双向高工技能基础:https://qr21.cn/Bm8gyp

第三阶段:应用开发中高级就业技术

第四阶段:全网首发-工业级南向设备开发就业技术:https://qr21.cn/Bm8gyp

《鸿蒙 (Harmony OS)开发学习手册》(共计892页)

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:https://qr21.cn/Bm8gyp

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习
ArkTS语言
9.……

ArkTS__458">基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

鸿蒙开发面试真题(含参考答案):https://qr21.cn/Bm8gyp

鸿蒙入门教学视频:

美团APP实战开发教学:https://qr21.cn/Bm8gyp

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://qr21.cn/FV7h05


http://www.ppmy.cn/devtools/17444.html

相关文章

03-JAVA设计模式-状态模式

状态模式 什么是状态模式 Java中的状态模式&#xff08;State Pattern&#xff09;是一种行为型设计模式&#xff0c;主要用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。状态模式允许一个对象在其内部状态改变时改变它的行为&#xff0c;使得对象看起来似乎…

笔记:Python 循环结构练习题

文章目录 前言一、Python 循环结构是什么&#xff1f;二、选择题2.填空题 总结 前言 欢迎来到Python循环结构的练习题目录&#xff01;本系列旨在帮助您巩固和提升您对Python循环结构的理解和应用能力。循环结构是编程中的重要概念之一&#xff0c;通过它&#xff0c;您可以轻…

OpenStack云计算(十)——OpenStack虚拟机实例管理,增加一个计算节点并进行实例冷迁移,增加一个计算节点的步骤,实例冷迁移的操作方法

项目实训一 本实训任务对实验环境要求较高&#xff0c;而且过程比较复杂&#xff0c;涉及的步骤非常多&#xff0c;有一定难度&#xff0c;可根据需要选做。可以考虑改为直接观看相关的微课视频 【实训题目】 增加一个计算节点并进行实例冷迁移 【实训目的】 熟悉增加一个…

MATLAB实现蚁群算法优化柔性车间调度(ACO-fjsp)

蚁群算法优化车间调度的步骤可以分为以下几个主要阶段&#xff1a; 1.初始化阶段&#xff1a; 设置算法参数&#xff0c;如信息素浓度、启发式因子等。这些参数将影响蚂蚁在选择路径时的决策过程。 确定车间调度的具体问题规模&#xff0c;包括工件数量、机器数量以及每个工件…

模拟电路 第三章(模拟集成电路)

一、模拟集成电路中的直流偏置技术 1、镜像电流源 镜像电流源的电路图如下图所示&#xff0c;、的参数完全相同&#xff0c;即、&#xff0c;由于两管具有相同的基-射极间电压&#xff08;&#xff09;&#xff0c;所以、。当BJT的较大时&#xff0c;基极电流可以忽略&#xf…

C语言求 MD5 值

MD5值常被用于验证数据的完整性&#xff0c;嵌入式开发时经常用到。md5sum命令可以求MD5码&#xff0c;下面介绍如何用C语言实现MD5功能。 一、求字符串MD5值 1、md5sum命令 $ echo -n "12345678" | md5sum //获取"12345678"字符串的md5值 结果&…

html、css、QQ音乐移动端静态页面,资源免费分享,可作为参考,提供InsCode在线运行演示

CSDN将我上传的免费资源私自变成VIP专享资源&#xff0c;且作为作者的我不可修改为免费资源&#xff0c;不可删除&#xff0c;寻找客服无果&#xff0c;很愤怒&#xff0c;&#xff08;我发布免费资源就是希望大家能免费一起用、一起学习&#xff09;&#xff0c;接下来继续寻找…

百度沈抖:智能,生成无限可能

4月16日&#xff0c;Create 2024百度AI开发者大会在深圳举行。会上&#xff0c;百度集团执行副总裁、百度智能云事业群总裁沈抖正式发布新一代智能计算操作系统——百度智能云万源。它能管理万卡规模的集群&#xff0c;极致地发挥GPU、CPU的性能&#xff1b;它有强大的大模型作…