对接调试一共分为两部分,一部分为安卓应用对接的SDK,另一部分为应用服务器与商米服务器直接的云对接API。
应用软件集成身份证识别sdk,应用软件后端服务器集成云端api(集成云端api用于保护用户身份信息,保证整个数据链路中,只有应用软件可获取身份证明文信息)
1、终端发起身份证请求,并发送身份证卡片信息到应用软件后台服务器
2、服务器验证卡片真伪,如果为真,返回reqid
3、应用软件收到reqid后,把reqid发送给应用后台服务器
4、应用后台服务器通过openapi把数据发送给商米服务器
5、商米服务器向解码服务器请求解析身份证信息
6、身份证解码服务器返回身份证全部信息的加密数据
7、商米服务器将加密数据返回应用软件后台服务器
8、应用软件服务器解密加密数据后,得到身份证明文数据
9、将明文数据返回应用软件
注:身份证云识别依赖网络,要求每次网络交互过程不得超过200ms,数据交互延迟高于110ms会降低解码成功率(sdk返回9100X错误),高于200ms会造成读卡失败。使用前请确定网络环境满足要求,sdk提供了延迟检测接口,用户可使用延迟检测接口测试网络。不建议使用物联网卡。
1、APP设计和开发
APP设计
APP设计注意要点:android NFC或者读卡器识别到卡片后会有声音提示,身份证读卡操作是个耗时操作,当声音提示后,不能直接拿走卡片,需要等到读卡成功或者失败再拿开卡片。界面上需要提示用户在有明确反馈前不要拿走卡片,建议:loading+文字提示
APP开发
身份证云识别的Android SDK 的集成、初始化、使用流程、网络延迟检测等。
应用发布前,请确保现场网络环境已达要求,否则将影响识别成功率。
1.1、集成
- 资源文件(AAR文件)
note:v1.1.1版本已经弃用,请用最新版本
1.2、导入AAR包
- 打开项目后:File -> New -> New Module…
- 在新的对话框:New Module -> Import .JAR/.AAR Package -> Next
- 下一步:Import Module from Library -> 选择 aar 文件夹下的 SunmiEID-SDK_vX.X.X-release/tes.aar 文件 -> Finish
- 完成:
1.3、app 模块引用
- 点击-打开模块设置:
- 设置对话框:选择“app” -> 点击“+”号 -> 选择“Module Dependency”
- 显示:勾选上对应的模块(SunmiEID-SDK_vX.X.X-release/tes)-> 点击“OK”,相关SDK引用成功。
1.4、接口文档
1.4.1、初始化
- 推荐在Application实现SDK初始化实现:
public class IApp extends Application implements EidCall {
@Override
public void onCreate() {
super.onCreate();
try {
EidSDK.init(this, "appid", this);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onTerminate() {
super.onTerminate();
EidSDK.destroy();
}
@Override
public void onCallData(int code, String msg) {
Log.d("app", "onCallData: code:" + code + ", msg:" + msg);
}
}
1.4.2、获取 EidReader 实例
private void initEidReader() {
Log.d("Eid", String.format("商米SDK.Ver:%s, 读卡模块Ver:%s", EidSDK.getSunmiEidSDKVersion(), EidSDK.getEidSDKVersion()));
EidPic.init(this, fileNameBase);
eid = EidSDK.getEidReaderForNfc(1, this);
}
1.4.3、实现 EidCall 接口
@Override
public void onCallData(int code, String msg) {
switch (code) {
case EidConstants.READ_CARD_START:
mState.setText("开始读卡,请勿移动");
Log.i(TAG, "开始读卡,请勿移动");
break;
case EidConstants.READ_CARD_SUCCESS:
closeNFCReader();//电子身份证需要关闭
Log.e("TAG", String.format(Locale.getDefault(), "正在获取身份信息(%s),请稍等.....", msg));
mState.setText(String.format(Locale.getDefault(), "正在获取身份信息(%s),请稍等.....", msg));
File file = new File(fileNameBase, "zp.bmp");
if (file.exists()) {
file.deleteOnExit();
}
getIDCardInfo(msg); //通过card_id请求识读卡片的信息
break;
case EidConstants.READ_CARD_FAILED:
closeNFCReader();//电子身份证需要关闭
Log.i(TAG, String.format(Locale.getDefault(), "读卡错误,请重新贴卡:%s", msg));
mState.setText(String.format(Locale.getDefault(), "读卡错误,请重新贴卡:%s", msg));
break;
case EidConstants.READ_CARD_DELAY:
Log.e("TAG", String.format(Locale.getDefault(), "延迟 %sms", msg));
mState.setText(String.format(Locale.getDefault(), "延迟 %sms", msg));
break;
default:
break;
}
}
1.4.4、调用NFC识读卡片
- 识读身份证:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
eid.nfcReadCard(intent);
}
- 识读电子身份证:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
try {
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
try {
isodep = IsoDep.get(tagFromIntent);
isodep.connect();
if (isodep.isConnected()) {
eid.readCard(IDCardType.ECCARD, new EidReadCardCallBack() {
@Override
public byte[] transceiveTypeB(byte[] data) {
return data;
}
@Override
public byte[] transceiveTypeA(byte[] data) {
byte[] outData = new byte[data.length];
try {
outData = isodep.transceive(data);
} catch (Exception e) {
e.printStackTrace();
}
return outData;
}
});
} else {
closeNFCReader()
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void closeNFCReader() {
if (isodep != null) {
try {
isodep.close();
isodep = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.5、参考DEMO
注:金融机的NFC功能非安卓标准NFC,需要调用金融SDK进行非接读卡。具体可参考DEMO中的金融读卡内容。
商米提供了2种不同路径的调用方式:EidCardDemo-OpenApi为端对云的方式,安装apk后输入对应appid和key就可以直接读取身份信息。好处是集成方便,数据路径较短。坏处是安全性没有第二种高。
EidCardDemo为端对云对云的方式,好处是安全性高,坏处是路径较长。
- 详细处理参考:EidCardDemo (安卓应用首先访问应用服务器,应用服务器通过商米Open Api访问商米服务器进行身份证读取)
- 直连商米 Open Api 接口:EidCardDemo-OpenApi (直连商米open api服务器即安卓应用直接访问商米服务器进行身份证读取。该用法可能会导致appid与appkey同时泄漏,造成损失将由应用商自己承担)
1.6、详细接口说明
- 详细接口文档:
1.7、错误码ErrorCode
2、身份证服务 API 接口
2.1、公共参数说明
2.1.1、概要
请求域名:https://openapi.sunmi.com
openapi的sdk:
golang 版本:https://github.com/sunmi-OS/sunmi-openapi-go-sdk
- 商米身份证服务的接口采用 HTTPS 协议
- 请求方式统一使用 POST
- 请求数据格式为 application/json
2.1.2、公共header说明
- 请求必传header
请求公共参数
参数名 | 类型 | 说明 |
Sunmi-Timestamp | Integer | 当前时间戳 |
Sunmi-Sign | string | 签名内容 |
Sunmi-Nonce | Integer | 6位随机数 |
Sunmi-Appid | string | 申请的APPID |
返回公共参数
参数名 | 类型 | 说明 |
code | Integer | 返回码,参见公共错误码 |
data | object | 正常返回,如有错误不返回 |
msg | string | 错误提示信息,如有错误此字段返回错误描述 |
2.1.3、签名生成说明
签名算法:hmac256
签名生成方式:
1、拼接stringA(即 stringA=json-body + Sunmi-Appid + Sunmi-Timestamp + Sunmi-Nonce)
2、获取申请的AppKey作为hmac256算法的密钥key
3、最后进行 hmac256(
stringA, Appkey)
最终获取到sign值
2.1.4、公共错误码
返回码 | 说明 |
1 | 成功返回 |
20000 | 网关校验缺少参数 |
20001 | 请求超过有效期 |
30000 | 开发者身份验证失败 |
30001 | 开发者权限不足 |
40000 | 签名验证失败 |
40001 | 签名失败 |
50000 | 服务器异常 |
50001 | 网关异常 |
2.2、身份证云识别接口
- 接口地址:/v2/eid/eid/idcard/decode
- 请求方式:POST
2.2.1、请求参数
参数名 | 类型 | 说明 |
request_id | string | android端生成的 request_id |
encrypt_factor | string | 加密因子(8 位大小写字母和数字组成的的随机字符串,建议每次访问随机生成) |
2.2.2、返回参数
成功返回
参数名 | 类型 | 说明 |
code | string | 返回码,参见常用错误码表 |
data | object | 返回身份证信息,参见下方 data 域内容 |
msg | string | 错误提示信息,如有错误此字段返回错误描述 |
成功返回 data 域内容
参数名 | 类型 | 说明 |
info | string | 身份证信息密文,解密方式参见解密说明 |
示例:
{
"code": 1,
"data": {
"info": "xxxxxxxxxxxxx"
},
"msg": ""
}
失败返回
参数名 | 类型 | 说明 |
code | Integer | 返回码,参见常见业务错误码 |
data | string | 空字符串 |
msg | string | 错误提示信息,如有错误此字段返回错误描述 |
{
"code": 20000,
"data": "",
"msg": "Missing required parameters"
}
2.2.3、解密说明
- 加密方式:DES_CBC_PKCS5Padding 加密
- 加密因子:传入的 encrypt_factor
- 加密key:开发者平台申请的AppKey
解密流程:
- 对 info 字符串 base64 解码(standard 标准解码),解码完为 stringA
- 对 stringA 字符串进行 des 解密,截取AppKey前8位作为秘钥key,向量 iv 作为 encrypt_factor 加密因子,解密完为 stringB
- stringB 即是身份证信息的 json 格式,内容参见下方身份证云解码信息
身份证云解码信息:
参数名 | 类型 | 说明 |
base_info | object | 身份证基础信息,参见下方身份证基础信息说明 |
dn | string | 指纹信息 |
picture | string | 身份证头像照片 |
appeidcode | string | 应用网络身份标记,同一个身份有一个编码 |
身份证基础信息:
参数名 | 类型 | 说明 |
name | string | 姓名 |
nation | string | 民族(如:汉) |
sex | string | 性别(如:男) |
idnum | string | 身份证号码 |
idType | string | 证件类型,见下方证件类型说明 |
birthDate | string | 出生年月日(如:20010305) |
address | string | 身份证住址 |
beginTime | string | 身份证有效期限开始时间(如:20180305) |
endTime | string | 身份证有效期限结束时间(如:20180305) |
signingOrganization | string | 签发机关 |
示例:
"base_info": {
"address": "xx省xx市xxxx路xx号",
"beginTime": "20180305",
"endTime": "20180305",
"birthDate": "20010305",
"idType": "01",
"idnum": "xxxxxxx",
"name": "孙小红",
"nation": "汉",
"sex": "男",
"signingOrganization": "xx市xx公安局"
},
"dn": "xxxxxxxxxx",
"picture": "xxxxxxxxx",
"appeidcode": "xxxxxxxxx",
2.2.4、常见业务错误码
返回码 | 说明 |
50000 | 服务器异常 |
14200 | 没有权限 |
14201 | sdk版本过低 |
14202 | 无可使用次数 |
14203 | 读卡错误 |
14204 | 参数异常 |