@expo-harmony/expo-media-library
v55.0.21-harmony.2
Published
HarmonyOS port of expo-media-library
Maintainers
Readme
@expo-harmony/expo-media-library
为 HarmonyOS 上的 React Native 应用提供 Expo MediaLibrary 的原生实现,与官方同版本的 expo-media-library 配套使用。支持图片和视频的查询、分页、元数据读取、保存、删除、相册成员管理,以及图库变更监听。
安装
npm install @expo-harmony/expo-media-library [email protected]本包适配 Expo SDK 55 的 expo-media-library,原生模块通过 Expo Harmony 自动链接。最低支持 HarmonyOS 5.0.1(API 13),宿主的 compatibleSdkVersion 也要满足这一要求。
查询图片、视频和相册需要 ohos.permission.READ_IMAGEVIDEO,保存和删除资源需要 ohos.permission.WRITE_IMAGEVIDEO。本包默认不声明这两项权限,使用前需按下文申请并配置。
业务代码从官方包导入:
import * as MediaLibrary from 'expo-media-library';
// 使用前需完成下方的权限配置。
const permission = await MediaLibrary.requestPermissionsAsync();
if (permission.granted) {
const { assets, endCursor, hasNextPage } = await MediaLibrary.getAssetsAsync({
first: 20,
mediaType: ['photo', 'video'],
});
}图库权限
ohos.permission.READ_IMAGEVIDEO 和 ohos.permission.WRITE_IMAGEVIDEO 属于受限权限(ACL),需按华为的 受限权限说明 申请。
只需让用户选择图片或视频时,可以使用 expo-image-picker 的系统选择器代替图库读写权限。
取得授权后,在 app.json 的 expo.harmony.permissions 数组中添加以下读取权限声明:
{
"name": "ohos.permission.READ_IMAGEVIDEO",
"reason": "$string:expo_media_library_read_permission_reason",
"usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
}写入权限使用以下声明,也添加到该数组中:
{
"name": "ohos.permission.WRITE_IMAGEVIDEO",
"reason": "$string:expo_media_library_write_permission_reason",
"usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
}reason 引用本包提供的默认用途说明。若入口 Ability 的名称不是 EntryAbility,请替换为实际名称。
修改 app.json 后,需要重新 prebuild 并构建应用。bare 工程可将上述声明加入入口模块 module.json5 的 requestPermissions 数组。应用签名需使用包含获批权限的 Profile 文件。
使用前需调用 requestPermissionsAsync() 向用户申请读写权限,并在返回的 granted 为 true 后调用图库接口。未取得所需权限时,调用会抛出 ERR_MEDIA_LIBRARY_PERMISSION。
若只使用 saveToLibraryAsync() 保存文件,可以只声明写入权限,并调用 requestPermissionsAsync(true) 申请用户授权。createAssetAsync() 需要同时取得读取和写入权限。
API 对照表
Constants
MediaLibrary.MediaType
类型:{ audio: 'audio', photo: 'photo', video: 'video', unknown: 'unknown' }
媒体类型取值。HarmonyOS 的公开接口不管理音频,audio 只作为取值存在,不能用于筛选出音频资源。
MediaLibrary.SortBy
类型:SortByObject
getAssetsAsync 支持的排序键:default、mediaType、width、height、creationTime、modificationTime、duration。
Hooks
usePermissions(options)
返回 [PermissionResponse | null, request, get],分别是权限状态、申请权限和查询权限的方法。options 见 PermissionHookOptions。
Methods
MediaLibrary.isAvailableAsync()
返回 Promise<boolean>。设备提供系统图库能力时为 true;不提供时只注册常量与事件,返回 false。
MediaLibrary.getPermissionsAsync(writeOnly)
返回 Promise<PermissionResponse>,查询图库权限。
writeOnly 省略或为 false 时同时检查读和写权限,为 true 时只检查写权限。status 可能为 'granted'、'denied' 或 'undetermined'。API 20 及以上由系统区分未决定和已拒绝;API 13 到 API 19 的系统查询只能给出已授权或未授权,模块自己记录用户有没有被问过,没问过时按未决定返回。
accessPrivileges 只会是 'all' 或 'none',HarmonyOS 不提供部分授权,不会出现 'limited'。expires 恒为 'never'。
MediaLibrary.requestPermissionsAsync(writeOnly)
返回 Promise<PermissionResponse>,弹出系统授权对话框,取值与 getPermissionsAsync() 一致。granularPermissions 参数不生效。
权限没有在 module.json5 中声明时,申请抛出 ERR_MEDIA_LIBRARY_PERMISSION_REQUEST。未授权时调用需要权限的方法抛出 ERR_MEDIA_LIBRARY_PERMISSION。
MediaLibrary.getAssetsAsync(assetsOptions)
返回 Promise<PagedInfo<Asset>>,查询一页图片或视频,需要读权限。
first 默认 20。after 传上一页的 endCursor;这个值必须是同一次查询结果中的资源标识,找不到时抛出 ERR_MEDIA_LIBRARY_INVALID_CURSOR。album 限定相册,相册标识不存在时抛出 ERR_MEDIA_LIBRARY_ALBUM_NOT_FOUND。
mediaType 默认 ['photo'],可以传 'all'、'photo'、'video';传 'all' 时不按类型过滤。'audio' 和 'unknown' 在 HarmonyOS 上查不到内容,只传这两个值时返回空页,与图片或视频一起传时忽略。取值不在这些值中时抛出错误。
sortBy 支持 SortBy 里的键,默认按平台顺序。SortBy.default 忽略方向。按 creationTime 排序或使用 createdAfter、createdBefore 筛选时,会先加载符合其余条件的资源再选出这一页,内存用量随候选集规模增长,不推荐在大图库上使用。
resolveWithFullInfo 为 true 时同时读出图片的 EXIF。资源的方向已在读取时校正,宽高按校正后的值返回。
MediaLibrary.getAssetInfoAsync(asset, options)
返回 Promise<AssetInfo | null>,读取单个资源的详细信息,需要读权限。资源不存在时返回 null。options.shouldDownloadFromNetwork 不生效。
localUri 是资源的原始地址。location 从 EXIF 的 GPS 字段换算成十进制度,读不到时为 null。exif 的字段集合和带单位的取值来自系统图像框架,与 Android、iOS 可能不同。isFavorite 取系统的收藏标记。
MediaLibrary.getAlbumsAsync(options)
返回 Promise<Album[]>,查询用户相册,需要读权限。includeSmartAlbums 为 true 时一并返回系统相册,这些相册的 type 为 'smartAlbum'。
MediaLibrary.getAlbumAsync(title)
返回 Promise<Album | null>,按名称查询用户相册,需要读权限。找不到时返回 null。系统相册不参与匹配。
MediaLibrary.createAssetAsync(localUri, album)
返回 Promise<Asset>,把本地文件导入图库,需要读权限和写权限。
localUri 必须指向应用沙箱内的文件,并带有图片或视频的扩展名,否则抛出 ERR_MEDIA_LIBRARY_MISSING_EXTENSION、ERR_MEDIA_LIBRARY_UNSUPPORTED_MEDIA_TYPE 或 ERR_MEDIA_LIBRARY_INVALID_URI。传入 album 时,资源创建后加入该相册;相册必须存在而且是用户相册。
保存已经生效、但后续读取资源信息或加入相册失败时,Promise 拒绝,创建的资源留在图库里,不会回滚。
MediaLibrary.saveToLibraryAsync(localUri)
返回 Promise<void>,把本地文件保存到图库,只写权限即可,不需要读权限。文件要求与 createAssetAsync() 相同。
MediaLibrary.addAssetsToAlbumAsync(assets, album, copy)
返回 Promise<boolean>,把资源加入相册,需要读权限和写权限。
加入相册不复制文件,copy 取任何值行为都一样。相册必须是用户相册,资源标识必须存在,否则抛出 ERR_MEDIA_LIBRARY_UNSUPPORTED_ALBUM_OPERATION 或 ERR_MEDIA_LIBRARY_ASSET_NOT_FOUND。传入空的资源数组时直接返回 true。
MediaLibrary.removeAssetsFromAlbumAsync(assets, album)
返回 Promise<boolean>,把资源移出相册,需要读权限和写权限。相册和资源的要求与 addAssetsToAlbumAsync() 相同。
MediaLibrary.deleteAssetsAsync(assets)
返回 Promise<boolean>,删除资源,需要写权限。系统会弹出删除确认,超过 300 个资源时分批处理,前面的批次已删除、后面的批次被取消或失败时,Promise 拒绝,删除不会整体回滚。
未实现的内容
createAlbumAsync()、deleteAlbumsAsync():HarmonyOS 没有对第三方应用公开的相册创建和删除接口,调用抛出ERR_MEDIA_LIBRARY_UNSUPPORTED_ALBUM_OPERATION。getMomentsAsync():iOS 专属接口,HarmonyOS 上没有对应能力。albumNeedsMigrationAsync()、migrateAlbumIfNeededAsync():Android 专属接口,HarmonyOS 上不需要迁移。presentPermissionsPickerAsync():Android 14+ 与 iOS 专属接口,HarmonyOS 上不提供部分授权的调整入口。expo-media-library/next入口:官方实验性接口,HarmonyOS 上没有实现。
Event subscriptions
MediaLibrary.addListener(listener)
返回 Subscription,订阅图库变更,需要读权限。没有读权限时不订阅系统变更,收不到事件。只在应用处于前台且存在订阅时触发。
事件对象的 hasIncrementalChanges 恒为 false,不附带增删改的资源列表,收到通知后应重新查询。
MediaLibrary.removeSubscription(subscription)
取消指定的监听。官方已标记废弃,改调 subscription.remove()。
MediaLibrary.removeAllListeners()
移除全部图库变更监听。
Types
Album
| 属性 | 类型 | 说明 |
| ------------ | ----------- | --------------------------- |
| id | string | 相册标识,取自系统相册地址 |
| title | string | 相册名称 |
| assetCount | number | 相册中的资源数量 |
| type | AlbumType | 'album' 或 'smartAlbum' |
AlbumType
'album' | 'moment' | 'smartAlbum'。HarmonyOS 只返回 'album' 和 'smartAlbum'。
AlbumRef
Album | string。
AlbumsOptions
| 属性 | 类型 | 说明 |
| -------------------- | --------- | ------------------------------ |
| includeSmartAlbums | boolean | 是否包含系统相册,默认 false |
Asset
| 属性 | 类型 | 说明 |
| ------------------ | ---------------- | ----------------------------------- |
| id | string | 资源标识,与 uri 相同 |
| filename | string | 系统显示的文件名 |
| uri | string | 资源地址 |
| mediaType | MediaTypeValue | 'photo'、'video' 或 'unknown' |
| width | number | 宽,单位像素,按方向校正 |
| height | number | 高,单位像素,按方向校正 |
| creationTime | number | 创建时间,Unix 纪元以来的毫秒数 |
| modificationTime | number | 修改时间,Unix 纪元以来的毫秒数 |
| duration | number | 时长,单位秒,图片为 0 |
资源没有拍摄时间时,creationTime 取入库时间。
AssetInfo
Asset 基础上增加以下属性:localUri、location、exif、isFavorite。见 getAssetInfoAsync()。
AssetRef
Asset | string。
AssetsOptions
| 属性 | 类型 | 说明 |
| --------------------- | ------------------------------------ | -------------------------------------- |
| first | number | 单页最多返回的数量,默认 20 |
| after | AssetRef | 上一页的 endCursor |
| album | AlbumRef | 只查询该相册中的资源 |
| mediaType | MediaTypeValue[] \| MediaTypeValue | 资源类型,默认 MediaType.photo |
| sortBy | SortByValue[] \| SortByValue | 排序键,可以传 [key, ascending] 组合 |
| createdAfter | Date \| number | 只返回该时间之后创建的资源 |
| createdBefore | Date \| number | 只返回该时间之前创建的资源 |
| resolveWithFullInfo | boolean | 是否一并读出 EXIF,默认 false |
未实现的内容
AssetsOptions.mediaSubtypes:iOS 专属选项,HarmonyOS 上不读取。
Location
| 属性 | 类型 | 说明 |
| ----------- | -------- | ------------ |
| latitude | number | 纬度,单位度 |
| longitude | number | 经度,单位度 |
MediaLibraryAssetInfoQueryOptions
| 属性 | 类型 | 说明 |
| --------------------------- | --------- | ------------------------ |
| shouldDownloadFromNetwork | boolean | HarmonyOS 上不读取该选项 |
MediaLibraryAssetsChangeEvent
| 属性 | 类型 | 说明 |
| ----------------------- | --------- | ---------------------------------- |
| hasIncrementalChanges | boolean | 恒为 false,变更内容需要重新查询 |
MediaTypeObject
见 MediaLibrary.MediaType。
MediaTypeValue
'audio' | 'photo' | 'video' | 'unknown' | 'pairedVideo'。HarmonyOS 上只会出现 'photo'、'video' 和 'unknown'。
PagedInfo
| 属性 | 类型 | 说明 |
| ------------- | --------- | ---------------------------------------- |
| assets | Asset[] | 当前页的资源 |
| endCursor | string \| null | 本页最后一项的标识,作为下一页的 after;结果为空且没有传 after 时为 null |
| hasNextPage | boolean | 是否还有下一页 |
| totalCount | number | 符合条件的资源总数 |
PermissionExpiration
'never' | number,恒为 'never'。
PermissionHookOptions
PermissionHookBehavior | Options。
PermissionResponse
| 属性 | 类型 | 说明 |
| ------------------ | ------------------------------ | ------------------------------------------- |
| status | PermissionStatus | 'granted'、'denied' 或 'undetermined' |
| granted | boolean | 是否已授权 |
| canAskAgain | boolean | 被系统阻止再次询问时为 false |
| expires | PermissionExpiration | 恒为 'never' |
| accessPrivileges | 'all' \| 'limited' \| 'none' | 只会是 'all' 或 'none' |
SortByKey
'default' | 'mediaType' | 'width' | 'height' | 'creationTime' | 'modificationTime' | 'duration'。
SortByObject
见 MediaLibrary.SortBy。
SortByValue
[SortByKey, boolean] | SortByKey。
未实现的内容
GranularPermission:Android 13+ 专属类型,HarmonyOS 的权限申请没有粒度选项。MediaSubtype:iOS 专属类型,HarmonyOS 不提供媒体子类型。MediaTypeFilter:Android 14+ 与 iOS 专属类型,配合部分授权使用。Asset.albumId、Asset.mediaSubtypes:Android 与 iOS 专属字段,HarmonyOS 上不返回。AssetInfo.isNetworkAsset、AssetInfo.orientation、AssetInfo.pairedVideoAsset:iOS 专属字段,HarmonyOS 上没有取值来源。Album.startTime、Album.endTime、Album.approximateLocation、Album.locationNames:iOS moment 相册专属字段,HarmonyOS 上没有取值来源。
Enums
PermissionStatus
'granted' | 'denied' | 'undetermined',三个取值都会出现。
Author
expo-harmony © Baoshuo, Released under the MIT License. Authored and maintained by Baoshuo with help from contributors
Personal Website · Blog · GitHub @renbaoshuo · Twitter @renbaoshuo
