在移动应用开发中,手动输入身份证、银行卡等信息不仅效率低,还容易出错。华为 HarmonyOS 提供的卡证识别控件,能通过 OCR 技术自动识别多种证件信息,完美解决这一痛点。本文会用口语化的表达,从场景介绍、约束限制,到详细开发步骤和完整实例,带大家一步步掌握卡证识别开发,每个重点都搭配 ArkTS 代码,让大家看完就能上手实操。

一、先搞懂:卡证识别控件能做啥?

咱们先明确下,这个卡证识别控件可不是花架子,功能实实在在。它能识别多种常见证件,还能自动分类、返回结构化信息,在很多场景都能派上大用场。

1.1 支持的证件类型,看这 5 种就够了

目前控件能搞定 5 种常用证件,基本覆盖日常开发需求。

  • 身份证:只支持中国大陆二代身份证,要注意,民汉双文的身份证暂时识别不了。而且它能单独识别正面、反面,也能同时进行双面识别,特别方便。
  • 行驶证、驾驶证:这两种证件也支持双面识别,像行驶证上的车辆信息、驾驶证上的准驾车型等,都能准确识别出来。
  • 护照:只能识别单面,不过像护照号、有效期、持证人姓名这些关键信息,都能完整提取。
  • 银行卡:同样是单面识别,不仅能识别卡号,还能通过配置显示卡号弹窗,让用户确认信息,避免识别错误。

1.2 实用场景,看完就知道在哪用

最常见的场景就是信息自动填充。比如用户注册账号时,需要填写身份证信息,用这个控件扫一下身份证,姓名、身份证号、地址等信息就自动填到表单里了,用户不用再手动输入,既省时间又减少错误。还有绑定银行卡的时候,扫一下银行卡,卡号直接获取,不用用户反复输入再确认,提升用户体验。另外,在一些需要验证证件的场景,比如租车时要验证驾驶证、行驶证,控件能快速识别证件信息并返回,方便开发者进行信息核验。

二、必注意:这些约束限制别踩坑

虽然卡证识别控件很好用,但也有一些约束和限制,开发前一定要了解清楚,不然开发到一半遇到问题,就麻烦了。

2.1 不支持模拟器,必须用真机

这个是硬性要求,不管你是开发哪种证件的识别功能,都不能用模拟器调试,必须用 HarmonyOS 真机。所以开发前,要准备好一台 HarmonyOS 系统的手机或平板,不然根本没办法测试控件是否能正常工作。

2.2 语种和证件类型有局限

从语种来看,目前只支持简体中文和英文,要是遇到其他语种的证件,比如纯日文、韩文的护照,就识别不了了,开发时要考虑到自己的应用是否会涉及这些特殊情况。证件类型方面,前面也提到了,暂时只支持身份证、行驶证、驾驶证、护照、银行卡这 5 种,像社保卡、医保卡这些暂时还不支持,要是应用需要识别这些证件,就不能用这个控件了。

2.3 控件不能被遮挡

在使用卡证识别功能时,卡证识别控件所在的区域不能被其他组件或窗口遮挡。比如你在页面上放了一个弹窗,刚好挡住了卡证识别的取景框,那控件就没办法正常识别证件了。所以开发页面布局时,要确保卡证识别控件的区域是完整显示的,没有其他元素遮挡。

三、手把手教:开发步骤详解(附代码)

了解了场景和约束,接下来就进入重点,教大家一步步进行卡证识别开发,每个步骤都有对应的 ArkTS 代码,跟着做就能实现功能。

3.1 第一步:导入相关类,打好基础

首先,要把卡证识别控件相关的类导入到工程里,这些类是实现卡证识别功能的基础,少了哪个都不行。需要注意的是,CardRecognitionConfig、CardContentConfig、BankCardConfig 这些类从 API12 开始才支持,所以开发时要确保项目的 API 版本不低于 12。

导入代码如下:

import { CardRecognition, CardRecognitionResult, CardType, CardSide, CardRecognitionConfig, ShootingMode, CardContentConfig, BankCardConfig } from "@kit.VisionKit";
import { hilog } from '@kit.PerformanceAnalysisKit';

