rntpc_react-native-cameraroll:基于 react-native-cameraroll 的 OpenHarmony 适配版,访问系统相册(保存/读取照片和视频)

基于 react-native-cameraroll 的 OpenHarmony 适配版,访问系统相册(保存/读取照片和视频)

分支4Tags8

文档模板: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
是否支持 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. 引入原生端代码

目前有两种方法:

  1. 通过 har 包引入;
  2. 直接链接源码。

方法一:通过 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。

本文档内容基于以下版本验证通过:

  1. RNOH:0.82.1;SDK:HarmonyOS 6.0.1 Release SDK;IDE:DevEco Studio 6.0.1 Release;ROM:6.0.0.120 SP7;
  2. RNOH:0.84.1;SDK:HarmonyOS 6.0.1 Release SDK;IDE:DevEco Studio 6.0.1 Release;ROM:6.0.0.120 SP7;
  3. RNOH:0.86.1;SDK:HarmonyOS 26.0.0 Release SDK;IDE:DevEco Studio 26.0.0 Release;ROM:7.0.0.100 SP9;

权限要求

编译运行API要求

当前三方库所有版本均已实现版本隔离,支持在 `API12+` 工程编译,及 `API12+` ROM运行。

[!TIP] 以下功能依赖特定版本的API,使用 低于指定API版本的工程编译 或 低于指定API版本的ROM运行 均可能导致部分功能受限。

  1. 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),请自由地享受和参与开源。

项目介绍

基于 react-native-cameraroll 的 OpenHarmony 适配版,访问系统相册(保存/读取照片和视频)

定制我的领域