《鸿蒙/Harmony | 开发日志》选择文件或拍照功能
鸿蒙选择文件或拍照的功能,有直接可以用的 API,而且和Android相比,最大的好处,是不需要向用户索要文件权限。
不需要索要权限的原因是,鸿蒙的权限改动升级的非常大,以前 Android的权限逻辑是,你授予了文件或图库的权限后,代码是可以在后台获取你所有的文件。这一点也是非常大的安全隐患。所以我自己用Android APP根本不敢随便授权那些 APP 给照片权限的,万一人家后台暗戳戳的扫码你的敏感图片,用户根本不知道的。
(这个权限的痛点,也是我使用最大的痛点。迫不及待的想升级鸿蒙。)
但是现在鸿蒙的文件权限逻辑是,没有办法可以直接获取文件库的权限,只有拉起的选择文件的界面,选择了几个文件,那么 APP 的代码就只能临时获取这几个文件的权限,APP 关闭再重新打开后,这些权限都消失了(当然有别的方式,可以存取这些临时的权限,网盘类的 APP 必须要这样),必须再次打开选择界面了。
选择文件 / 照片
一般在 APP 中选择文件大概分类三类
- 照片 + 拍照
- 视频 + 录像
- 文件(各种类型的文件、浏览器下载的文件等)
在鸿蒙中,这几类是不同的。
照片和视频,属性媒体类,而文件是系统文件类 。这上面三种都是需要调用不同的 API 来文件的。虽然获取文件的方式根据上面的类别不同调用的 API 不同,但是获取后文件的处理,是一样的。
照片 + 拍照
效果:
可以使用访问提供的 Picker API,选择照片并且自带拍照功能,参考官方文档《使用Picker选择媒体库资源》
const options = new photoAccessHelper.PhotoSelectOptions();
options.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE; // 过滤选择媒体文件类型为IMAGE
options.maxSelectNumber = 1; // 获取多少张
const picker = new photoAccessHelper.PhotoViewPicker()
const result = await picker.select(options)
const uris = result.photoUris;
if (uris.length == 0) {
return null // 没有选择文件
}
const imgURI = uris[0] // 获取的文件
在这里注意一下。官方文档描述了一段:
select返回的uri权限是只读权限,可以根据结果集中uri进行读取文件数据操作。注意不能在picker的回调里直接使用此uri进行打开文件操作,需要定义一个全局变量保存uri,使用类似一个按钮去触发打开文件。
文件 + 浏览器下载
访问自带选择文件的API《【鸿蒙官方文档】选择用户文件》,调用出来的界面,特别像 PC 端,浏览器打开的选择文件,可以多选,如下图:
const options = new picker.DocumentSelectOptions();
// 选择文档的最大数目(可选)
options.maxSelectNumber = 5;
const documentViewPicker = new picker.DocumentViewPicker(uiAbilityContext);
const uris = await documentViewPicker.select(options)
if (uris.length == 0) {
return null // 没有选择文件
}
const fileURI = uris[0] // 获取的文件
在这里注意一下。官方文档描述了一段:
注意
1、使用picker获取的select()返回的uri权限是临时只读权限,待退出应用后台后,获取的临时权限就会失效。
2、如果想要获取持久化权限(仅在2in1设备上生效),请参考文件持久化授权访问。
3、开发者可以根据结果集中uri做进一步的处理。建议定义一个全局变量保存uri。
多选的效果图:
选择视频 + 拍摄
目前官方文档提供了两种选择视频的方式。
- 使用《Picker选择媒体库资源》
- 使用《文件选择器》
在实践过程中,推荐还是第一种比较方便,第二种只能获取 APP 当前自带有权限的目录,如果没有传递授权目录,就会没有视频可以选,也没有拍摄的功能。
第一种和照片的接口一样,只是修改一下参数即可:
const options = new photoAccessHelper.PhotoSelectOptions();
options.MIMEType = photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE; // 过滤选择媒体文件类型为视频
options.maxSelectNumber = 1;
const picker = new photoAccessHelper.PhotoViewPicker()
const result = await picker.select(options)
效果如下图:
根据上一步获取到的uri,获取文件详细信息
可以使用《文件管理 API》和《文件URI API》来获取文件的信息。根据上面官方提示需要使用单独的按钮触发,才能去用api去打开文档。但是我本人实验过,是可以直接使用api来获取文件的信息的。
获取文件的名称
《文件URI API》可以简单的获取文件的名称。
import { fileUri } from '@kit.CoreFileKit';
//imgURI 是上一步获取的文件uri file://media/xxx
let fileUriObject = new fileUri.FileUri(imgURI);
console.info("The name of FileUri is " + fileUriObject.name);
获取文件的大小
这个需要使用《文件管理 API》来获取。stat
方法获取。注意直接调用stat
方法传入上面的 imgURI的话,会报错,文件不存在。需要先使用open
方法,获取文件的fd
信息,在把fd
传给stat
方法,才能成功获取信息。
import { fileIo as fs } from '@kit.CoreFileKit';
const file = await fs.open(imgURI)
const stat = await fs.stat(file.fd) // file.fd 是个数字类似 153 这样的。不用明白这数字是干嘛的
console.log(stat.size)
获取文件的二进制
import { fileIo as fs } from '@kit.CoreFileKit';
const file = await fs.open(imgURI)
const stat = await fs.stat(file.fd) // file.fd 是个数字类似 153 这样的。不用明白这数字是干嘛的
let arrayBuffer = new ArrayBuffer(stat.size);
await fs.read(file.fd, arrayBuffer)
图片压缩
参考另一篇文章《鸿蒙/Harmony | 开发日志》图片压缩