npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hxa-rn/react-native-document-scanner

v0.0.1-beta

Published

Scan documents, automatic border detection, automatic crop

Readme

@hxa-rn/react-native-document-scanner

本项目基于 react-native-document-scanner 开发。如果在使用过程中有任何问题,欢迎在 GitCode 提交 Issue,会及时跟进。

项目介绍

@hxa-rn/react-native-document-scanner 是 react-native-document-scanner(上游版本 1.4.2)的鸿蒙(OpenHarmony / HarmonyOS,RNOH)适配包,当前版本 0.0.1-beta。

上游是一个文档扫描库:拍摄纸质文档、自动识别边框并做透视裁剪,把裁剪后的图片以文件路径或 Base64 字符串的形式回传给业务方,并在取景过程中回报每次边框检测的结果。

鸿蒙适配版提供两种扫描引擎,二者都在全屏扫描会话中运行:

  • Vision Kit 引擎(缺省):基于系统文档扫描控件(@hms.ai.DocumentScanner),控件内完成取景、自动拍摄、裁剪、滤镜、编辑与保存;
  • 自建取景引擎:基于 Camera Kit 相机会话与 ArkUI XComponent 预览,实现上游的实时边框检测(onRectangleDetect)、检测框遮罩(overlayColor)、手电筒(enableTorch)、前后摄切换(useFrontCam)、自动拍摄阈值与检测间隔,并回传真实的裁剪前原图与四角坐标。

两种引擎都支持:单张与连续拍摄、文件路径或 Base64 回传、逐张触发 onPictureTaken、quality / brightness / saturation / contrast 对结果图生效、结构化错误码。

⚠️ 交互模型与上游不同(重要):上游是内嵌在 RN 视图树里的实时相机取景组件;鸿蒙侧两种引擎的取景都在独立的全屏会话中进行,不内嵌在 RN 页面内。<DocumentScanner> 在页面上渲染一个触发面,点击它或调用 ref.startScan() 拉起全屏扫描会话,扫描结束后回到原页面。

| 鸿蒙适配包版本 | 上游版本 | React Native / RNOH | 编译 SDK | 接入方式 | | --- | --- | --- | --- | --- | | 0.0.1-beta | 1.4.2 | RN >=0.72(基于 0.72.5 + @react-native-oh/react-native-harmony 0.72.143) | compatibleSdkVersion 5.1.0(18),targetSdkVersion 6.1.1(24) | Autolink(RNOH hvigor 插件)或 Manual Link,两条路线均在示例宿主副本上仅经 tgz 安装本包编译验证 |

包内鸿蒙模块的 ohpm 名为 @oh-rn/react-native-document-scanner(源码 HAR harmony/document_scanner.har,同源源码目录 harmony/document_scanner),与 npm 包名不同;下文接入步骤里两个名字请照抄,不要互换。

集成指南

1. 安装

npm install @hxa-rn/[email protected]

宿主为 RN 0.72 工程时如遇 peer 冲突,可加 --legacy-peer-deps。peerDependencies:react-native >= 0.72,react *。

2. JS 侧导入

包内已声明 harmony.alias 为 react-native-document-scanner。宿主 Metro 配置使用 RNOH 的 createHarmonyMetroConfig(RNOH 工程模板默认如此)时,打包会把上游包名重定向到本包,业务代码仍从上游包名导入:

import DocumentScanner, { RNPdfScannerManager } from 'react-native-document-scanner';

不要写成 from '@hxa-rn/react-native-document-scanner'。

3. 鸿蒙原生接入