这里还导入了 hilog,主要是为了在控制台打印日志,方便开发时调试,查看识别结果等信息。

3.2 第二步:配置页面布局,选好识别参数

导入类之后,就要配置页面布局了,同时选择需要识别的卡证类型、卡证页面(正面 / 反面 / 双面),还要设置一些其他的参数,比如拍摄模式、是否支持照片选择等,最后在回调函数里获取识别结果。下面分别以身份证、银行卡、护照、驾驶证、行驶证这 5 种证件为例,给大家展示具体的代码。

3.2.1 身份证识别配置

身份证支持双面识别,所以 cardSide 设为 CardSide.DEFAULT。拍摄模式这里选的是手动模式(ShootingMode.MANUAL),也可以根据需求选自动模式。isPhotoSelectionSupported 设为 true,表示支持从相册选择照片进行识别,要是不需要这个功能,设为 false 就行。

代码如下:

const TAG = 'CardRecognition';

@Entry
@Component
struct Index {
  build() {
    Column() {
      // 身份证识别控件
      CardRecognition({
        supportType: CardType.CARD_ID, // 识别类型为身份证
        cardSide: CardSide.DEFAULT, // 支持双面识别
        cardRecognitionConfig: {
          defaultShootingMode: ShootingMode.MANUAL, // 手动拍摄模式
          isPhotoSelectionSupported: true // 支持从相册选图
        },
        onResult: ((params: CardRecognitionResult) => {
          // 打印识别结果相关日志
          hilog.info(0x0001, TAG, `params code: ${params.code}`);
          hilog.info(0x0001, TAG, `params cardType: ${params.cardType}`);
          hilog.info(0x0001, TAG, `params cardInfo front: ${JSON.stringify(params.cardInfo?.front)}`);
          hilog.info(0x0001, TAG, `params cardInfo back: ${JSON.stringify(params.cardInfo?.back)}`);
        })
      })
    }
    .height('100%')
    .width('100%')
  }
}

在 onResult 回调里,params.code 表示识别状态码,200 表示识别成功;params.cardType 是识别出的证件类型;params.cardInfo.front 是身份证正面的信息,像姓名、身份证号等;params.cardInfo.back 是身份证反面的信息,比如有效期。

3.2.2 银行卡识别配置

银行卡只有单面,所以 cardSide 设为 CardSide.FRONT。这里还多了一个 cardContentConfig 配置,isBankNumberDialogShown 设为 true,识别成功后会弹出显示银行卡号的弹窗,让用户确认卡号是否正确,提升信息准确性。

代码如下:

const TAG = 'CardRecognition';

@Entry
@Component
struct Index {
  build() {
    Column() {
      // 银行卡识别控件
      CardRecognition({
        supportType: CardType.CARD_BANK, // 识别类型为银行卡
        cardSide: CardSide.FRONT, // 仅识别正面
        cardRecognitionConfig: {
          defaultShootingMode: ShootingMode.MANUAL, // 手动拍摄模式
          isPhotoSelectionSupported: true, // 支持从相册选图
          cardContentConfig: { 
            bankCard: { isBankNumberDialogShown: true } // 显示卡号弹窗
          }
        },
        onResult: ((params: CardRecognitionResult) => {
          hilog.info(0x0001, TAG, `params code: ${params.code}`);
          hilog.info(0x0001, TAG, `params cardType: ${params.cardType}`);
          hilog.info(0x0001, TAG, `params cardInfo: ${JSON.stringify(params.cardInfo?.main)}`);
        })
      })
    }
    .height('100%')
    .width('100%')
  }
}

银行卡的识别信息存在 params.cardInfo.main 里,包括卡号、银行名称等。

3.2.3 护照识别配置

护照也是单面识别,配置和银行卡类似,只是 supportType 设为 CardType.CARD_PASSPORT,不需要 cardContentConfig 配置(除非有特殊需求)。

代码如下:

