更新记录
0.1.0(2026-09-30)
首次发布预览版。
新增
- 纯本地离线 OCR:PP-OCRv5 mobile 检测 + 识别,ONNX Runtime 推理,全程不联网、不上传。
- 13 种识别模式:普通文本、身份证正/反面、车牌、银行卡、营业执照、自定义证件、社保卡、发票、车架号 VIN、行驶证、手机号、电动车牌。
- 字段级国标校验与纠错:GB 11643(身份证)、GA 36(车牌)、GB 32100(统一社会信用代码)、ISO 3779(VIN)、Luhn(银行卡)。校验不通过时结果仍返回并给出原因;仅在纠正结果唯一可信时才自动纠正。
- 真实证件适配:同行多框合并(证件标签字距大会被切成两个框)、按垂直重叠率分组、水印行丢弃、印章文字截断、地址跨行块提取、相册图方向搜索、车牌按牌面颜色做 ROI 定位。
- API:
ocrRecognize、ocrRecognizeAlbum、getBase64FromFilePath、ocrPrepare、ocrRelease。 - 初始化失败原因可通过
ocrPrepare回调的error与 logcat 标签offline-ocr获取。 - 随包
THIRD-PARTY-NOTICES.md:内置开源组件(ONNX Runtime / MIT、PaddleOCR PP-OCRv5 模型与字符表 / Apache-2.0)的许可声明、我们所做改动说明与 SHA-256 校验值。
已知限制
- 仅 Android(arm64-v8a,minSdk 21)。iOS / HarmonyOS 未包含在本版本。
- v1 不含内置取景界面与透视矫正,图片需由调用方用
uni.chooseImage取得后传imagePath。 - 推理库锁定 ONNX Runtime 1.19.2(其 aar 自带 manifest 声明 minSdk 21,可覆盖 Android 5~7 的旧手持机/PDA;1.22.0 起要求 minSdk 24)。详见 README「关于 ONNX Runtime 版本」。
- 不内置发卡行(BIN)名称库。
- 识别率实测样本量有限(每类 1 张真件 + 合成件),批量准确率请以自测为准。
平台兼容性
uni-app x(5.26)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | 5.0 | × | × | × |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | × | √ |
离线 OCR 文本识别(身份证 / 车牌 / 银行卡 / 营业执照 / 社保卡 / 车架号 VIN)
三端同一引擎的纯本地证件 OCR 插件:不联网、不上传任何图片、无调用次数限制、无后端依赖。
与市面同类插件最关键的两点差异:
- 三端加载同一份 PP-OCRv5 模型、同一套前后处理与字段规则(规则写在
utssdk/根目录的共享 UTS 源码里,编译到 Kotlin / Swift / ArkTS),因此同一张图在 Android、iOS、鸿蒙上得到完全一致的结构化结果。分平台各调一套系统 OCR 的实现做不到这一点。 - 字段级国标校验。识别出的号码不是"读出来就交给你",而是逐个过校验位并把结论一起返回:
| 字段 | 标准 | 校验内容 |
|---|---|---|
| 身份证号 | GB 11643-1999 | 省份码 + 出生日期合法性 + mod 11 校验位 |
| 车牌号 | GA 36-2018 | 省份简称白名单 + 序号字符规则 + 新能源 D/F 位 + 使领/港澳入境 |
| 统一社会信用代码 | GB 32100-2015 | 31 字符集(不含 I O S Z V)+ 加权模 31 校验位 |
| 车架号 VIN | ISO 3779 / 3729 | 17 位字符集(不含 I O Q)+ mod 11 校验位 |
| 银行卡号 | ISO/IEC 7812 | 13~19 位 + Luhn |
校验不通过时结果照样返回,但会明确告诉你哪条规则没过、原因是什么、以及哪些字段被自动纠正过(见 result.verify)。
同时做易混字符纠正:车牌字符集本身不含 I/O,所以 I→1、O→0 可以无损还原;VIN 受反光锈蚀影响大的 18 组形近字符做单点替换,只有当校验位能唯一确定答案时才接受,多解或无解一律不猜、原样返回并标记未通过。
一、平台支持
| 平台 | 支持情况 | 说明 |
|---|---|---|
| Android | 支持 | arm64-v8a;minSdk 21;需云打包(含三方 AAR) |
| iOS | 未实现 | 平台支持表按实标注为 -,不谎报;需要 iOS 请勿购买本版 |
| HarmonyOS NEXT | 未实现 | 同上 |
| H5 / 小程序 | 不支持 | 依赖原生推理 |
请以下方「版本信息」与 changelog 中的实测记录为准。未在你目标机型上验证过的项目,不要假定一定可用;本 README 不宣称未经实测的能力。
关于 ONNX Runtime 版本(影响你的 minSdk)
模型与推理库的 minSdk 是绑死的,实测各 AAR 自带 manifest 声明:1.22.0 要求 minSdk 24,1.19.2 / 1.17.0 要求 minSdk 21。
本插件锁定 1.19.2,为的是保住 Android 5~7 设备——证件 OCR 的主力客户里很大一块是停车场、物流、政务窗口用的手持终端/PDA,系统版本普遍偏旧。用到的 8 个 ORT API 已逐签名核对与新版一致,若你的工程本身 minSdk ≥ 24 想换新版,替换 utssdk/app-android/libs/ 下的 AAR 即可,代码无需改动。
三端差异(务必阅读)
- Android 已在本机完成编译验证(UTS→Kotlin 编译通过、宿主 App 编译通过),真机识别结果见「实测数据」。
- iOS / 鸿蒙:共享层(字段规则、校验、同行合并)与 Android 是同一份 UTS 源码,逻辑一致;native 取图与推理封装需各自平台的二进制依赖(iOS 需
onnxruntime.xcframework,鸿蒙需@ohos/onnxruntimeHAR)。推理库本身的获取路径不是障碍(Microsoft.ML.OnnxRuntimeNuGet 包内即含 iOS xcframework 三切片),本版本未交付这两端的真实原因是没有可编译、可验证的环境(无 macOS/Xcode、无对应真机),因此不做无法验证的承诺。若你购买的版本尚未包含对应端实现,插件会在该端返回错误码9020008,不会静默失败。
二、安装
环境要求
- HBuilderX 4.24+(uni_modules 规范插件)
- uni-app(Vue3)或 uni-app x 项目均可
- 因为本插件带三方原生依赖,标准基座不能运行,必须使用自定义调试基座或正式云打包。 运行到手机时报「模型加载失败」,绝大多数情况就是还在用标准基座。
步骤
- 插件市场点「下载插件并导入 HBuilderX」,或把
uni_modules/zdd-ocr-recognize整个目录拷进你的工程根目录下的uni_modules/。 - manifest.json → App 权限配置:勾选
Camera、Gallery(相机和相册)。 从 HBuilderX 3.6.11 起云打包默认不再包含这两个模块,不勾选时uni.chooseImage会直接失败。 - 生成自定义调试基座(发行 → 原生App-云打包 → 勾选"打自定义调试基座"),然后运行到手机时选择自定义基座。
- 首次识别会自动从安装包内解压并加载模型(约 1~2 秒);建议在页面空闲时调
ocrPrepare预热。
三、快速开始
import { ocrRecognize, ocrPrepare } from '@/uni_modules/zdd-ocr-recognize'
export default {
methods: {
// 1) 先用 uni.chooseImage 取图(三端同一套用法,权限由 uni-app 处理)
pickAndRecognize() {
uni.chooseImage({
count: 1,
sourceType: ['camera'], // 或 ['album']
success: (e) => this.recognize(e.tempFilePaths[0])
})
},
// 2) 把路径交给插件,recognizeType 决定证件类型
recognize(path) {
ocrRecognize({
recognizeType: 1, // 1 = 身份证正面
imagePath: path,
needVerify: true,
success: (res) => {
const d = res.result
console.log('姓名', d.name, '号码', d.idNo)
console.log('校验是否通过', d.verify.passed, d.verify.rules, d.verify.reasons)
},
fail: (err) => console.log('失败', err.code, err.message)
})
}
}
}
uni-app x(uvue)写法需要显式类型:
import { ocrRecognize, OCROptions } from '@/uni_modules/zdd-ocr-recognize'
const opt = {
recognizeType: 4, // 银行卡
imagePath: '/storage/emulated/0/Download/card.jpg'
} as OCROptions
ocrRecognize(opt)
四、API
4.1 ocrRecognize(options)
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
imagePath |
string | 必填 | 图片本地路径。接受 chooseImage 返回的临时路径、file://、content://、_doc/ |
recognizeType |
number | 0 |
识别模式,见下表 |
needVerify |
boolean | true |
是否执行国标校验并回填纠正结果 |
needCropImage |
boolean | true |
是否额外保存并返回裁剪后的证件图路径 |
customizeTags |
string | "" |
仅 recognizeType=6:自定义字段名 JSON 数组串,最多 15 项 |
recognizeType 之外的取景类参数 |
— | — | scanHintText、showPhotoAlbum、scanColor、bgColor、showBeep、showVibrate、isSupportZoom、showLightController、forceVertical、imgLocation、pickTextFromImg、textAreaType、pickTextAreaType、multiVerify、skipMatchParams、cameraDevice、customerToken 等,为 v2 内置取景界面预留,当前版本传入不报错也不生效 |
回调:success(res: OCRResult) / fail(err) / complete(res)。
4.2 ocrRecognizeAlbum({ imagePaths, recognizeType, breakOnError, complete })
批量识别相册图片。串行执行(避免多张图同时占内存),res.items 与入参顺序一致,单张失败不影响其余。
4.3 getBase64FromFilePath({ imagePath, success, fail })
图片转 base64(不含 data: 前缀,res.mime 为 jpeg)。内部会先降采样到 1280 长边,避免大图 base64 撑爆内存。
4.4 ocrPrepare(complete)
预热模型。回调参数为 { ready: boolean, error: string }。
error 一定要打印出来——加载失败的真实原因(缺依赖、资源未进包等)全在这里,只看 ready 会无从排查。
4.5 ocrRelease()
释放模型内存。App 长时间不再识别时调用;下次识别会自动重新加载。
五、识别模式与返回字段
res.result 为扁平结构,只填充当前模式相关字段,其余为 null。所有模式都会填 imagePath。
recognizeType |
模式 | 返回字段 |
|---|---|---|
| 0 | 普通文本 | text、lines[{text,box,confidence}] |
| 1 | 身份证正面 | name sex nation birthday(yyyy-MM-dd) address idNo |
| 2 | 身份证反面 | validPeriod(yyyy-MM-dd 至 yyyy-MM-dd) issueOrg |
| 3 | 车牌 | licensePlate licensePlateType licensePlateTypeName |
| 4 | 银行卡 | cardId bankInfo validDate cardScheme |
| 5 | 营业执照 | businessName socialCreditCode businessType businessAddress legalPeople registerMoney createDate validDate businessScope businessLicenseNumber |
| 6 | 自定义证件 | fields(Map,键为 customizeTags 里的字段名) |
| 7 | 社保卡 | name socialSecurityNumber bankCardNo bankCardType cardNo |
| 8 | 发票 | invoiceCode invoiceNumber invoiceDate invoiceAmount invoiceTotal buyerName sellerName |
| 9 | 车架号 VIN | vin |
| 10 | 行驶证 | owner licensePlate vin vehicleType bandType engineNo registerDate issueDate address |
| 11 | 手机号 | phoneNumbers(数组,已去重) |
| 12 | 电动车/自行车牌 | licensePlate |
licensePlateType 取值:0 未知、1 常规蓝牌、2 新能源、3 黄牌、4 白牌(军警)、5 使领馆、6 港澳入境、7 电动车牌。
该枚举为本插件自定义,不与任何其他插件的数值互通,迁移需按名称重映射。
result.verify
{
passed: true, // 主字段是否通过国标校验
rules: ["idCardChecksum"], // 命中的规则
reasons: [], // 未通过的原因(人类可读)
correctedFields: ["idNo"] // 被自动纠正过的字段名
}
passed=false 不代表结果一定错,只代表它无法自证。建议业务侧的处理策略:passed=true 直接入库;passed=false 展示原文让用户确认。
六、实测数据
真机(华为 HMA-AL00 / Android 10 / arm64,2026-09-30)
通过页面自动回归跑完整链路(ocrPrepare → 读图 → det → rec → 同行合并 → 字段抽取 → 国标校验),结果从 logcat 机器可读输出采集:
| 类型 | 耗时 | 校验规则 | 关键结果 |
|---|---|---|---|
| 身份证正面 | 912ms | idCardChecksum 通过 |
姓名/号码/出生日期/民族/性别正确,住址跨 3 行正确合并 |
| 车牌 | 263ms | plateGA36 通过 |
粤R888G8(装饰圆点已剥离),类型"常规车牌" |
| 银行卡 | 1075ms | luhn 通过 |
6231020501000087054、UnionPay、威海市商业银行 |
| 营业执照 | 3048ms | usccChecksum 通过 |
名称、91310112MAD5T2164X、法定代表人(红章文字已剥离)、2023-11-28 至 2027-12-11 |
| 车架号 VIN | 1304ms | vinChecksum 通过 |
LS5A2DKE2MA263439 |
冷启动首次识别含模型加载约多花 350ms(实测 1320ms vs 预热后 969ms),所以建议在页面空闲时先调 ocrPrepare。
取图方式会影响识别结果(重要)
同一张身份证照片,uni.chooseImage 默认返回的是压缩重编码后的临时文件,而压缩会引入模型误读。实测同一张图:
| 输入 | 未加保护时的姓名取值 |
|---|---|
| 原始文件 | 龚友强 |
| JPEG 质量 0.8 重编码 | 姓名b → 姓名被解析成 b龚友强 |
JPEG 压缩在标签区产生的伪字符会被检测框吸附到标签上,于是"取标签之后的内容"就把噪声一起取了进来。
插件侧已做防护:姓名字段按 CJK 白名单清洗(只保留汉字与少数民族姓名的间隔号),压缩引入的拉丁字母会被剥掉,清洗后为空则退回原值。
调用侧建议:能取原图就取原图 —— uni.chooseImage({ sizeType: ['original'] })。
样本量诚实说明:以上每类各只有 1 张实拍样本。它证明的是"链路对这些真实版式能跑通且字段正确",不等于批量识别率。真实识别率需要每类 ≥50 张不同机型、光线、角度的样本统计,购买后请按你的实际场景自测。
已记录的能力边界
- 形近汉字仍会错:营业执照"2幢323室"两端都读成"2输323室";同一路名 PC 读"幸福路"、真机读"李福路",说明低对比度小字已在模型判定边界上。
- 银行卡有效期没有校验位,因此要求它必须未过期才输出(实测真机会把无关数字读成
12/12并当成有效期)。
七、能力边界(会踩到,请看完)
- v1 不含内置取景界面。图片必须由调用方用
uni.chooseImage等方式取得后传imagePath。实时预览、边框检测、自动抓拍在 v2。 - 倾斜/弯曲不矫正。v1 只做轴对齐裁剪,不做透视变换。拍歪的卡证请重拍,或自行做矫正后传入。
- 形近汉字会错。实测把营业执照"2幢323室"读成"2输323室"。汉字形近误识是当前模型的固有边界,无校验位的字段(姓名、地址、经营范围)无法自动发现。
- 背景水印会产生假文本框。证件满版水印(如营业执照的
SCJDGL)置信度可达 0.88,插件按规则丢弃"无中文的纯大写拉丁短行",但不能保证全部滤净。 - 照片方向。手机照片可能物理旋转而 EXIF 未标记,插件会做方向搜索兜底,但会增加耗时;取景时保持横平竖直最稳。
- 发卡行名称不内置。准确的 BIN→银行 映射需要持牌数据源,插件不内置猜测表。
bankInfo返回的是卡面上识别到的银行名称文字,cardScheme是按公开号段规则判定的卡组织。 - 各地电动车牌规则不统一。编码长度与规则各城市不同,模式 12 只保证"不输出非法串",不保证种类判定正确。
- 军警白牌不做颜色定位(与背景对比度太低),会退回通用文本检测,成功率下降。
- 文件扩展名不可信。遇到过实际是 WebP 却命名为
.jpg的相册图;插件按内容解码,但请确保来源格式在平台解码能力范围内。 - 包体积:模型约 21MB + 推理库约 28MB,会明显增加安装包体积。只投 arm64 可再减小。
八、隐私与合规
- 全部识别在设备本地完成,不联网、不采集、不上传任何图片或识别结果,插件不申请网络权限。
- 但你的 App 用本插件处理身份证等个人敏感信息时,仍需按《个人信息保护法》履行告知同意、在隐私政策中列明摄像头/相册权限与用途,并满足各应用市场的审核要求。插件本身不提供合规承诺。
- 若上架国内应用市场,还需在 manifest 中配置隐私政策相关项,否则云打包会给出提示。
- 内置开源组件:ONNX Runtime(MIT)+ PaddleOCR / PP-OCRv5 模型与字符表(Apache-2.0)。两者的许可均允许商用与再分发;完整声明、我们所做改动及文件校验值见插件包内
THIRD-PARTY-NOTICES.md,请勿删除该文件。 - 识别能力来自 PP-OCRv5 通用文字模型,不是 PaddlePaddle 官方对本插件准确率的背书;所有字段校验规则(GB 11643、GA 36、GB 32100、ISO 3779、Luhn)由本插件自行实现。
九、错误码
| 码 | 含义 | 常见原因 |
|---|---|---|
| 9020001 | 用户取消 | 取图取消 |
| 9020002 / 9020003 | 相机 / 相册权限被拒 | 系统权限未授予 |
| 9020004 | 图片读取失败 | 路径失效、文件被移动 |
| 9020005 | 图片解码失败 | 格式不支持或文件损坏 |
| 9020006 | 模型资源缺失 | 插件 assets 未完整打进包 |
| 9020007 | 引擎初始化失败 | 在用标准基座运行;或缺三方库 |
| 9020008 | 当前平台不支持该模式 | 该端尚未实现 |
| 9020009 | 推理失败 | 内存不足、图片过大 |
| 9020010 | 未检测到有效文本区域 | 距离太远、光线差、角度歪 |
| 9020011 | 字段校验未通过 | 结果仍返回,见 verify.reasons |
| 9020012 | 参数非法 | 未传 imagePath 等 |
ocrPrepare 的 error 字段会带上底层异常原文,排查时优先看它和 logcat 的 offline-ocr 标签。
十、FAQ
Q:为什么报"模型加载失败"?
A:九成是在用标准基座。本插件含三方原生依赖,必须打自定义调试基座。请先调 ocrPrepare 并把 error 打印出来确认。
Q:uni.chooseImage 报 chooseImage:fail 路径不存在,但插件没报错?
A:这是取图阶段的权限问题,插件根本没被调用。部分国产 ROM(华为 EMUI 等)不会自动授予相机/存储运行时权限,即使清单里已声明、即使用 adb install -g 安装。到系统设置里手动授予后重试。排查时先看引擎状态:如果还是 idle,说明失败发生在插件之前。
Q:姓名/号码前面多出一个字母或符号?
A:uni.chooseImage 默认返回压缩重编码的临时文件,JPEG 压缩会在卡面标签区产生被模型误读的伪字符。已实测并加了 CJK 清洗保护。建议调用时传 sizeType: ['original']。
Q:能不能不传 imagePath,让插件自己开相机?
A:v1 不行,用 uni.chooseImage 即可,三端一致且权限已由 uni-app 处理。内置取景在 v2。
Q:识别一张要多久?
A:与机型和文字量相关。建议先 ocrPrepare 预热,避免把首次加载的 1~2 秒算进第一次识别。
Q:能同时支持 32 位设备吗? A:当前只保证 arm64-v8a。需要 armeabi-v7a 请先联系确认。
Q:识别结果能直接入库吗?
A:verify.passed === true 的字段可以直接入库;为 false 的必须人工确认,因为号码类字段一旦校验位不对就是错的。

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 1
赞赏 0
下载 12649086
赞赏 1953
赞赏
京公网安备:11010802035340号