基于 react-native-cameraroll 的 OpenHarmony 适配版,访问系统相册(保存/读取照片和视频)
当前访问频次受限,请登录后继续访问
文档模板:v0.4.2
react-native-camera-roll
本项目基于 react-native-camera-roll 开发。
该第三方库的仓库已迁移至 Gitcode,且支持直接从 npm 下载,新的包名为:@react-native-ohos/camera-roll,版本所属关系如下:
| 三方库名称 | 三方库版本(npm地址) | 发布信息 | 支持RN版本 | Autolink | 编译API版本 | 社区基线版本 | 源码地址 |
|---|---|---|---|---|---|---|---|
| @react-native-ohos/camera-roll | ~ 7.11.0 | Gitcode Releases | 0.82.* / 0.84.* / 0.86.* | 是 | API12+ | 7.10.2 | master |
| @react-native-ohos/camera-roll | ~ 7.10.1 | Gitcode Releases | 0.77.* | 否 | API12+ | 7.10.0 | br_rnoh0.77 |
| @react-native-ohos/camera-roll | ~ 7.8.4 | Gitcode Releases | 0.72.* | 是 | API12+ | 7.8.3 | br_rnoh0.72 |
| @react-native-oh-tpl/camera-roll | <= 7.8.3-0.1.5@deprecated | Github Releases(deprecated) | 0.72.* | 否 | API12+ | 7.8.3 | sig |
简介
Camera Roll 组件用于 React Native。
提供相册图片/视频的保存、查找与删除功能,支持获取相册列表、图片缩略图以及相册权限管理等能力。
下载安装
进入到工程目录并输入以下命令:
npm
npm install @react-native-ohos/camera-roll
yarn
yarn add @react-native-ohos/camera-roll
Link
| 是否支持 Autolink | RN 框架版本 | |
|---|---|---|
| ~ 7.11.0 | 是 | 0.82/0.84/0.86 |
使用 Autolink 的工程需按照该文档进行配置,Autolink 框架指导文档:https://gitcode.com/CPF-RN/ohos_react_native/blob/master/docs/zh-cn/Autolinking.md
如您使用的版本支持 Autolink,且工程已接入 Autolink,可跳过 ManualLink 配置。
ManualLink:此步骤为手动配置原生依赖项的指导
首先需要使用 DevEco Studio 打开项目中的 HarmonyOS 工程 harmony。
1. Overrides RN SDK
为了确保工程依赖同一版本的 RN SDK,需要在工程根目录的 harmony/oh-package.json5 中添加 overrides 字段,指向工程所需使用的 RN SDK 版本。替换的版本可以是具体的版本号,也可以是模糊版本号,还可以是本地已有的 HAR 包或源码目录。
关于该字段的作用,请阅读官方说明
{
"overrides": {
"@rnoh/react-native-openharmony": "~0.82.18"
// "@rnoh/react-native-openharmony" : "./react_native_openharmony.har" // 指向本地 har 包的路径
// "@rnoh/react-native-openharmony" : "./react_native_openharmony" // 指向源码路径
}
}
2. 引入原生端代码
目前有两种方法:
- 通过 har 包引入;
- 直接链接源码。
方法一:通过 har 包引入(推荐)
har 包位于三方库安装路径的 `harmony` 文件夹下。
打开 entry/oh-package.json5,添加以下依赖:
"dependencies": {
"@react-native-ohos/camera-roll": "file:../../node_modules/@react-native-ohos/camera-roll/harmony/camera_roll.har"
}
点击右上角的 sync 按钮
或者在终端执行:
cd entry
ohpm install
方法二:直接链接源码
如需使用直接链接源码,请参考[直接链接源码说明](https://gitcode.com/CPF-RN/usage-docs/blob/master/zh-cn/link-source-code.md)
3. 配置 CMakeLists 和引入 CameraRollPackage
仅0.77需要配置 CMakeLists 和引入 CameraRollPackage。
打开 entry/src/main/cpp/CMakeLists.txt,添加:
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules/@rnoh/react-native-openharmony/src/main/cpp")
set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use
add_compile_definitions(WITH_HITRACE_SYSTRACE)
# (VM) Define a variable and assign it to the current module's cpp directory
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
# Add the Header File directory, including cpp, cpp/include, and tell cmake to find the Header Files introduced by the code here
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
add_subdirectory("${RNOH_CPP_DIR}" ./rn)
# RNOH_BEGIN: manual_package_linking_1
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/camera-roll/src/main/cpp" ./camera-roll)
# RNOH_END: manual_package_linking_1
file(GLOB GENERATED_CPP_FILES "${CMAKE_CURRENT_SOURCE_DIR}/generated/*.cpp") # this line is needed by codegen v1
add_library(rnoh_app SHARED
${GENERATED_CPP_FILES}
"./PackageProvider.cpp"
"${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)
# RNOH_BEGIN: manual_package_linking_2
+ target_link_libraries(rnoh_app PUBLIC rnoh_camera_roll)
# RNOH_END: manual_package_linking_2
打开 entry/src/main/cpp/PackageProvider.cpp,添加:
#include "RNOH/PackageProvider.h"
+ #include "CameraRollPackage.h"
using namespace rnoh;
std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx)
{
return {
+ std::make_shared<CameraRollPackage>(ctx)
};
}
打开 entry/src/main/ets/RNPackagesFactory.ets,添加:
import type {RNPackageContext, RNPackage} from '@rnoh/react-native-openharmony/ts';
+ import { CameraRollPackage } from '@react-native-ohos/camera-roll/ts';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [
+ new CameraRollPackage(ctx),
];
}
运行
点击右上角的 sync 按钮
或者在终端执行:
cd entry
ohpm install
然后编译、运行即可。
约束与限制
兼容性
要使用此库,需要使用正确的 React-Native 和 RNOH 版本。另外,还需要使用配套的 DevEco Studio 和 手机 ROM。
本文档内容基于以下版本验证通过:
- RNOH:0.82.1;SDK:HarmonyOS 6.0.1 Release SDK;IDE:DevEco Studio 6.0.1 Release;ROM:6.0.0.120 SP7;
- RNOH:0.84.1;SDK:HarmonyOS 6.0.1 Release SDK;IDE:DevEco Studio 6.0.1 Release;ROM:6.0.0.120 SP7;
- RNOH:0.86.1;SDK:HarmonyOS 26.0.0 Release SDK;IDE:DevEco Studio 26.0.0 Release;ROM:7.0.0.100 SP9;
权限要求
-
getPhotos、getAlbums、deletePhotos 等接口需要使用
ohos.permission.READ_IMAGEVIDEO和ohos.permission.WRITE_IMAGEVIDEO权限,需应用方自行申请后,才可以正常使用。HarmonyOS 受限权限官方说明:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/restricted-permissions-V5#section397164718158
-
保存网络图片/视频(saveAsset 传入网络 url)时,需要在
entry/src/main/module.json5中添加网络权限:requestPermissions: [ { name: "ohos.permission.INTERNET", }, ],
编译运行API要求
当前三方库所有版本均已实现版本隔离,支持在 `API12+` 工程编译,及 `API12+` ROM运行。
[!TIP] 以下功能依赖特定版本的API,使用 低于指定API版本的工程编译 或 低于指定API版本的ROM运行 均可能导致部分功能受限。
- RNOH:0.72/7.8.5、0.77/7.10.2、0.82/7.11.0 版本开始使用 showSingleAssetCreationDialogEx预览图片,解决先前使用showAssetsCreationDialog 显示图片不全的问题。
此API需要在支持
API12+的工程编译,并在支持API23+的ROM上运行,方可生效。
使用示例
下面的代码展示了这个库的基本使用场景:
使用时 import 的库名不变。
import { View, Button } from "react-native";
import {
CameraRoll
} from "@react-native-camera-roll/camera-roll";
export default function App() {
return (
<View>
<Button
title="savePhotos"
onPress={() => {
CameraRoll.saveAsset("https://res.vmallres.com/uomcdn/CN/cms/202408/5442d69d916d4bcf9ee740d595a164fb.jpg").then((res) => {
console.log('res-----',res);
});
}}
/>
</View>
);
}
接口说明
"平台"列表示该属性在原三方库上支持的平台。
"OpenHarmony平台支持"列为 "是" 表示 OpenHarmony 平台支持该属性;"否" 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。
API
CameraRoll 静态方法
| 名称 | 类型 | 参数类型 | 返回值 | 必填 | 平台 | OpenHarmony平台支持 | 描述 |
|---|---|---|---|---|---|---|---|
| save | function | tag: string, options?: SaveToCameraRollOptions | Promise<string> | 否 | iOS/Android | partially | 保存图片/视频,返回新保存资源的 URI。由于原库版本升级,该方法已弃用,可用saveAsset接口代替。 图片支持格式:png/jpg/jpeg/heif/bmp/gif/webp/svg/heic 视频支持格式:mp4/mov |
| saveAsset | function | tag: string, options?: SaveToCameraRollOptions | Promise<PhotoIdentifier> | 否 | iOS/Android | partially | 保存图片/视频,返回新创建的资源信息。 图片支持格式:png/jpg/jpeg/heif/bmp/gif/webp/svg/heic 视频支持格式:mp4/mov 其中fileSize仅api22以上支持 |
| saveToCameraRoll | function | tag: string, type?: 'photo' | 'video' | 'auto' | Promise<PhotoIdentifier> | 否 | iOS/Android | partially | 保存图片/视频。由于原库版本升级,该方法已弃用,调用会弹出警告,可用saveAsset接口代替。 图片支持格式:png/jpg/jpeg/heif/bmp/gif/webp/svg/heic 视频支持格式:mp4/mov |
| getPhotos | function | params: GetPhotosParams | Promise<PhotoIdentifiersPage> | 否 | iOS/Android | 否 | 查找图片/视频。由于 HarmonyOS 安全策略要求,该接口需要使用 ohos.permission.READ_IMAGEVIDEO 和 ohos.permission.WRITE_IMAGEVIDEO 权限,需应用方自行申请后,才可以正常使用 |
| getParamsWithDefaults | function | params: GetPhotosParams | GetPhotosParams | 否 | iOS/Android | 否 | 为getPhotos的参数填充默认值并返回:assetType未设置时默认为'All';非Android平台下groupTypes未设置时默认为'All'。该方法服务于getPhotos,随getPhotos在HarmonyOS上受权限策略限制 |
| getAlbums | function | params?: GetAlbumsParams | Promise<Album[]> | 否 | iOS/Android | 否 | 查找相册。由于 HarmonyOS 安全策略要求,该接口需要使用 ohos.permission.READ_IMAGEVIDEO 和 ohos.permission.WRITE_IMAGEVIDEO 权限,需应用方自行申请后,才可以正常使用 |
| deletePhotos | function | photoUris: Array<string> | Promise<void> | 否 | iOS/Android | 否 | 删除图片/视频。由于 HarmonyOS 安全策略要求,该接口需要使用 ohos.permission.READ_IMAGEVIDEO 和 ohos.permission.WRITE_IMAGEVIDEO 权限,需应用方自行申请后,才可以正常使用 |
| iosGetImageDataById | function | internalID: string, options?: PhotoConvertionOptions | Promise<PhotoIdentifier> | 否 | iOS | 否 | 获取图片数据。由于 HarmonyOS 安全策略要求,该接口需要使用 ohos.permission.READ_IMAGEVIDEO 和 ohos.permission.WRITE_IMAGEVIDEO 权限,需应用方自行申请后,才可以正常使用 |
| getPhotoThumbnail | function | internalID: string, options: PhotoThumbnailOptions | Promise<PhotoThumbnail> | 否 | iOS | 否 | 获取缩略图。由于 HarmonyOS 安全策略要求,该接口需要使用 ohos.permission.READ_IMAGEVIDEO 和 ohos.permission.WRITE_IMAGEVIDEO 权限,需应用方自行申请后,才可以正常使用 |
权限相关方法
| 名称 | 类型 | 参数类型 | 返回值 | 必填 | 平台 | OpenHarmony平台支持 | 描述 |
|---|---|---|---|---|---|---|---|
iosReadGalleryPermission |
function | accessLevel: AccessLevel | Promise<CameraRollAuthorizationStatus> | 否 | iOS | 否 | 权限验证 |
iosRequestReadWriteGalleryPermission |
function | / | Promise<CameraRollAuthorizationStatus> | 否 | iOS | 否 | 读写权限申请 |
iosRequestAddOnlyGalleryPermission |
function | / | Promise<CameraRollAuthorizationStatus> | 否 | iOS | 否 | 添加权限申请 |
iosRefreshGallerySelection |
function | / | Promise<boolean> | 否 | iOS | 否 | 图片列表刷新 |
harmonyReadGalleryPermission |
function | accessLevel: AccessLevel | Promise<CameraRollAuthorizationStatus> | 否 | harmony | 否 | 权限验证。由于 HarmonyOS 安全策略要求,该接口需要使用 ohos.permission.READ_IMAGEVIDEO 和 ohos.permission.WRITE_IMAGEVIDEO 权限,需应用方自行申请后,才可以正常使用 |
harmonyRequestReadWriteGalleryPermission |
function | / | Promise<CameraRollAuthorizationStatus> | 否 | harmony | 否 | 读写权限申请。由于 HarmonyOS 安全策略要求,该接口需要使用 ohos.permission.READ_IMAGEVIDEO 和 ohos.permission.WRITE_IMAGEVIDEO 权限,需应用方自行申请后,才可以正常使用 |
harmonyRequestAddOnlyGalleryPermission |
function | / | Promise<CameraRollAuthorizationStatus> | 否 | harmony | 否 | 添加权限申请。由于 HarmonyOS 安全策略要求,该接口需要使用 ohos.permission.READ_IMAGEVIDEO 和 ohos.permission.WRITE_IMAGEVIDEO 权限,需应用方自行申请后,才可以正常使用 |
harmonyRefreshGallerySelection |
function | / | Promise<boolean> | 否 | harmony | 否 | 图片列表刷新 |
类型
type GroupTypes =
| 'Album'
| 'All'
| 'Event'
| 'Faces'
| 'Library'
| 'SmartAlbum'
| 'PhotoStream'
| 'SavedPhotos';
type SubTypes =
| 'PhotoPanorama'
| 'PhotoHDR'
| 'PhotoScreenshot'
| 'PhotoLive'
| 'PhotoDepthEffect'
| 'VideoStreamed'
| 'VideoHighFrameRate'
| 'VideoTimelapse';
type SourceType = 'UserLibrary' | 'CloudShared';
type Include =
| 'filename'
| 'fileSize'
| 'fileExtension'
| 'location'
| 'imageSize'
| 'playableDuration'
| 'orientation'
| 'albums'
| 'sourceType';
type AssetType = 'All' | 'Videos' | 'Photos';
type AlbumType = 'All' | 'Album' | 'SmartAlbum';
type GetPhotosParams = {
first: number; // 获取的照片数量,按时间倒序(最新在前)
after?: string; // 分页游标,取上一页返回的 page_info.end_cursor
groupTypes?: GroupTypes;
groupName?: string; // 按相册名称过滤
includeSharedAlbums?: boolean; // 包含 iCloud 共享相册资源,仅 iOS
assetType?: AssetType;
fromTime?: number; // 起始时间戳(毫秒),不含
toTime?: number; // 结束时间戳(毫秒),含
mimeTypes?: Array<string>; // 按 mimetype 过滤,如 image/jpeg
include?: Include[]; // 额外包含的输出字段
};
type PhotoIdentifier = {
node: {
id: string;
type: string;
subTypes: SubTypes;
sourceType: SourceType;
group_name: string[];
image: {
filename: string | null;
filepath: string | null;
extension: string | null;
uri: string;
height: number;
width: number;
fileSize: number | null; // size仅api22以上支持
playableDuration: number;
orientation: number | null;
};
timestamp: number;
modificationTimestamp: number;
location: {
latitude?: number;
longitude?: number;
altitude?: number;
heading?: number;
speed?: number;
} | null;
};
};
type PhotoConvertionOptions = {
convertHeicImages?: boolean;
quality?: number;
};
type PhotoIdentifiersPage = {
edges: Array<PhotoIdentifier>;
page_info: {
has_next_page: boolean;
start_cursor?: string;
end_cursor?: string;
};
limited?: boolean;
};
type SaveToCameraRollOptions = {
type?: 'photo' | 'video' | 'auto';
album?: string;
};
type GetAlbumsParams = {
assetType?: AssetType;
albumType?: AlbumType;
};
type AlbumSubType =
| 'AlbumRegular'
| 'AlbumSyncedEvent'
| 'AlbumSyncedFaces'
| 'AlbumSyncedAlbum'
| 'AlbumImported'
| 'AlbumMyPhotoStream'
| 'AlbumCloudShared'
| 'Unknown';
type Album = {
id: string;
title: string;
count: number;
type: AlbumType;
subtype?: AlbumSubType;
};
type ThumbnailSize = {
height: number;
width: number;
};
type PhotoThumbnailOptions = {
allowNetworkAccess: boolean; // 仅 iOS
targetSize: ThumbnailSize;
quality: number;
};
type PhotoThumbnail = {
thumbnailBase64: string;
};
type AccessLevel = 'addOnly' | 'readWrite';
type CameraRollAuthorizationStatus =
| 'granted'
| 'limited'
| 'denied'
| 'unavailable'
| 'blocked'
| 'not-determined';
遗留问题
其他
- cameraRoll 预览图片时调用 showAssetsCreationDialog,该接口在图片宽高比过大时会显示不全。该问题已修复,修复版本 API23 及以上,采用 showSingleAssetCreationDialogEx 预览图片。issue19 API
目录结构
/rntpc_react-native-cameraroll # 项目根目录
├── harmony # 鸿蒙适配代码
│ └─ camera_roll.har # har包
│ └─ camera_roll # 鸿蒙适配核心代码
│ └─ index.ets # 鸿蒙适配代码入口
│ └─ ts.ets # TS侧入口文件
│ └─ src/main/cpp # C++代码
│ └─ CMakeLists.txt # CMake构建配置
│ └─ CameraRollPackage.h # C++侧Package注册入口
│ └─ RNCCameraRoll.cpp/.h # 相册模块C++实现
│ └─ RNCCameraRollPermission.cpp/.h # 权限模块C++实现
│ └─ generated # codegen生成的C++代码
│ └─ src/main/ets # ArkTs代码
│ └─ CameraRollPackage.ets # TurboModule包注册入口
│ └─ CameraRollParamTypes.ts # 相册接口参数类型定义
│ └─ CameraRollTurboModule.ts # 相册操作TurboModule实现
│ └─ CameraRollPermissionTurboModule.ts # 权限TurboModule实现
│ └─ Logger.ts # 日志工具
│ └─ generated # codegen生成的代码
├── src # RN代码
│ └─ index.ts # 入口文件
│ └─ CameraRoll.ts # 相册操作
│ └─ CameraRollIOSPermission.ts # iOS权限
│ └─ NativeCameraRollModule.ts # 原生模块类型
│ └─ NativeCameraRollPermissionModule.ts # 原生权限模块类型
│ └─ useCameraRoll.ts # Hook
├── example # 示例工程
│ └─ harmony # 鸿蒙示例工程
│ └─ src # 示例页面代码
├── lib # 构建产物
├── README.md # 中文安装使用方法
└── README_en.md # 英文安装使用方法
贡献代码
使用过程中发现任何问题都可以提交 Issue,当然,也非常欢迎提交 PR。
开源协议
本项目基于 The MIT License (MIT),请自由地享受和参与开源。