接入前提
Demo 工程使用 Stage 模型:
根工程
modelVersion: 5.0.2entry 模块
apiType: stageModeDemo 产品
compatibleSdkVersion: 5.0.0(12)SDK HAR
compatibleSdkVersion: 12SDK HAR 包名:
kycnfcsdk埋点依赖 HAR 包名:
analytics建议业务工程使用 HarmonyOS API 12 及以上版本,并在真机上验证 NFC 能力。读卡流程需要设备支持 NFC,且系统 NFC 开关处于开启状态。
接入步骤
步骤1:SDK 文件和依赖配置
Demo 的 SDK 文件位于根目录
libs:libs/KycNfcSdk-v1.0.0-b3e74971.harlibs/WAAnalytics-2.3.4-ce3e09a.har
KycNfcSdk-v1.0.0-b3e74971.har 内部依赖 JLReaderD-1.1.5.har,并依赖 analytics@2.3.4。业务工程需要同时提供 WAAnalytics-2.3.4-ce3e09a.har,并保证 analytics 依赖解析到该本地 HAR。
根工程
oh-package.json5 增加 analytics override:{"modelVersion": "5.0.2","dependencies": {},"overrides": {"analytics": "file:./libs/WAAnalytics-2.3.4-ce3e09a.har"}}
entry 模块
entry/oh-package.json5 增加 SDK 依赖:{"name": "entry","version": "1.0.0","dependencies": {"kycnfcsdk": "file:../libs/KycNfcSdk-v1.0.0-b3e74971.har","analytics": "file:../libs/WAAnalytics-2.3.4-ce3e09a.har"}}
配置完成后执行依赖同步或
ohpm install。依赖锁中应能看到:kycnfcsdk@1.0.0analytics@2.3.4jlreader@1.1.5libjlreader.so步骤2:module.json5 配置
2.1 网络权限
Demo 的 entry 模块显式声明了网络权限:
"requestPermissions": [{ "name": "ohos.permission.INTERNET" }]
SDK HAR 自身声明了:
[{ "name": "ohos.permission.INTERNET" },{ "name": "ohos.permission.GET_NETWORK_INFO" },{ "name": "ohos.permission.SET_NETWORK_INFO" },{ "name": "ohos.permission.NFC_TAG" }]
外部工程接入时,entry 模块至少保留
ohos.permission.INTERNET。如果业务工程的权限合并或合规扫描要求所有权限必须在 entry 模块显式出现,请同步确认 SDK HAR 中声明的网络/NFC 权限没有被裁剪。2.2 NFC Tag 分发配置
承载 NFC 流程的
UIAbility 需要配置 ohos.nfc.tag.action.TAG_FOUND,并声明 SDK 需要识别的 Tag 技术类型:NfcB、IsoDep。
核心新增配置如下:
{"module": {"abilities": [{"name": "EntryAbility","exported": true,"skills": [{"actions": ["ohos.nfc.tag.action.TAG_FOUND"],"uris": [{ "type": "tag-tech/NfcB" },{ "type": "tag-tech/IsoDep" }]}]}]}}
如果该 Ability 同时作为桌面入口,保留原有的
entity.system.home 和 action.system.home 配置。Demo 将桌面入口 action 与 NFC TAG_FOUND action 放在同一个 skill 中。步骤3:EntryAbility 必须初始化 JLElementName
注意:
该配置为必接项,不是可选配置。
SDK 底层读卡能力需要当前 Ability 的
ElementName。必须在 EntryAbility.onCreate() 中初始化,否则 NFC 前台分发注册会失败。import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';import { JLElementName } from 'kycnfcsdk';export default class EntryAbility extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {JLElementName.elementName = {bundleName: want.bundleName as string,abilityName: want.abilityName as string,moduleName: want.moduleName as string};}}
步骤4:SDK 初始化参数
业务侧通过
NfcInitDataMap 向 SDK 传入初始化参数。Demo 使用的核心类型如下:import {InputData,NfcInitDataMap,WbCloudNfcSDK} from 'kycnfcsdk';
4.1 InputData 构造参数
SDK 导出的
InputData 字段:参数 | 说明 | 类型 | 长度 | 是否必填 |
orderNo | 订单号 | String | 32 | 必填,合作方订单的唯一标识,字母/数字组成的字符串 |
openApiAppId | String | 8 | 必填 | |
openApiAppVersion | 接口版本号 | String | 20 | 必填,默认填 1.0.0 |
openApiNonce | 32位随机字符串 | String | 32 | 必填,每次请求需要的一次性 nonce |
openApiUserId | User Id | String | 30 | 必填,每个用户唯一的标识 |
openApiSign | 合作方后台服务器通过 ticket 计算出来的签名信息 | String | 40 | 必填 |
openApiOcrCertId | 合作方后台服务器通过 ticket 计算出来的 ocrCertId | String | 40 | 必填 |
构造顺序必须与 Demo 一致:
const inputData = new InputData(orderNo,openApiAppId,openApiAppVersion,openApiNonce,openApiUserId,openApiSign,ocrCertId);
4.2 初始化 Map
import {InputData,NfcInitDataMap,TRAVEL_CARD_BIRTH,TRAVEL_CARD_NO,TRAVEL_CARD_VALIDATE,WbCloudNfcSDK} from 'kycnfcsdk';const data: NfcInitDataMap = {};data[WbCloudNfcSDK.INPUT_DATA] = new InputData(orderNo,openApiAppId,openApiAppVersion,openApiNonce,openApiUserId,openApiSign,ocrCertId);// 单位:毫秒。Demo 传入 20000。data[WbCloudNfcSDK.NFC_TIME] = 20000;// Demo 中:'1' 表示身份证;'3' 表示回乡证/旅行证件类流程。data[WbCloudNfcSDK.NFC_TYPE] = nfcType;if (nfcType === '3') {data[TRAVEL_CARD_NO] = travelCardNo;data[TRAVEL_CARD_BIRTH] = travelBirth;data[TRAVEL_CARD_VALIDATE] = travelValidate;}
Demo 也直接使用过以下字符串 key:
data.travel_card_no = travelCardNo;data.travel_card_birth = travelBirth;data.travel_card_validate = travelValidate;
外部接入建议优先使用 SDK 导出的常量,避免后续 SDK 升级时 key 发生变化。
4.3 初始化调用
import common from '@ohos.app.ability.common';import {NfcLoginListener,WbCloudNfcSDK} from 'kycnfcsdk';class LoginListener implements NfcLoginListener {onLoginSuccess(): void {// 初始化和 SDK 登录成功后,再启动读卡。}onLoginFailed(errorCode: string, errorMsg: string): void {// 初始化失败,业务侧提示或上报。}}const context = getContext() as common.UIAbilityContext;WbCloudNfcSDK.getInstance().init(context, data, new LoginListener());
init() 完成后会通过 NfcLoginListener 返回结果。只有收到 onLoginSuccess() 后才调用读卡接口。步骤5:SDK 读卡调用
带 UI 模式由 SDK 展示内置 NFC 引导、协议、读卡和完成页面。业务侧只需要在
init() 成功后调用 startActivityForNfc()。import common from '@ohos.app.ability.common';import {NfcResultListener,WBNfcResult,WbCloudNfcSDK} from 'kycnfcsdk';class ResultListener implements NfcResultListener {onFinish(result: WBNfcResult): void {if (result.code === '0') {// 读卡成功。可使用 result.reqId/orderNo 查询最终业务结果。return;}// 读卡失败或取消。展示 result.message,并按业务需要上报。}}const context = getContext() as common.UIAbilityContext;WbCloudNfcSDK.getInstance().startActivityForNfc(context, new ResultListener());
注意:
不要在一次识别未结束时重复调用
startActivityForNfc()。SDK 内部会拦截重复调用。如果业务需要重试,等待
onFinish() 回调后重新走初始化/启动流程;SDK 也导出了 resetCanDoNfcSdkRecognise() 用于重置识别状态。生产环境建议关闭 SDK 内部日志,见“可选配置项”。
步骤6:结果回调和结果查询
6.1 WBNfcResult
SDK 通过
NfcResultListener.onFinish() 或 NfcResultWithStateListener.onFinish() 回调 WBNfcResult。参数 | 说明 |
type | NFC 类型,Demo 使用 '1'、'3' |
code | SDK 结果码,Demo 以 '0' 判断成功 |
message | 结果描述 |
orderNo | 业务订单号 |
ocrCertId | OCR/NFC 凭证 ID |
reqId | 本次请求 ID,后续查询结果使用 |
guidePageTime | SDK 引导页耗时 |
nfcPreDoTime | NFC 前置处理耗时 |
nfcDetectTime | NFC 检测耗时 |
netRequestTime | 网络请求耗时 |
端侧读卡成功不等于业务已经拿到全部证件信息。业务侧通常需要使用
appId、nonce、reqId、orderNo 到服务端查询最终结果。6.2 Demo 中的签名接口
Demo 为了演示,在端侧直接请求:
GET https://kyc1.qcloud.com/ems-partner/cert/nfc/getocrcertid
请求参数:
参数 | 说明 |
appId | OpenAPI AppId |
nonce | 随机串 |
userId | 用户 ID |
orderNo | 订单号 |
nfcType | NFC 类型 |
Demo 期望返回:
class SignResponse {sign: string = '';ocrCertId: string = '';code: string = '';msg: string = '';}
生产接入建议由业务后端负责签名和敏感参数处理,端侧只接收启动 SDK 所需的
sign、ocrCertId 等参数。6.3 Demo 中的结果查询接口
Demo 读卡成功后请求:
GET https://kyc1.qcloud.com/ems-partner/cert/nfc/queryrecord
请求参数:
参数 | 说明 |
appId | OpenAPI AppId |
nonce | 随机串 |
reqId | SDK 回调中的 result.reqId |
orderNo | 业务订单号 |
Demo 解析的主要结果字段:
字段 | 说明 |
code / msg | 查询接口结果 |
reqId / orderNo | 请求 ID 和订单号 |
name / enName | 姓名/英文名 |
sex / nation / birth | 性别、民族、出生日期 |
address | 地址 |
idcard | 证件号 |
signingOrganization | 签发机关 |
validDateBegin / validDateEnd | 有效期 |
frontPhoto / backPhoto / portraitPhoto | 图片 Base64 或 data URL |
结果查询接口不是端侧 SDK 的公共 API,实际生产方案以业务方服务端和腾讯云接口约定为准。
步骤7:可选配置项
SDK 导出配置单例
WbCloudNfcConfig:import { WbCloudNfcConfig } from 'kycnfcsdk';const config = WbCloudNfcConfig.getInstance();// 是否使用 SIT 环境。生产环境不要打开。config.setSitEnv(false);// 是否打开 SDK 内部日志。Demo 打开;生产环境建议 false。config.setEnableLog(false);
SDK 还导出以下配置方法:
方法 | 说明 |
setIpv6(boolean) / isIpv6() | IPv6 相关配置 |
setRetCrop(boolean) / isRetCrop() | 裁剪结果相关配置 |
setWbUrl(boolean) / isWbUrl() | URL 相关配置 |
setCheckWarnings(boolean) / isCheckWarnings() | 告警检查相关配置 |
Demo 未使用这些扩展配置。外部接入如需启用,应以 SDK 版本说明或商务/服务端配置要求为准。
NFC 能力检测
SDK 导出:
const availability = WbCloudNfcSDK.getInstance().getNfcAvailability();
返回结构:
interface NfcAvailabilityState {status: NfcAvailabilityStatus; // ready / unsupported / disabledcode: string;message: string;canRead: boolean;}
无 UI 模式建议在启动
enableReaderMode() 前检测 canRead。带 UI 模式下 SDK 内部会处理 NFC 不支持或未开启等状态,但业务侧仍可提前检测并做自定义提示。步骤8:混淆配置
Demo 当前
entry/obfuscation-rules.txt 已开启 release 混淆,配置如下:-enable-property-obfuscation-enable-toplevel-obfuscation-enable-filename-obfuscation-enable-export-obfuscation
当前 Demo 未额外配置
-keep-* 规则。外部工程可以先按上述配置验证 release 包;如果业务工程还有自定义反射、动态字段访问、运行时按字符串调用方法、JSON 字段直接映射、router routeName 等场景,请按业务代码实际情况补充 keep 规则。
重点关注以下跨运行时边界:
SDK 回调方法:
onLoginSuccess、onLoginFailed、onFinish、onTagDiscovered、onStartJLElementName 相关字段:elementName、bundleName、abilityName、moduleNameSDK 初始化和结果字段:
INPUT_DATA、NFC_TIME、NFC_TYPE、orderNo、appId、nonce、userId、sign、ocrCertId、reqId、type、code、message回乡证参数字段:
TRAVEL_CARD_NO、TRAVEL_CARD_BIRTH、TRAVEL_CARD_VALIDATE、travel_card_no、travel_card_birth、travel_card_validate业务结果查询 JSON 字段:
result、data、name、sex、nation、birth、address、idcard、frontPhoto、backPhoto、portraitPhoto 等步骤9:接入验证清单
接入完成后按以下顺序验证:
1.
ohpm install 或 DevEco 依赖同步成功。2. entry 模块可以正常 import:
import { WbCloudNfcSDK, InputData } from 'kycnfcsdk';
3. HAP 构建成功,未出现
kycnfcsdk、analytics、jlreader、libjlreader.so 解析失败。4.
EntryAbility.onCreate() 已设置 JLElementName.elementName。5.
module.json5 中 NFC TAG_FOUND skill 包含 tag-tech/NfcB 和 tag-tech/IsoDep。6. 真机 NFC 已开启,设备支持 NFC。
7. 业务后端能返回有效
sign 和 ocrCertId。8.
init() 能回调 onLoginSuccess()。9. 带 UI 模式能进入 SDK 页面并最终回调
onFinish();无 UI 模式能收到 onTagDiscovered()、onStart()、onFinish()。10. 成功时
WBNfcResult.code === '0',并能使用 reqId、orderNo 查询业务结果。11. release 包开启混淆后仍能正常回调,字段未被混淆破坏。
常见问题排查
init() 失败
检查:
InputData 构造参数顺序是否正确。sign、ocrCertId 是否为空。appId、nonce、userId、orderNo 是否与服务端签名一致。网络权限和网络连通性是否正常。
setSitEnv() 是否错误地指向了非目标环境。无法检测到 NFC 卡片
检查:
真机是否支持 NFC,系统 NFC 开关是否打开。
module.json5 是否配置 ohos.nfc.tag.action.TAG_FOUND。uris 是否包含 tag-tech/NfcB 和 tag-tech/IsoDep。JLElementName.elementName 是否在 EntryAbility.onCreate() 中初始化。无 UI 模式页面隐藏或后台时是否过早调用了
disableReaderMode()。日志出现 reader elementName 缺失或前台分发注册失败
优先检查
EntryAbility.onCreate() 中的:JLElementName.elementName = {bundleName: want.bundleName as string,abilityName: want.abilityName as string,moduleName: want.moduleName as string};
该配置缺失会导致底层 SDK NFC 注册失败。
带 UI 模式重复调用无反应
SDK 会防止一次识别流程中重复调用
startActivityForNfc()。等待 onFinish() 后再发起下一次识别;必要时调用:WbCloudNfcSDK.getInstance().resetCanDoNfcSdkRecognise();
release 包回调方法不执行
优先确认 release 包使用的混淆规则是否与 Demo 一致。若业务工程在 Demo 配置之外增加了更严格的混淆,或存在按字符串调用回调方法的代码,再补充
-keep-property-name 保留 onLoginSuccess、onLoginFailed、onFinish、onTagDiscovered、onStart 等回调名。结果页查不到证件信息
SDK 的
onFinish() 返回的是 NFC 读卡流程结果。证件详情需要通过服务端结果查询接口获取。请确认:result.code === '0'result.reqId 非空查询时使用的
appId、nonce、orderNo 与启动 SDK 时一致查询接口环境与 SDK 登录环境一致