const TAG = 'CardRecognition';

@Entry
@Component
struct Index {
  build() {
    Column() {
      // 护照识别控件
      CardRecognition({
        supportType: CardType.CARD_PASSPORT, // 识别类型为护照
        cardSide: CardSide.FRONT, // 仅识别正面
        cardRecognitionConfig: {
          defaultShootingMode: ShootingMode.MANUAL, // 手动拍摄模式
          isPhotoSelectionSupported: true // 支持从相册选图
        },
        onResult: ((params: CardRecognitionResult) => {
          hilog.info(0x0001, TAG, `params code: ${params.code}`);
          hilog.info(0x0001, TAG, `params cardType: ${params.cardType}`);
          hilog.info(0x0001, TAG, `params cardInfo: ${JSON.stringify(params.cardInfo?.main)}`);
        })
      })
    }
    .height('100%')
    .width('100%')
  }
}

护照的识别信息,像护照号、持证人姓名、有效期等,都在 params.cardInfo.main 中。

3.2.4 驾驶证识别配置

驾驶证支持双面识别,配置和身份证类似,supportType 设为 CardType.CARD_DRIVER_LICENSE。

代码如下:

const TAG = 'CardRecognition';

@Entry
@Component
struct Index {
  build() {
    Column() {
      // 驾驶证识别控件
      CardRecognition({
        supportType: CardType.CARD_DRIVER_LICENSE, // 识别类型为驾驶证
        cardSide: CardSide.DEFAULT, // 支持双面识别
        cardRecognitionConfig: {
          defaultShootingMode: ShootingMode.MANUAL, // 手动拍摄模式
          isPhotoSelectionSupported: true // 支持从相册选图
        },
        onResult: ((params: CardRecognitionResult) => {
          hilog.info(0x0001, TAG, `params code: ${params.code}`);
          hilog.info(0x0001, TAG, `params cardType: ${params.cardType}`);
          hilog.info(0x0001, TAG, `params cardInfo front: ${JSON.stringify(params.cardInfo?.front)}`);
          hilog.info(0x0001, TAG, `params cardInfo back: ${JSON.stringify(params.cardInfo?.back)}`);
        })
      })
    }
    .height('100%')
    .width('100%')
  }
}

驾驶证正面信息(如姓名、准驾车型)在 params.cardInfo.front,反面信息(如有效期、档案编号)在 params.cardInfo.back。

3.2.5 行驶证识别配置

行驶证同样支持双面识别,supportType 设为 CardType.CARD_VEHICLE_LICENSE,其他配置和身份证、驾驶证类似。

代码如下:

const TAG = 'CardRecognition';

@Entry
@Component
struct Index {
  build() {
    Column() {
      // 行驶证识别控件
      CardRecognition({
        supportType: CardType.CARD_VEHICLE_LICENSE, // 识别类型为行驶证
        cardSide: CardSide.DEFAULT, // 支持双面识别
        cardRecognitionConfig: {
          defaultShootingMode: ShootingMode.MANUAL, // 手动拍摄模式
          isPhotoSelectionSupported: true // 支持从相册选图
        },
        onResult: ((params: CardRecognitionResult) => {
          hilog.info(0x0001, TAG, `params code: ${params.code}`);
          hilog.info(0x0001, TAG, `params cardType: ${params.cardType}`);
          hilog.info(0x0001, TAG, `params cardInfo front: ${JSON.stringify(params.cardInfo?.front)}`);
          hilog.info(0x0001, TAG, `params cardInfo back: ${JSON.stringify(params.cardInfo?.back)}`);
        })
      })
    }
    .height('100%')
    .width('100%')
  }
}

行驶证正面的车辆品牌、型号、车牌等信息在 params.cardInfo.front,反面的核定载人数、使用性质等信息在 params.cardInfo.back。

四、实战演练:完整开发实例(入口页 + 实现页)

前面讲的是单个证件的识别配置,实际开发中,通常需要一个入口页,点击按钮进入对应的卡证识别页面,识别完成后还能显示识别到的信息。下面就给大家展示一个完整的开发实例,包含卡证识别入口页和实现页,以身份证识别为例,其他证件的识别只需修改 supportType 等参数即可。

