UniApp 离线 OCR (基于 RapidOcr 的原生模块开发)
一、项目背景
移动端 OCR 需求很常见:识别身份证、票据、屏幕截图中的文字。主流方案有两种:
| 方案 | 代表 | 优点 | 缺点 |
|---|---|---|---|
| 云端 OCR | 百度、腾讯、阿里 API | 识别率高 | 需联网、按次收费、数据安全风险 |
| 端侧 OCR | RapidOcr(ONNX Runtime) | 离线、免费、低延迟 | 模型精度略低、包体增大 |
本项目选择端侧离线 OCR(RapidOcr Android,底层 ONNX Runtime + PP-OCR 模型),并需要把它塞进UniApp 离线打包的壳工程里,让前端页面通过 JS 调用原生相机识别界面,拿到识别结果。
1.1 技术栈
- 前端:UniApp(使用Vue2 语法)
- 壳工程:Android(Java + Kotlin),集成 UniApp SDK(
uniapp-v8-release.aar) - OCR 引擎:
OcrLibrary(native so:libRapidOcr.so、libonnxruntime.so),支持 x86 / armeabi-v7a / arm64-v8a - 相机:Jetpack CameraX + 自定义取景框(
CameraLensView)
1.2 整体架构
┌──────────────────────────────────────────┐ │ UniApp 页面 (pages/index/index.vue) │ │ weex.requireModule("OCRModule") │ └──────────────┬───────────────────────────┘ │ JS Bridge (UniModule) ┌──────────────▼───────────────────────────┐ │ OCRModule (UnoModule 子类) │ │ getOcrResult(UniJSCallback) │ └──────────────┬───────────────────────────┘ │ 静态 Holder 中转 ┌──────────────▼───────────────────────────┐ │ OcrResultHolder (static result/timeMs) │ └──────────────┬───────────────────────────┘ │ 静态方法读写 ┌──────────────▼───────────────────────────┐ │ CameraActivity (CameraX 预览 + OCR识别) │ │ OcrEngine (Kotlin 单例, native 加速) │ └──────────────────────────────────────────┘主要识别流程:UniApp 拉起原生 Activity → Activity 拍照识别 → 结果写入静态 Holder → Activity finish → UniApp 页面轮询 Holder 拿结果。
二、数据传递流程
原生 Activity 与 UniModule 之间没有直接引用关系,需要做一个静态数据中转:
publicclassOcrResultHolder{privatestaticStringlastResult="";privatestaticintlastTimeMs=0;publicstaticvoidsetResult(Stringresult,inttimeMs){lastResult=result;lastTimeMs=timeMs;}/** 读取结果并自动清除(读取即消费) */publicstaticStringgetLastResult(){Stringr=lastResult;lastResult="";returnr;}publicstaticintgetLastTimeMs(){intt=lastTimeMs;lastTimeMs=0;returnt;}}将数据传回js端
@UniJSMethod(uiThread=true)publicvoidgetOcrResult(UniJSCallbackcallback){Map<String,Object>data=newHashMap<>(4);Stringresult=OcrResultHolder.getLastResult();inttimeMs=OcrResultHolder.getLastTimeMs();data.put("result",result!=null?result:"");data.put("timeMs",timeMs);data.put("success",!TextUtils.isEmpty(result));callback.invoke(data);}前端页面获取识别结果:
checkOcrResult(){try{constmodule=uni.requireNativePlugin('OCRModule')if(!module){console.error('[OCR] OCRModule未注册')return}constself=thismodule.getOcrResult(function(res){if(res.success&&res.result&&res.result!==''){constocr=res.result self.ocrText=ocr self.ocrTime=res.timeMs uni.showToast({title:'OCR成功:'+res.result,icon:'none'})}else{console.log('[OCR] 无可用结果')}})}catch(e){console.error('[OCR] 读取结果失败:',JSON.stringify(e))uni.showToast({title:'读取OCR结果失败',icon:'none'})}}三、项目总结
通过本次基于 RapidOcr 的 UniApp 离线 OCR 原生模块开发,我们可以得出以下几点经验:
1.采用混合开发:
利用 UniModule 结合静态数据中转类 (OcrResultHolder) 的设计模式,完美解决了跨语言及不同生命周期组件间异步通信的痛点,确保了原生相机扫描结果能够无缝、安全地回传至前端页面。
2.兼顾性能与数据安全:
采用端侧离线运行模式(ONNX Runtime + PP-OCR 模型),不仅彻底摆脱了对外部网络环境的依赖、节省了长期的云端 API 商业调用成本,更从根本上保障了敏感文本(如身份证、票据等)的本地化隐私安全。高扩展与高复用性:
四、资源下载
以下地址提供完整的项目源码,欢迎点赞、收藏、下载交流,点击分享内容即可下载
https://pan.quark.cn/s/b60c184772c2