包内 harmony/document_scanner.har 是源码 HAR(含 ETS 源码、C++ 源码与 codegen 产物,ohpm 名 @oh-rn/react-native-document-scanner),与同队其他 @hxa-rn/* 适配包形态一致。接入分两条路线,二选一,不要同时做(否则 CMake 会报同一 binary dir 被用两次)。以下片段与本仓 example_auto 示例宿主的接线代码逐字相同(示例以仓内源码路径依赖本模块,这里改为 npm 安装位置)。

① 工程根 oh-package.json5:为 RNOH 框架配置 overrides(按宿主既有的 RNOH 接入方式填写;示例工程使用 npm 包内的源码版 HAR):

{
  "overrides": {
    "@rnoh/react-native-openharmony": "file:../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har"
  }
}

本模块自身对 @rnoh/react-native-openharmony 的依赖写的是相对路径 file:../react_native_openharmony_release.har,必须依靠上面这条 overrides 指到宿主的 RNOH,否则 ohpm install 会报找不到该 HAR。

② entry/oh-package.json5:依赖包内的 HAR:

"dependencies": {
  "@oh-rn/react-native-document-scanner": "file:../../node_modules/@hxa-rn/react-native-document-scanner/harmony/document_scanner.har"
}

在 harmony 工程目录执行 ohpm install --all(或在 DevEco Studio 中 Sync)。ohpm 会把 HAR 解包成工程内 oh_modules/@oh-rn/react-native-document-scanner/ 目录(含 src/main/cpp),后续 CMake 与 ETS 导入都从这里解析。

路线 A:Autolink(宿主 hvigorfile.ts 使用 RNOH 的 createRNOHModulePlugin 且开启 autolinking)

package.json 已声明 harmony.autolinking(cmakeLibraryTargetName document_scanner、ohPackageName @oh-rn/react-native-document-scanner、etsPackageClassName / cppPackageClassName DocumentScannerPackage)。构建时插件会自动:把 ② 的依赖写入工程根 oh-package.json5、生成 entry/src/main/cpp/autolinking.cmake 与 RNOHPackagesFactory.h / RNOHPackagesFactory.ets 并注册 DocumentScannerPackage。宿主只需保证 CMakeLists.txt 里有 include("${CMAKE_CURRENT_SOURCE_DIR}/autolinking.cmake") 与 autolink_libraries(rnoh_app)、PackageProvider.cpp / RNPackagesFactory.ets 里合并了 createRNOHPackages(ctx)(RNOH 工程模板默认如此),不要再手动注册。

路线 B:Manual Link(宿主未启用 autolinking,或在 hvigorfile.ts 的 autolinking.excludeNpmPackages 中写入了 '@hxa-rn/react-native-document-scanner')

排除项按 npm 包名匹配,写成 ohpm 名 @oh-rn/… 不会生效。

③ entry/src/main/cpp/CMakeLists.txt:

# RNOH 模板工程已定义 OH_MODULE_DIR;未定义时先加:
# set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
add_subdirectory("${OH_MODULE_DIR}/@oh-rn/react-native-document-scanner/src/main/cpp" ./document_scanner)

target_link_libraries(rnoh_app PUBLIC document_scanner)

④ entry/src/main/cpp/PackageProvider.cpp:

#include "RNOH/PackageProvider.h"
#include "DocumentScannerPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<DocumentScannerPackage>(ctx),
    };
}

⑤ entry/src/main/ets/RNPackagesFactory.ets:

import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
import DocumentScannerPackage from '@oh-rn/react-native-document-scanner';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new DocumentScannerPackage(ctx),
  ];
}

包内同时附带源码目录 harmony/document_scanner/(与 HAR 同源),供查阅或自行 assembleHar;不要把它以 file: 源码目录方式直接作为 ohpm 依赖——ohpm 会以 junction 链接到工程外,hvigor 的 CompileArkTS 会报 EINVAL: invalid argument, mkdir '…\C:'。

4. 宿主工程还需接线三处

鸿蒙的 HAR 模块不能自行声明 Ability、页面与权限。两种引擎各需要一个承载 Ability 与一个承载页,以下三处必须由宿主应用完成;缺任一项,对应引擎的 startScan() 会以错误码 reject。所需文件已随包附在 host-template/(与示例宿主逐字一致),复制即可。

1. 声明相机权限(entry/src/main/module.json5),usedScene.abilities 必须同时列出两个承载 Ability:

"requestPermissions": [
  {
    "name": "ohos.permission.CAMERA",
    "reason": "$string:camera_reason",
    "usedScene": { "abilities": ["DocumentScannerAbility", "SelfBuiltScannerAbility"], "when": "inuse" }
  }
]

$string:camera_reason 需在宿主 resources/base/element/string.json 中定义。

2. 声明两个承载 Ability(entry/src/main/module.json5 的 abilities):

{
  "name": "DocumentScannerAbility",
  "srcEntry": "./ets/documentscannerability/DocumentScannerAbility.ets",
  "description": "$string:EntryAbility_desc",
  "icon": "$media:layered_image",
  "label": "$string:EntryAbility_label",
  "startWindowIcon": "$media:startIcon",
  "startWindowBackground": "$color:start_window_background",
  "launchType": "singleton",
  "exported": false
},
{
  "name": "SelfBuiltScannerAbility",
  "srcEntry": "./ets/documentscannerability/SelfBuiltScannerAbility.ets",
  "description": "$string:EntryAbility_desc",
  "icon": "$media:layered_image",
  "label": "$string:EntryAbility_label",
  "startWindowIcon": "$media:startIcon",
  "startWindowBackground": "$color:start_window_background",
  "launchType": "singleton",
  "exported": false
}

description / icon / label / startWindowIcon / startWindowBackground 五项照抄宿主自己 EntryAbility 的取值即可。

两个 srcEntry 都是继承本库基类的空子类,直接复制包内 host-template/DocumentScannerAbility.ets 与 host-template/SelfBuiltScannerAbility.ets 到 entry/src/main/ets/documentscannerability/:

import { DocumentScannerAbility as BaseDocumentScannerAbility } from '@oh-rn/react-native-document-scanner';
export default class DocumentScannerAbility extends BaseDocumentScannerAbility {}
import { SelfBuiltScannerAbility as BaseSelfBuiltScannerAbility } from '@oh-rn/react-native-document-scanner';
export default class SelfBuiltScannerAbility extends BaseSelfBuiltScannerAbility {}

3. 提供两个承载页并注册进 main_pages.json:pages/DocumentScannerPage(挂载 Vision Kit 控件)与 pages/SelfBuiltScannerPage(相机预览、检测遮罩与控制条),两者都用本库导出的函数完成配置折算、结果回传与错误回传。复制包内 host-template/DocumentScannerPage.ets 与 host-template/SelfBuiltScannerPage.ets 到 entry/src/main/ets/pages/,并在 entry/src/main/resources/base/profile/main_pages.json 中加入:

{
  "src": [
    "pages/Index",
    "pages/DocumentScannerPage",
    "pages/SelfBuiltScannerPage"
  ]
}

只打算使用 Vision Kit 引擎时也请完成自建取景引擎的接线:调用方一旦传入 onRectangleDetect、enableTorch 等属性就会自动切换到自建取景引擎。

使用说明

基础用法

import React from 'react';
import { View, Image } from 'react-native';
import DocumentScanner from 'react-native-document-scanner';

export default function Demo() {
  const scannerRef = React.useRef(null);
  const [image, setImage] = React.useState(null);

  return (
    <View>
      <DocumentScanner
        ref={scannerRef}
        captureMultiple={false}
        useBase64={false}
        quality={0.8}
        onPictureTaken={(data) => setImage(data.croppedImage)}
      />
      {image ? <Image source={{ uri: image }} style={{ width: 200, height: 200 }} /> : null}
    </View>
  );
}

以上写法不涉及取景微调属性,使用 Vision Kit 引擎。需要实时检测回调或取景微调时,直接写出对应属性即可切换到自建取景引擎:

<DocumentScanner
  ref={scannerRef}
  overlayColor="rgba(255,130,0,0.7)"
  enableTorch={false}
  detectionCountBeforeCapture={5}
  detectionRefreshRateInMS={50}
  onRectangleDetect={({ stableCounter, lastDetectionType }) => console.log(stableCounter, lastDetectionType)}
  onPictureTaken={(data) => console.log(data.croppedImage, data.rectangleCoordinates)}
/>
  • scanEngine 未传(或为 'auto')时:写出 overlayColor、enableTorch、useFrontCam、detectionCountBeforeCapture、detectionRefreshRateInMS、onRectangleDetect 中任意一项(即使值为 false 或 undefined)即使用自建取景引擎,一项都不写则使用 Vision Kit 引擎;
  • 也可显式指定 scanEngine="visionkit" 或 scanEngine="selfbuilt";
  • onRectangleDetect 的参数直接就是 { stableCounter, lastDetectionType },写法与上游一致。

命令式拉起扫描

// 拉起全屏扫描会话;会话结束(保存、取消或失败)时返回
const result = await scannerRef.current.startScan();
// result = { cancelled: boolean, code: number, pictures: Picture[] }

capture() 按调用时的会话状态执行:

| 调用时机 | ref.capture() / RNPdfScannerManager.capture() 的行为 | |---|---| | 没有进行中的扫描会话 | ref.capture() 等同于 startScan()(使用组件当前属性);RNPdfScannerManager.capture() 以默认配置(单张、文件路径、Vision Kit 引擎)拉起会话,结果只在返回值中,不触发组件的 onPictureTaken | | 自建取景会话进行中 | 立即拍一张,返回 { cancelled: false, code: 200, pictures: [该张] };正在拍摄或会话已关闭时返回 { cancelled: true, code: -1, pictures: [] }。该张同时计入本次会话结果 | | Vision Kit 会话进行中 | 以 document_scanner_busy reject(系统控件不支持从外部触发拍摄) |

扫描会话期间 RN 页面处于后台,JS 定时器暂停,事件回调照常到达。因此会话中的 capture() 请在 onRectangleDetect 等事件回调中调用,或直接点击自建取景界面上的「拍摄」按钮:

<DocumentScanner
  ref={scannerRef}
  scanEngine="selfbuilt"
  onRectangleDetect={({ stableCounter }) => {
    if (stableCounter === 2) {
      scannerRef.current.capture().then((shot) => console.log(shot.pictures.length));
    }
  }}
/>

上游的 NativeModules.RNPdfScannerManager.capture() 在鸿蒙侧改为具名导出:

import { RNPdfScannerManager } from 'react-native-document-scanner';

const result = await RNPdfScannerManager.capture();

连续拍摄与 Base64

<DocumentScanner
  captureMultiple          // 一次会话可连续拍摄多张
  maxShotCount={5}         // 单次会话最多 5 张(缺省 9)
  useBase64                // 结果以 Base64 字符串返回,而非文件路径
  onPictureTaken={(data) => console.log(data.croppedImage.length)}
/>

onPictureTaken 在扫描会话结束时按顺序逐张触发。

错误处理

try {
  await scannerRef.current.startScan();
} catch (e) {
  // e.code 为结构化错误码,e.message 为可读描述
  console.warn(e.code, e.message);
}

接口文档

组件属性

| 属性 | 类型 | 默认值 | 说明 | 鸿蒙支持 | |---|---|---|---|---| | captureMultiple | boolean | false | 是否连续拍摄 | ✅ 两种引擎均生效。严格布尔判定:仅 true 视为开启,字符串 'true'、数字 1 等按 false 处理 | | maxShotCount | number | 9 | captureMultiple 为 true 时单次会话最多拍摄的张数(鸿蒙新增) | ✅ 两种引擎均生效。正整数向下取整,非法值按 9 处理 | | useBase64 | boolean | false | 结果以 Base64 字符串返回,而非文件路径 | ✅ 两种引擎均生效 | | scanButtonText | string | '点击扫描文档' | 触发面按钮文案(鸿蒙新增) | ✅ 生效 | | scanEngine | 'visionkit' \| 'selfbuilt' \| 'auto' | 'auto' | 选择扫描引擎(鸿蒙新增),'auto' 规则见「使用说明」 | ✅ 生效。非法值按 'auto' 处理 | | manualOnly | boolean | false | 关闭自动拍摄,只允许手动拍(按上游 1.4.3 语义提供) | ✅ 两种引擎均生效:Vision Kit 切手动拍摄模式;自建取景不再按 detectionCountBeforeCapture 自动拍 | | onPictureTaken | (data) => void | 空函数 | 每张图片触发一次,载荷见下表 | ✅ 两种引擎均生效,在会话结束时逐张触发 | | onRectangleDetect | ({ stableCounter, lastDetectionType }) => void | — | 每次检测到文档边框时触发 | ✅ 自建取景引擎生效;Vision Kit 引擎下不触发 | | overlayColor | string \| number | 不绘制 | 检测框遮罩颜色,支持 #RRGGBBAA、rgba() 等;数值按 0xAARRGGBB 解析 | ✅ 自建取景引擎生效;Vision Kit 引擎下不生效 | | enableTorch | boolean | false | 手电筒 | ✅ 自建取景引擎生效(设备不支持时不动作);Vision Kit 引擎下不生效 | | useFrontCam | boolean | false | 使用前置摄像头 | ✅ 自建取景引擎生效(启动时设备没有所需摄像头会以 document_scanner_no_camera reject;在取景界面切换时没有对应摄像头则保持当前摄像头);Vision Kit 引擎下不生效 | | detectionCountBeforeCapture | number | 5 | 连续检出的合格边框数超过该值时自动拍摄(缺省第 6 次) | ✅ 自建取景引擎生效;Vision Kit 引擎下不生效 | | detectionRefreshRateInMS | number | 50 | 两次边框检测的间隔,实际间隔为该值 × 10 毫秒(缺省约 0.5 秒,与上游一致) | ✅ 自建取景引擎生效;Vision Kit 引擎下不生效 | | brightness | number | 0 | 结果图亮度 | ✅ 两种引擎均对结果图调色;自建取景引擎只作用于裁剪成功的 croppedImage | | saturation | number | 1 | 结果图饱和度(传 0 与上游一样按 1 处理) | ✅ 同 brightness | | contrast | number | 1 | 结果图对比度 | ✅ 同 brightness | | quality | number | 0.8 | JPEG 压缩质量,取值钳制到 0.1~1 | ✅ 两种引擎均生效:显式传入数值时按该质量重新编码结果图;未传时保留引擎原始图片 |

实例方法

| 方法 | 签名 | 说明 | |---|---|---| | startScan() | () => Promise<ScanResult> | 拉起全屏扫描会话(鸿蒙新增)。会话结束时 resolve;拉起失败时 reject | | capture() | () => Promise<ScanResult> | 对齐上游 capture():无会话时等同于 startScan();自建取景会话中立即拍一张;Vision Kit 会话中 reject document_scanner_busy | | RNPdfScannerManager.capture() | () => Promise<ScanResult> | 具名导出,对应上游 NativeModules.RNPdfScannerManager.capture()。会话中的行为同 capture();无会话时以默认配置拉起会话,不触发组件回调 |

返回值与回调载荷

ScanResult:

| 字段 | 类型 | 说明 | |---|---|---| | cancelled | boolean | 用户取消、未保存任何图片或会话失败时为 true | | code | number | 200 表示成功;取消时为 -1 | | pictures | Picture[] | 逐张结果;cancelled 为 true 时为空数组 |

onPictureTaken 的载荷(即 Picture):

| 字段 | 类型 | 说明 | |---|---|---| | croppedImage | string | 裁剪后的图片:file:// URI 或 Base64 字符串(不含换行),取决于 useBase64 | | initialImage | string | 裁剪前原图。Vision Kit 引擎下与 croppedImage 取值相同;自建取景引擎下为未裁剪的原始拍照图(未能裁剪时与 croppedImage 相同) | | rectangleCoordinates | object \| null | 四角坐标 { topLeft, topRight, bottomLeft, bottomRight },每个角为 { x, y }。Vision Kit 引擎下恒为 null;自建取景引擎裁剪成功时为拍照图像素坐标,未能裁剪时为 null |

onRectangleDetect 的参数:

| 字段 | 类型 | 说明 | |---|---|---| | stableCounter | number | 连续检出合格边框的次数;检出非合格边框时清零,未检出边框时保持不变 | | lastDetectionType | number | 本次检出的边框类型:0 合格、1 角度不佳、2 距离过远 |

错误码

startScan() / capture() / RNPdfScannerManager.capture() reject 时,error.code 为下列之一,error.message 为可读描述:

| 错误码 | 含义 | 常见原因 | |---|---|---| | document_scanner_busy | 已有扫描会话在进行中 | 上一次会话尚未结束时再次 startScan();或在 Vision Kit 会话中调用 capture() | | document_scanner_permission_denied | 相机权限被拒绝 | 用户在系统权限弹窗上选择了「不允许」,或宿主未声明相机权限(见「集成指南」第 4 节第 1 步) | | document_scanner_no_context | 无法拉起扫描会话 | 宿主未声明对应的承载 Ability(见「集成指南」第 4 节第 2 步) | | document_scanner_permission_not_declared | 相机权限申请异常 | 权限申请所用上下文不合法 | | document_scanner_load_content_failed | 扫描页加载失败 | 宿主未提供承载页或未注册进 main_pages.json(见「集成指南」第 4 节第 3 步) | | document_scanner_no_camera | 没有可用的摄像头 | 自建取景引擎下设备无摄像头、要求前置摄像头但设备没有,或摄像头无可用预览规格 | | document_scanner_camera_session_failed | 相机会话启动失败 | 自建取景引擎下系统相机会话装配或启动出错 |

其他底层异常会原样抛出(无 code 字段)。

快速验证(运行 Example)

以下为源码仓的验证流程;npm 包不含示例工程与 scripts/,需先克隆仓库。

前置条件

| 依赖 | 版本要求 | |------|----------| | Node.js | >= 20(示例工程 engines 要求;库本身 >= 18) | | DevEco Studio | 6.1.1(示例验证用 6.1.1.290) | | HarmonyOS SDK | compatibleSdkVersion 5.1.0(18),targetSdkVersion 6.1.1(24) |

运行步骤

1. 克隆仓库(鸿蒙适配代码在 ohos/ 子目录,根目录保留上游 iOS 实现)

git clone -b br_dev https://gitcode.com/hxa-rn/react-native-document-scanner.git
cd react-native-document-scanner/ohos

Windows/DevEco 环境建议将仓库克隆到短路径(如 D:\rn\ds)。RNOH 源码模式编译会生成较深的 native 中间路径,目录过长可能在 ninja 阶段因 .rsp 路径过长失败。

2. 安装库依赖并构建 JS 产物

npm install --legacy-peer-deps      # 触发 prepare:tsc --noEmit && bob build → dist/

3. 进入 example_auto 目录,安装依赖(example 同构)

cd example_auto
npm install --legacy-peer-deps

示例工程以 file:.. 依赖本库源码,Metro 与 tsconfig 已把 react-native-document-scanner 映射到本库。

4. 生成 JS Bundle

npm run dev

产物:harmony/entry/src/main/resources/rawfile/bundle.harmony.js

5. 用 DevEco Studio 打开鸿蒙工程

  • 打开 DevEco Studio,选择 example_auto/harmony 目录,等待 Sync 完成;
  • Sync 完成后,在 example_auto/harmony 目录执行 libevent 2.1.13 补丁脚本(示例工程使用 RNOH 源码依赖模式):
bash ../../scripts/patch-libevent-2113.sh .

6. 编译并运行 HAP

在 DevEco Studio 中点击运行按钮,将 HAP 安装到设备。命令行等价(hvigorw 位于 DevEco Studio 安装目录 tools/hvigor/bin,需加入 PATH):

hvigorw --mode module -p module=entry@default -p product=default -p buildMode=release assembleHap --no-daemon

注意:Example 中已预置插件依赖、Package 注册(Manual Link)、「宿主工程还需接线三处」要求的两个 Ability 子类、两个扫描页面(均已登记进 main_pages.json)以及相机权限声明(usedScene.abilities 已含两者),无需手动配置。

约束与限制

兼容性

| 项 | 值 | |---|---| | 适配的鸿蒙 SDK | compatibleSdkVersion 5.1.0(18)、targetSdkVersion 6.1.1(24),runtimeOS HarmonyOS | | 依赖的系统能力 | Vision Kit 文档扫描控件 @hms.ai.DocumentScanner(@kit.VisionKit,起始版本 5.0.0(12));Camera Kit(@ohos.multimedia.camera);Image Kit、Effect Kit、Core File Kit(结果图处理) | | 上游库版本 | react-native-document-scanner 1.4.2 | | React Native | >=0.72(适配基于 0.72.5 + @react-native-oh/react-native-harmony 0.72.143) | | 支持设备类型 | default(手机)、tablet(平板)、2in1;Vision Kit 文档扫描控件官方仅支持手机、平板 |

验证状态

  • 真机黑盒:适配源码此前的构建包已在 API 22 / 23 / 24 / 26 四档真机按 20 条用例完成黑盒验证,四档累计 80/80 通过,Vision Kit 与自建取景两条引擎路径均覆盖(数据出处:库仓 交付件/整体测试报告.md,报告日期 2026-09-16)。
  • API 24 定向复测(2026-09-25)对应基线 f479aa0 的历史构建包:修复手电筒状态回读与输出路径等问题;纸张检测与透视裁剪质量一项因机位缺受控场景记为部分通过。
  • 当前源码(f007b4e,含上述修复)只做过 release 重建与离线核验;该重建包与本 npm 包均未在真机安装运行。
  • 本 npm 包(0.0.1-beta):候选 tgz 在 Windows 构建机(DevEco Studio 6.1.1.290、RNOH 0.72.143 源码依赖模式)上以 example_auto 的副本为宿主、仅通过 tgz 安装本包(无任何指向库仓源码的路径),按本文「集成指南」路线 A(Autolink)与路线 B(Manual Link)各完成一次 release assembleHap 编译验证;宿主目录在多轮尝试间复用(依赖与产物目录每轮重置)。
  • 只在上述环境验证过;不据此声明所有 RNOH 版本或所有 API 版本均兼容。

权限

本库依赖 1 项系统权限:

| 权限 | 类型 | 用途 | |---|---|---| | ohos.permission.CAMERA | user_grant | 两种引擎扫描时的相机取景与拍摄 |

⚠️ 该权限为 user_grant,且 HAR 模块不能自行声明权限:

  • 宿主应用必须在自己的 entry/src/main/module.json5 中声明它,并在 usedScene.abilities 中同时列出 DocumentScannerAbility 与 SelfBuiltScannerAbility(见「集成指南」第 4 节第 1 步);
  • 运行时的动态申请由本库在承载 Ability 内自动完成,宿主无需重复申请;
  • 用户拒绝授权时,startScan() 会以 document_scanner_permission_denied reject。

使用约束

  • 交互模型:两种引擎的扫描界面都是全屏会话,不内嵌在 RN 页面内,需由点击触发面或调用 ref.startScan() / ref.capture() 显式拉起。
  • 会话期间的 JS:会话进行中 RN 页面处于后台,JS 定时器暂停、事件回调照常到达;会话中的 capture() 请在事件回调中调用。
  • 回调时机:onPictureTaken 在会话结束时逐张触发,而非每拍一张立即触发;需要在会话中立即拿到某一张时,使用会话中 capture() 的返回值。
  • Vision Kit 引擎:拍摄模式默认自动、滤镜默认原图(彩色),扫描界面无相册导入与分享入口;不回传裁剪前原图与四角坐标,不触发 onRectangleDetect,取景微调属性不生效,会话中不支持 capture()。
  • 自建取景引擎:边框检测为独立实现,同一场景下检出的边框可能与 iOS 不同;rectangleCoordinates 为拍照图像素坐标,数值不与 iOS 逐位可比;切换前后摄像头后会按 enableTorch 重新设置手电筒;拍照时不会额外触发一次 onRectangleDetect。
  • 连续拍摄:captureMultiple 为 true 时单次会话最多 maxShotCount 张(缺省 9),上游不限张数。
  • 结果图处理:brightness / saturation / contrast / quality 在拍摄完成后作用于结果图,不改变取景预览画面;quality 未传时不重新编码。
  • 文件形态:文件结果为 file:// URI;Base64 结果不含换行。
  • 1.4.3 才引入的上游属性(noGrayScale / documentAnimation / saveInAppDocument / onProcessing / onPermissionsDenied)不在本包 API 面内;manualOnly 按 1.4.3 语义作为本端新增属性提供,缺省 false 时行为与 1.4.2 一致。

开源license

本项目基于 MIT 协议,详见 LICENSE 文件,与上游 react-native-document-scanner 保持一致。

问题反馈渠道

如果在使用过程中遇到任何问题,欢迎通过 GitCode 仓库与 Issue 反馈:

https://gitcode.com/hxa-rn/react-native-document-scanner

https://gitcode.com/hxa-rn/react-native-document-scanner/issues