4.1 入口页:MainPage.ets

入口页很简单,就是一个页面,上面有一个 “卡证识别” 按钮,点击按钮跳转到卡证识别实现页(CardDemoPage)。这里用到了 Navigation 和 NavPathStack 来实现页面跳转,这是 HarmonyOS 中常用的页面导航方式。

代码如下:

import { CardDemoPage } from './CardDemoPage'; // 引入识别实现页

@Entry
@Component
struct MainPage {
  // 用于管理页面导航栈
  @Provide('pathStack') pathStack: NavPathStack = new NavPathStack();

  // 页面映射,根据名称跳转到对应的页面
  @Builder
  PageMap(name: string) {
    if (name === 'cardRecognition') {
      CardDemoPage(); // 跳转到卡证识别实现页
    }
  }

  build() {
    // 导航组件
    Navigation(this.pathStack) {
      // 卡证识别入口按钮
      Button('卡证识别', { stateEffect: true, type: ButtonType.Capsule })
        .width('50%')
        .height(40)
        .onClick(() => {
          // 点击按钮,将识别页推入导航栈,实现跳转
          this.pathStack.pushPath({ name: 'cardRecognition' });
        })
    }
    .title('卡证识别控件Demo') // 导航栏标题
    .navDestination(this.PageMap) // 设置页面映射
    .mode(NavigationMode.Stack) // 栈式导航模式
  }
}

这里的 @Provide ('pathStack') 是为了给子组件(CardDemoPage)提供导航栈实例,方便子组件进行页面返回操作。Button 的 type 设为 Capsule,是胶囊样式的按钮,看起来更美观;stateEffect 设为 true,点击时有状态变化的效果。

4.2 实现页:CardDemoPage.ets

实现页是卡证识别的核心页面,主要功能是加载卡证识别控件,进行身份证识别,识别成功后将识别到的信息(包括证件图片和文字信息)显示在页面上,要是识别失败(状态码不是 200),就返回入口页。

代码如下:

import { CardRecognition, CardRecognitionResult, CardType, CardSide, ShootingMode } from "@kit.VisionKit";
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG: string = 'CardRecognitionPage'; // 日志标签

// 卡证识别实现页
@Entry
@Component
export struct CardDemoPage {
  // 用于存储识别到的卡证信息
  @State cardDataSource: Record<string, string>[] = [];
  // 从父组件获取导航栈实例,用于返回入口页
  @Consume('pathStack') pathStack: NavPathStack;

