二维码/条码扫描组件
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 3 个月前 | ||
| 11 天前 | ||
| 11 天前 | ||
| 12 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 21 天前 | ||
| 12 天前 | ||
| 11 天前 | ||
| 11 天前 | ||
| 1 个月前 | ||
| 11 天前 | ||
| 1 个月前 |
本项目基于 react-native-qrcode-scanner 开发。如果在使用过程中有任何问题,可以在 GitCode Issues 提交 Issue,会及时跟进。
项目介绍
react-native-qrcode-scanner 是一个二维码/条码扫描组件,提供取景预览、条码识别与结果派发、
扫码去重与重新武装(reactivate)、震动反馈、读码启停、取景框与顶/底部内容区、闪光灯与相机休眠等能力。
本仓为其 HarmonyOS 适配版本,适配基线 = 上游 1.6.0;npm 包为 @hxa-rn/react-native-qrcode-scanner,当前版本 1.6.0(与上游基线同号)。
架构形态(务必先读):上游自身零原生代码(index.js 348 行 JS 包装组件),
把「取景 + 出码」全权委托给 peer 依赖 react-native-camera。该 peer 已归档停维、无 RNOH 移植、
103 个原生文件的旧架构,照搬即强阻塞。
本适配采用依赖倒置:把相机来源抽象成可注入的 cameraProvider 契约,鸿蒙侧用 HarmonyOS Scan Kit
的 customScan 自建 Fabric 原生组件 QRScanKitCamera(customScan + XComponent + codegen C++ glue +
emitComponentEvent('barCodeRead'))。本库自身的控制逻辑(去重 / 震动 / reactivate)与解码流映射无平台障碍。
集成指南
本节用于接入已有 RN 鸿蒙应用;运行本仓库示例请参见「快速验证(运行 Example)」。
1. 安装适配包
npm 包:@hxa-rn/react-native-qrcode-scanner@1.6.1(正式版,dist-tag latest;预发布版 0.0.1-beta 保留在 dist-tag beta),业务别名为 react-native-qrcode-scanner。在你的 RN 应用根目录执行:
npm install @hxa-rn/react-native-qrcode-scanner@1.6.1 --legacy-peer-deps
peerDependencies:{"react-native":">=0.72","react":"*"}。还需已有可运行的 RNOH 宿主工程(示例基线为 RN 0.72.5 + RNOH 0.72.143)。
包内含源码 HAR harmony/qrcode_scanner.har(ArkTS 源码 + C++ 源码,由宿主工程一起编译),其 ohpm 模块名为 @oh-rn/react-native-qrcode-scanner(与 npm 包名不同,下文 ohpm 依赖、ArkTS/C++ 导入一律用 ohpm 名)。
2. 配置 Metro 并导入
适配包已声明 harmony.alias。宿主 metro.config.js 合并以下配置,并保留原有的自定义设置:
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const {createHarmonyMetroConfig} = require('@react-native-oh/react-native-harmony/metro.config');
module.exports = mergeConfig(
getDefaultConfig(__dirname),
createHarmonyMetroConfig({
reactNativeHarmonyPackageName: '@react-native-oh/react-native-harmony',
}),
);
业务代码(两种写法等价,createHarmonyMetroConfig 会把别名解析到本包):
import QRCodeScanner, {checkCameraPermission, requestCameraPermission} from 'react-native-qrcode-scanner';
// 或
import QRCodeScanner from '@hxa-rn/react-native-qrcode-scanner';
3. 声明 HAR 依赖
在宿主鸿蒙工程根 harmony/oh-package.json5 与 harmony/entry/oh-package.json5 的 dependencies 追加下项(路径相对于各自文件所在目录,按宿主实际 node_modules 位置调整),并在根 overrides 中将 @rnoh/react-native-openharmony 指向宿主正在使用的同一 RNOH HAR(勿混用 debug/release 或不同版本):
// harmony/oh-package.json5
"dependencies": {
"@oh-rn/react-native-qrcode-scanner": "file:../node_modules/@hxa-rn/react-native-qrcode-scanner/harmony/qrcode_scanner.har"
},
"overrides": {
"@rnoh/react-native-openharmony": "file:../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony_release.har"
}
// harmony/entry/oh-package.json5
"dependencies": {
"@oh-rn/react-native-qrcode-scanner": "file:../../node_modules/@hxa-rn/react-native-qrcode-scanner/harmony/qrcode_scanner.har"
}
然后在 harmony 目录执行 ohpm install --all 并同步工程。不要把 file: 指向解包后的源码目录 harmony/qrcode_scanner/(ohpm 会建越界 junction,ArkTS 编译报 EINVAL),只依赖 .har。
4. 注册原生 Package(Autolink 与 Manual 二选一)
路线 A:Autolink(推荐,与本仓示例一致)
本包声明了 Autolinking 元数据:CMake 目标 qrcode_scanner,ohpm 包 @oh-rn/react-native-qrcode-scanner,C++ / ETS 类 QrcodeScannerPackage。宿主 harmony/hvigorfile.ts 的 createRNOHModulePlugin 启用 autolinking: {} 即可;构建时 hvigor 会生成 entry/src/main/ets/RNOHPackagesFactory.ets、entry/src/main/cpp/RNOHPackagesFactory.h 与 autolinking.cmake。宿主 CMakeLists.txt 需 include("${CMAKE_CURRENT_SOURCE_DIR}/autolinking.cmake") 并 autolink_libraries(rnoh_app),PackageProvider.cpp 与 RNPackagesFactory.ets 需合并 createRNOHPackages(ctx) 的返回值(RNOH 模板已含)。此时不要再做下面的手工注册,否则会重复注册(CMake 报 binary directory … is already used)。
路线 B:Manual Link
宿主已启用 Autolinking 时,先把本包排除,避免与手工注册冲突(排除项写 npm 包名):
autolinking: {
excludeNpmPackages: ['@hxa-rn/react-native-qrcode-scanner'],
},
然后补齐以下三处:
harmony/entry/src/main/cpp/CMakeLists.txt:添加子目录,并在已有add_library(rnoh_app ...)之后链接:
set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
add_subdirectory("${OH_MODULE_DIR}/@oh-rn/react-native-qrcode-scanner/src/main/cpp" ./qrcode_scanner)
# 放在 rnoh_app 目标创建之后:
target_link_libraries(rnoh_app PUBLIC qrcode_scanner)
harmony/entry/src/main/cpp/PackageProvider.cpp:添加头文件,并把实例加入getPackages返回集合(RNOH 模板可加入ManualLinkingPackage列表):
#include "QrcodeScannerPackage.h"
// 加入已有 Package 集合:
std::make_shared<rnoh::QrcodeScannerPackage>(ctx)
harmony/entry/src/main/ets/RNPackagesFactory.ets:添加默认导入,并把实例加入createRNPackages返回数组:
import QrcodeScannerPackage from '@oh-rn/react-native-qrcode-scanner';
// 加入 createRNPackages(ctx) 返回数组:
new QrcodeScannerPackage(ctx)
5. 注册 ArkTS 取景组件(两条路线都必须)
取景组件 QRScanKitCamera 由 ArkTS 实现。包内 QrcodeScannerPackage 已登记组件描述符与构建器,但宿主 RNApp 必须声明 arkTsComponentNames,Autolink 不会替你改宿主页面。在宿主承载 RNApp 的页面(示例为 harmony/entry/src/main/ets/pages/Index.ets)按本仓示例写法补齐三处(示例同时在宿主提供构建器,已随示例编译验证):
import { ComponentBuilderContext, RNApp } from '@rnoh/react-native-openharmony';
import { QRScanKitCamera, QR_SCAN_KIT_CAMERA_TYPE } from '@oh-rn/react-native-qrcode-scanner';
// 1) 声明由 ArkTS 实现的组件名(与 JS 侧 codegenNativeComponent('QRScanKitCamera') 逐字一致)
const ARK_TS_COMPONENT_NAMES: string[] = [QR_SCAN_KIT_CAMERA_TYPE];
// 2) 组件构建器:C-API 混合方案要求外层 Stack 且 position 为 (0,0)
@Builder
export function buildCustomRNComponent(ctx: ComponentBuilderContext) {
Stack() {
if (ctx.componentName === QR_SCAN_KIT_CAMERA_TYPE) {
QRScanKitCamera({ ctx: ctx.rnComponentContext, tag: ctx.tag })
}
}
.position({ x: 0, y: 0 })
}
const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomRNComponent)
// 3) 传给 RNApp(其余参数保持宿主原样)
RNApp({
rnInstanceConfig: {
createRNPackages,
enableCAPIArchitecture: true,
arkTsComponentNames: ARK_TS_COMPONENT_NAMES,
// ...
},
wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder,
// ...
})
漏掉 arkTsComponentNames 时,RNOH 会去找不存在的 C++ ComponentInstance,取景区不渲染。宿主已有其他 ArkTS 组件时,把名字并入同一数组、在同一构建器里追加分支。
6. 权限
在宿主 harmony/entry/src/main/module.json5 的 requestPermissions 声明(本 HAR 未声明任何权限,须由宿主声明):
"requestPermissions": [
{
"name": "ohos.permission.CAMERA",
"reason": "$string:camera_permission_reason",
"usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
},
{ "name": "ohos.permission.VIBRATE" }
]
camera_permission_reason 需在宿主 resources/base/element/string.json 中定义。CAMERA 为 user_grant,运行时通过 checkCameraPermission() / requestCameraPermission() 检查与申请(组件挂载时也会自动发起);VIBRATE 供 vibrate(默认 true)使用。设备需支持 HarmonyOS Scan Kit。
完成以上步骤后重新生成宿主 Bundle、构建并安装 HAP;只刷新 JS 不会加载新增的原生模块。
使用说明
import React from 'react';
import {Text} from 'react-native';
import QRCodeScanner, {QRScanKitCamera as QRScanKitCameraProvider} from 'react-native-qrcode-scanner';
export default function App() {
return (
<QRCodeScanner
cameraProvider={QRScanKitCameraProvider}
onRead={(e) => console.log(e.data, e.type, e.bounds)}
vibrate
reactivate
reactivateTimeout={2000}
showMarker
topContent={<Text>将二维码放入框内</Text>}
bottomContent={<Text>扫描中…</Text>}
/>
);
}
派发链路(禁止绕过):
Scan Kit customScan 回调 → QRScanKitCamera.ets → eventEmitter.emit('barCodeRead')(codegen 封装的 emitComponentEvent)
→ JS 包装 → cameraProvider 的 onBarCodeRead
→ QRCodeScanner._handleBarCodeRead(去重锁 / 震动 / reactivate 定时器 / disable 门控)
→ props.onRead
若图省事直接调 onRead,「去重与重新武装」「震动与启停」两组行为会全部假通过——它们判的正是被绕过的那一段。
接口文档
公开接口 = 默认导出组件的 props(25 个) + 公开实例方法(3 个),另有适配层新增的 cameraProvider。主要项:
| API | 类型 | 默认值 | 说明 |
|---|---|---|---|
onRead |
(e: BarCodeReadEvent) => void |
打印日志 | 必填。识别到条码时派发一次 |
cameraProvider |
Component | 内置 Scan Kit 相机组件 | 可选的自定义相机来源注入点(适配层新增) |
vibrate |
boolean | true |
识别成功是否震动 |
reactivate |
boolean | false |
一次识别后是否自动重新武装 |
reactivateTimeout |
number | 0 |
重新武装延时(ms) |
cameraTimeout |
number | 0 |
相机空闲休眠时长(ms);0 = 不休眠 |
showMarker |
boolean | false |
取景框总开关 |
customMarker |
Element | 未定义 | 自定义取景框(受 showMarker 门控) |
topContent / bottomContent |
Element | string | 未定义 | 顶/底部内容区 |
containerStyle / cameraStyle / markerStyle / topViewStyle / bottomViewStyle |
Style | — | 各层样式 |
fadeIn |
boolean | true |
取景区淡入动画 |
flashMode |
'off'|'on'|'auto'|'torch' |
'auto' |
闪光灯档位(鸿蒙侧 auto 按环境亮度自动开关补光,见「约束与限制」) |
cameraType |
'front'|'back' |
'back' |
鸿蒙侧仅后置 |
notAuthorizedView / pendingAuthorizationView |
Element | 内置视图 | 未授权 / 待授权视图,鸿蒙侧由 QRScannerPermission TurboModule 提供授权状态 |
cameraTimeoutView |
Element | 内置「Tap to activate camera」 | 相机休眠时呈现 |
permissionDialogTitle / permissionDialogMessage / buttonPositive / checkAndroid6Permissions |
— | 'Info' / 'Need camera permission' / 'OK' / false |
源平台授权对话框参数,鸿蒙侧无对应表现 |
cameraProps |
object | {} |
透传给底层相机组件的任意 props |
disable() |
方法 | — | 停止读码(门控整个读码处理) |
enable() |
方法 | — | 恢复读码 |
reactivate() |
方法 | — | 手动重新武装(解锁去重) |
onRead 事件对象:
| 字段 | 类型 | 说明 |
|---|---|---|
data |
string | 条码原始内容(Scan Kit ScanResult.originalValue) |
type |
string | 码制字符串(scanType 经映射;无对等者为 unknown) |
bounds |
{ width, height, origin } |
码区域与四角点(Scan Kit scanCodeRect 折算,Android 形态) |
Fabric 原生组件契约(QRScanKitCamera,供接入方了解,不直接对外):
props flashMode(string,默认 'auto',上游 flashMode 原值直传,由 ArkTS 侧折算)、scanTypesCsv(string,默认 '',Scan Kit ScanType 数值 CSV,空 = 全部);
事件 onBarCodeRead(DirectEventHandler,bounds.origin 以 originJson JSON 字符串承载)、onCameraError(DirectEventHandler,{ code, message },经 cameraProps 透传可见)。
快速验证(运行 Example)
前置条件
| 依赖 | 版本要求 |
|---|---|
| Node.js | >= 20(示例工程 engines 要求);DevEco Sync 时 ohpm preInstall 钩子也要用 PATH 中的 Node.js 20+(或设置环境变量 DEVECO_PRELOAD_NODE 指向 node.exe) |
| DevEco Studio | 需含 compatibleSdkVersion 5.1.0(18) 及以上 SDK 的版本(targetSdkVersion 未显式指定,以本机 SDK 为准) |
| HarmonyOS SDK | API 18+(example/harmony 的 compatibleSdkVersion 为 5.1.0(18)) |
| 路径 | Windows 下仓库根目录的完整路径不超过 40 个字符,否则原生构建的中间文件路径会超过系统上限 |
运行步骤
1. 克隆仓库
git clone -b br_rnoh0.72 https://gitcode.com/hxa-rn/react-native-qrcode-scanner.git
cd react-native-qrcode-scanner
Windows 下可在克隆时指定短目录名,例如 git clone -b br_rnoh0.72 https://gitcode.com/hxa-rn/react-native-qrcode-scanner.git C:\rqr。
2. 进入 example 目录,安装依赖
cd example
npm install --legacy-peer-deps
Example 从 npm 公仓安装 @hxa-rn/react-native-qrcode-scanner@1.6.1,不需要在仓根执行 npm pack。
3. 生成 JS Bundle
npm run dev
产物:harmony/entry/src/main/resources/rawfile/bundle.harmony.js
4. 用 DevEco Studio 打开鸿蒙工程
- 打开 DevEco Studio,选择
example/harmony目录 - 首次构建请在 File → Project Structure → Signing Configs 勾选 Automatically generate signature,Apply 后 Sync
- 等待 Sync 完成
5. 编译并运行 HAP
在 DevEco Studio 中点击运行按钮,将 HAP 安装到设备。
example_auto(自动化用例工程)步骤相同,把 example 换成 example_auto 即可,两者的依赖与构建输出相互独立。
注意:Example 已完成 HAR 依赖、Autolink、ArkTS 组件注册与权限声明,无需手动 Link。编 HAP 前必须先执行
npm run dev;改过 JS 后重新执行再运行。设备需支持 HarmonyOS Scan Kit。
常见问题
- 找不到 JS 模块:检查适配包安装、Metro 别名及对应入口,修改 Metro 后重启打包进程。
- 找不到 HAR:核对
node_modules/@hxa-rn/react-native-qrcode-scanner/harmony/qrcode_scanner.har是否存在;不要将example_auto的 node_modules 当成example的依赖。 - 取景区空白:检查「集成指南」第 5 步的
arkTsComponentNames与组件构建器,以及相机权限是否已授予。 - 原生模块未注册或重复注册:检查 HAR、CMake、C++ 和 ETS 注册,Autolink 与 Manual 只能二选一,然后重建 HAP。
- DevEco 同步时报
Node.js 20 or newer with npm is required:安装 Node.js 20+ 并重启 DevEco Studio,或设置DEVECO_PRELOAD_NODE。 - SDK / 签名报错:按当前工程配置安装对应 SDK,并重新配置本机签名。
- Ninja
.rsp创建失败:查看完整日志;确认是路径长度问题后,缩短工程目录、清理旧路径构建缓存再构建。
约束与限制
兼容性:RNOH 0.72.143 / RN 0.72.5;HarmonyOS Scan Kit customScan(since API 4.1.0(11))。
本版本(1.6.0)验证范围:代码与 1.0.0 相同,仅版本号改为与上游基线一致。发布前以本包安装文件为依赖,本仓 example、example_auto(Autolink)在 DevEco Studio 6.1.1 下 assembleHap 编译通过;按「集成指南」路线 B 改接的宿主副本(Manual Link)编译通过的记录来自 1.0.0。
权限:ohos.permission.CAMERA(取景与识码依赖)、ohos.permission.VIBRATE(震动反馈),宿主 module.json5 需声明。
- 相机来源:当前适配包默认使用内置 Scan Kit 相机组件;
cameraProvider用于自定义来源,不依赖react-native-camera。 - 未授权 / 待授权两态视图:鸿蒙侧新增
QRScannerPermissionTurboModule,授权由 JS 侧发起 (与上游 iOS 分支同构),checkCameraPermission()/requestCameraPermission()返回真实相机授权状态,notAuthorizedView/pendingAuthorizationView两态视图分支可按授权状态呈现。 flashMode='auto'自动补光:使用customScan.on('lightingFlash')(5.0.0(12) 起)订阅环境亮度,暗则openFlashLight()、亮则closeFlashLight(),切出 auto 或组件销毁时退订。- 仅支持后置相机:
cameraType='front'无效,customScan API 无前置相机参数。 - 部分码制无对等映射:QR / AZTEC / CODE39 / 93 / 128 / DATAMATRIX / EAN8 / 13 / ITF14 / PDF417 / UPC_E
一一对应;CODABAR / UPC_A / 聚合枚举归
unknown(诚实归类,不伪造映射);code39mod43/interleaved2of5无 Scan Kit 对等,已剔除。 disable()的语义:它门控的是整个读码处理(既不派发也不震动), 尽管上游内部字段名为disableVibrationByUser——该命名有误导性,只按「关震动」理解会用错。- 自定义取景框受总开关门控:
showMarker关闭时,即便传了customMarker也不呈现。 static defaultProps禁止引用文件底部的styles:类属性初始化器在类定义时即求值, 那一刻const styles = StyleSheet.create({...})尚未初始化 → 取到undefined→ 模块加载即抛 → 首装纯白屏。三个默认视图必须写成内联样式对象。- 依赖精简:上游声明的
@react-native-community/async-storage、prop-types、react-native-permissions与 peerreact-native-camera在鸿蒙实现中均未使用,本包不声明这些依赖(授权改由内置QRScannerPermissionTurboModule 提供)。
开源 License
本项目基于 MIT License,与上游react-native-qrcode-scanner 保持一致,请自由地享受和参与开源。
问题反馈渠道
使用过程中发现任何问题,欢迎在GitCode 提交 Issue,也欢迎提交 PR 参与共建。