  build() {
    // 导航目标组件,用于承载识别页面内容
    NavDestination() {
      // 栈式布局,用于叠加显示识别控件和信息列表
      Stack({ alignContent: Alignment.Top }) {
        // 显示识别到的卡证信息的栈
        Stack() {
          this.cardDataShowBuilder(); // 调用自定义构建器显示信息
        }
        .width('80%')
        .height('80%')

        // 卡证识别控件(身份证识别为例)
        CardRecognition({
          supportType: CardType.CARD_ID, // 识别类型:身份证
          cardSide: CardSide.DEFAULT, // 支持双面识别
          cardRecognitionConfig: {
            defaultShootingMode: ShootingMode.MANUAL, // 手动拍摄模式
            isPhotoSelectionSupported: true // 支持从相册选图
          },
          onResult: ((params: CardRecognitionResult) => {
            // 打印识别状态码
            hilog.info(0x0001, TAG, `params code: ${params.code}`);
            // 识别失败(状态码非200),返回入口页
            if (params.code !== 200) {
              this.pathStack.pop();
            }
            // 打印识别的证件类型
            hilog.info(0x0001, TAG, `params cardType: ${params.cardType}`);

            // 将身份证正面信息添加到数据源
            if (params.cardInfo?.front !== undefined) {
              this.cardDataSource.push(params.cardInfo?.front);
            }

            // 将身份证反面信息添加到数据源
            if (params.cardInfo?.back !== undefined) {
              this.cardDataSource.push(params.cardInfo?.back);
            }

            // 其他证件(如银行卡、护照)的信息添加(此处预留)
            if (params.cardInfo?.main !== undefined) {
              this.cardDataSource.push(params.cardInfo?.main);
            }

            // 打印身份证正反面信息
            hilog.info(0x0001, TAG, `params cardInfo front: ${JSON.stringify(params.cardInfo?.front)}`);
            hilog.info(0x0001, TAG, `params cardInfo back: ${JSON.stringify(params.cardInfo?.back)}`);
          })
        })
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .hideTitleBar(true) // 隐藏导航栏标题栏,让识别控件全屏显示
  }

  // 自定义构建器:用于显示识别到的卡证信息
  @Builder
  cardDataShowBuilder() {
    // 列表组件,垂直方向显示信息
    List() {
      // 遍历数据源,显示每条卡证信息
      ForEach(this.cardDataSource, (cardData: Record<string, string>) => {
        ListItem() {
          Column() {
            // 显示证件图片
            Image(cardData.cardImageUri)
              .objectFit(ImageFit.Contain) // 图片适应方式:包含
              .width(100)
              .height(100)

            // 显示证件文字信息(JSON格式)
            Text(JSON.stringify(cardData))
              .width('100%')
              .fontSize(12) // 字体大小,避免文字过多显示不全
          }
        }
      })
    }
    .listDirection(Axis.Vertical) // 列表垂直排列
    .alignListItem(ListItemAlign.Center) // 列表项居中对齐
    .margin({ top: 50 }) // 顶部margin,避免信息靠上显示
    .width('100%')
    .height('100%')
  }
}
4.2.1 关键代码解析
  • @State cardDataSource:用 @State 装饰器修饰,是状态变量,当它的值发生变化时,页面会自动刷新,显示最新的识别信息。它是一个数组,每个元素是 Record<string, string> 类型,用来存储单页证件的信息,包括 cardImageUri(证件图片的 URI)和其他文字信息(如姓名、身份证号等)。
  • @Consume ('pathStack'):从父组件(MainPage)消费导航栈实例,当识别失败时,调用 this.pathStack.pop () 就能返回入口页。
  • CardRecognition 控件:这里设置的是身份证识别,要是想识别其他证件,只需把 supportType 改成对应的类型,比如识别银行卡就改成 CardType.CARD_BANK,同时调整 cardSide 等参数。
  • cardDataShowBuilder 构建器:用 List 组件显示识别到的信息,每个 ListItem 包含证件图片和文字信息。Image 组件通过 cardData.cardImageUri 获取证件图片,Text 组件用 JSON.stringify (cardData) 显示所有文字信息,方便开发者查看完整的识别结果。
4.2.2 测试效果

把这两个页面的代码写好后,用 HarmonyOS 真机运行项目。点击入口页的 “卡证识别” 按钮,进入实现页,此时会打开相机,对准身份证正面或反面,手动点击拍摄按钮进行识别。识别成功后,页面会显示身份证的图片和对应的文字信息;要是识别失败,比如相机没对准证件、光线太暗导致识别不清,页面会自动返回入口页。另外,也可以点击页面上的相册图标,从相册选择保存好的身份证图片进行识别,同样能得到识别结果。

五、常见问题与解决办法

在开发和测试过程中,可能会遇到一些问题,这里总结了几个常见的问题和对应的解决办法,帮大家少走弯路。

5.1 问题 1:模拟器运行报错

现象:在模拟器上运行项目,打开卡证识别页面时,报错提示不支持该功能。原因:前面已经提到,卡证识别控件不支持模拟器,只能用真机。解决办法:准备一台 HarmonyOS 系统的真机,将项目部署到真机上进行测试。部署前要确保真机已开启开发者模式,并且已在 DevEco Studio 中正确配置了设备。

5.2 问题 2:识别不到证件信息

现象:用真机测试,对准证件拍摄后,没有返回识别信息,日志中可能显示识别失败。原因:可能有以下几种原因:

  1. 证件不在支持的类型范围内,比如用了民汉双文的身份证,或者社保卡等不支持的证件。
  2. 拍摄时光线不好,证件上的文字模糊,导致 OCR 识别不出信息。
  3. 卡证识别控件被其他组件遮挡,比如页面上有弹窗、按钮等元素挡住了取景框。解决办法
  4. 确认使用的是支持的 5 种证件,并且身份证是中国大陆二代非民汉双文的。
  5. 调整拍摄环境,确保光线充足,证件平整,文字清晰,让证件完全处于取景框内,没有倾斜或超出边框。
  6. 检查页面布局,确保卡证识别控件所在的区域没有被其他组件遮挡,必要时可以让控件全屏显示。

5.3 问题 3:从相册选图识别失败

现象:点击相册图标,选择证件图片后,识别失败,没有返回信息。原因:可能是图片不符合要求,比如图片分辨率太低、证件在图片中占比太小、图片有旋转或变形等,导致 OCR 无法准确识别。解决办法:选择清晰、分辨率适中的证件图片,确保证件在图片中占比足够大,没有旋转、变形或遮挡,这样能提高识别成功率。

六、总结与扩展

通过本文的介绍,相信大家已经掌握了 HarmonyOS 卡证识别控件的开发方法,从场景了解、约束注意,到开发步骤和完整实例,每个环节都有详细的说明和代码,只要跟着操作,就能实现卡证识别功能。

6.1 开发总结

开发卡证识别功能,核心步骤就是导入相关类、配置控件参数(证件类型、拍摄模式等)、在回调中处理识别结果,最后根据需求显示或使用识别到的信息。需要特别注意的是,必须用真机测试,而且要确保控件不被遮挡,证件类型在支持范围内。

6.2 功能扩展

在实际项目中,还可以对卡证识别功能进行扩展,提升用户体验和功能完整性。比如:

  1. 增加识别 loading 提示:在点击拍摄或选择图片后,显示 loading 动画,告诉用户正在进行识别,避免用户以为没操作成功而重复点击。
  2. 信息校验:识别到证件信息后,对关键信息进行校验,比如身份证号可以校验位数和校验码是否正确,银行卡号可以校验格式是否正确,要是校验不通过,提示用户重新识别。
  3. 多证件切换:在实现页增加证件类型选择按钮,用户可以根据需要选择识别身份证、银行卡、护照等,不用每次都修改代码重新编译。
  4. 信息编辑:识别到的信息可能存在个别错误(比如识别错了一个数字),可以提供编辑功能,让用户修改错误的信息后再提交。

比如增加多证件切换功能,可以在 CardDemoPage 页面顶部加几个按钮,分别对应不同的证件类型,点击按钮时改变 supportType 的值,重新加载 CardRecognition 控件。代码大致如下:

// 在 CardDemoPage 的 build 方法中,添加证件类型选择按钮
Row({ space: 20 })
  .margin({ top: 20 })
  .justifyContent(FlexAlign.Center) {
    Button('身份证')
      .onClick(() => {
        this.currentCardType = CardType.CARD_ID;
        this.resetRecognition(); // 重置识别控件,重新加载
      });
    Button('银行卡')
      .onClick(() => {
        this.currentCardType = CardType.CARD_BANK;
        this.resetRecognition();
      });
    Button('护照')
      .onClick(() => {
        this.currentCardType = CardType.CARD_PASSPORT;
        this.resetRecognition();
      });
  }

// 然后在 CardRecognition 控件的 supportType 中使用 this.currentCardType
CardRecognition({
  supportType: this.currentCardType,
  // 其他参数...
})

这样用户就能在页面上自由切换要识别的证件类型,非常方便。

总之,HarmonyOS 的卡证识别控件功能强大,开发难度不大,只要掌握好本文讲的内容,就能轻松在项目中集成该功能,提升用户体验。大家可以根据自己的项目需求,对功能进行扩展和优化,让卡证识别功能更好地服务于应用。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