搜索
开发文档
应用开发
快应用开发
小游戏开发
开发文档/应用开发/服务能力/钱包服务/CCC车钥匙接入指南
CCC车钥匙接入指南更新时间: 2024-10-23 15:42:00

概述

小米数字车钥匙是依托小米智能卡平台的数字车钥匙集成方案,实现将车钥匙装入智能设备。

相较于传统的车钥匙,小米数字车钥匙无需实体车钥匙,将车钥匙功能集成在移动智能终端设备(手机+穿戴),基于SE、TEE等安全功能,使用NFC、蓝牙、UWB等技术连接手机和车,可实现车辆的开门、启动、远程车控、朋友分享等功能。

流程概览

步骤 分类 内容 用途说明
1 接入准备 测试手机及环境准备 联调用测试手机刷机
测试账号及VPN账号通过上述方法,不需要申请VPN账号,但需要小米配置IP白名单,以及需要在合作方处做一些其他配置工作
证书交换 数字钥匙证书信任链
服务器通信安全性验证
测试环境相关配置申请 用于车厂关于车钥匙功能的访问权限控制
2 相关文档及软件包下载 接口文档 用于开发联调的接口说明,包括客户端接口和服务端接口文档
小米数字钥匙框架
小米智能卡
应用及SDK输出文档
小米智能卡网页组件
应用及SDK输出文档
SDK
应用及SDK输出文档
用于车企app集成车钥匙功能,签署保密协议后,可查看
3 功能实现(系统联调) 整体架构
钥匙开通
认证交互
钥匙查询
钥匙删除
钥匙分享
远程车控
特殊场景说明 关于设备挂失、退出账号、恢复出厂设置等场景钥匙处理说明
车端读卡器要求
常见问题 联调过程中常见问题说明
4 UI设计 UI流程 数字车钥匙各功能模块在小米钱包内的开通流程
相关素材要求 车端相关元素在钱包内展示要求
5 测试验收 验收流程
功能测试
性能测试
6 生产上线 生产证书交换
上线申请及配置 上线流程及相关配置内容
7 新机上线 新机测试上线流程 新机的上线流程说明
8 存量机适配 存量机型适配流程 存量机适配流程

一、接入准备

1、测试手机及环境准备

联调阶段的测试手机,需要对手机进行解锁、刷机、安装系统等操作,一般来说, 小米近2年内发布的NFC手机可以用于WCC2功能联调, UWB手机可以用于WCC3功能联调。

车厂可以自行采购测试手机,并寄给小米刷机。手机采购或邮寄前, 请与小米相关人员确认手机型号是否支持CCC车钥匙。

注:测试手机刷机后, 与小米NFC卡片(公交卡/银行卡/门卡/车钥匙/校园卡等)相关的业务不能在生产环境下使用,手机其它功能不受影响。

2、测试环境小米账号和小米VPN账号

小米VPN账号

车钥匙联调过程中, 测试手机必须通过VPN网络接入小米测试环境, 因此要在测试手机上安装VPN软件。 VPN账号申请和使用方法如下:

1、发送VPN账号申请邮件至did-carkey@xiaomi.com,内容包括申请原因,申请人姓名、邮箱和手机号。中国籍申请人需要提供中文姓名。

2、收到VPN账号开通短信后,通过手机短信实名认证,并设置密码后即可使用。

3、扫码下载APP(小米飞兔),登录后可以一键链接VPN。

上传文件

测试手机必须登录测试小米账号才能使用数字钥匙功能,发送测试小米账号申请邮件至did-carkey@xiaomi.com,内容包括申请原因,申请人姓名、邮箱和手机号。

手机连上VPN网络后, 在手机“设置-登录小米账号”页面,使用测试小米账号和密码登录。

多台测试手机可以共用一个测试账号。

3、证书交换

1、车厂发起证书交换申请, 邮件发送至 did-carkey@xiaomi.com

2、小米发送Device OEM CA Certificate 的CSR文件给车厂,车厂签署 [F] - Device OEM CA Certificate (Signed by Vehicle OEM)

3、车厂回复以下证书给小米

  • [F] Device OEM CA Certificate (Signed by Vehicle OEM)
  • [J] Vehicle OEM CA Certificate
  • [P] Vehicle OEM Privacy Encryption Certificate
  • [Q] Vehicle OEM Signature Key Certificate

同时提供以下车厂ID信息。

Vehicle OEM Vehicle Brand Vehicle OEM Identifier Vehicle Brand Name Vehicle Brand Identifier

小米服务器和车服务器都需要支持双向SSL认证,以保证双方通信时数据安全可靠

1、小米发送小米侧SSL Client Certificate的CSR文件给车厂,由车厂签发

2、车厂提供车厂侧SSL Client Certificate的CSR文件给小米,由小米签发

证书交换过程中,证书文件均需要加密,秘钥与证书文件分不同渠道发送

二、功能实现

小米数字车钥匙满足CCC规范中对手机的技术要求,下面的内容将帮助开发者了解如何快速接入小米CCC数字车钥匙服务。

1、架构

CCC车钥匙架构如下

上传文件

CCC车钥匙架构中的每个节点各自都发挥着不同作用,他们职责明确并相互连接,从而支撑起整个数字车钥匙系统

按照角色划分如下

1、车

负责管理车端证书和钥匙数据

实现NFC、蓝牙、UWB模块的相关功能,如配对、开关车门、启动引擎等

2、车服务器

负责管理车服务器证书

记录并管理钥匙生命周期

建立与车端的通信连接并下发命令

3、设备(手机)

Native App:手机厂商的数字车钥匙应用,一般指手机钱包App

车App:汽车厂商的数字车钥匙应用

DKF:

负责管理设备和钥匙的证书信息

负责管理SE中的钥匙数据

实现和车端通信的能力,包括NFC、蓝牙、UWB

将如上的能力暴露接口供Native App和车App使用

4、设备服务器

负责安装和管理SE中的CCC Applet

负责和车服务器进行对接,接收钥匙事件通知并执行和钥匙有关的操作,例如云端删除

记录并管理设备中钥匙的生命周期,例如云端挂失

5、Relay Server

由设备厂商或者第三方厂商提供,实现跨品牌的钥匙分享能力

2、开发准备

双向SSL证书互签

小米与车服务器采用双向SSL方式进行安全通信,汽车厂商需要提供通信证书链,小米会对其进行信任配置

车服务器SSL证书到期更换前,需要将新证书链发送小米进行配置

交换云端地址

小米服务器接口地址如下

API类型 测试环境URL 生产环境URL
Health Check API https://staging3-sp-server.tsm.pay.xiaomi.com/ccc/v1/healthcheck https://sp-server.tsm.pay.xiaomi.com/ccc/v1/healthcheck
Manage Key API https://staging3-sp-server.tsm.pay.xiaomi.com/ccc/v1/manageKey https://sp-server.tsm.pay.xiaomi.com/ccc/v1/manageKey
Event Notification API https://staging3-sp-server.tsm.pay.xiaomi.com/ccc/v1/eventNotification https://sp-server.tsm.pay.xiaomi.com/ccc/v1/eventNotification

车服务器需要提供如下API给小米(did-carkey@xiaomi.com),车服务器的接口使用说明参考:“小米请求车服务器接口说明.pdf”(签署协议后可查看)

API类型 测试环境URL 生产环境URL
Health Check API
Track Key API
Manage Key API

3、功能开发

CCC车钥匙主要包括了如下使用场景:钥匙开通、钥匙查询、钥匙删除、刷卡使用、钥匙分享、远程车控

开发者需要实现各个场景下的相关功能,从而串起整个车钥匙业务

功能开发准备,向小米申请SDK服务访问权限,需要提供的信息:应用包名,应用SHA1签名

3.1、钥匙开通

3.1.1、钥匙开通

遵循CCC协议数字车钥匙添加方式有三种:从小米智能卡侧发起添加、从车厂App发起开通、从车端Reader发起开通(可选)

  • 从钱包侧发起开通

从钱包主页面车钥匙入口进入开通流程,参考UI流程

  • 从车厂App发起开通
上传文件

调用createDigitalKey接口将拉起NativeApp(Wallet)的钥匙开通页面,待钥匙开通完成,将返回车辆OEMApp页面。

接口调用步骤为:getInstance->isSupportedByDevice->getWirelessCapabilities(可选)->isCreateDigitalKeyPossible->createDigitalKey

具体见《DKF_SDK_API_20230404(外部修正版)》第3.3节

钥匙信息DigitalKeyData,具体见《DKF_SDK_API_20230404(外部修正版)》第3.4.2节中DigitalKeyData

签署保密协议后,可查看上述文档。

  • 从车端Reader发起开通

将小米手机放置在开通数字车钥匙的控制台上,手机中弹出提示弹窗,按照步骤操作即可,具体支持情况以车厂为主

3.1.2、配对流程

配对流程指设备与车端进行认证以及数据交换的过程,具体内容可以参考CCC数字车钥匙规范

3.1.3、云端注册钥匙

当配对流程完成后,设备会发送钥匙注册请求,通过Track Key API将钥匙数据注册到车服务器

代码示例

@PostMapping("/ccc/v1/trackKey") 
public Map<String, Object> trackKey(@RequestHeader("x-device-oemId") String deviceOemId, @RequestBody Map<String, Object> param) {
// 加密证书链
List<String> encryptionCertChain = (List<String>) param.get("encryptionCertChain");
String encryptionVersion = String.valueOf(param.get("encryptionVersion"));
// 车主钥匙信息
String keyId = String.valueOf(param.get("keyID"));
String keyType = String.valueOf(param.get("keyType"));
String deviceType = String.valueOf(param.get("deviceType"));
String accountIdHash = String.valueOf(param.get("accountIdHash"));
// 车主钥匙数据
Map<String, Object> keyData = (Map<String, Object>) param.get("keyData");
String version = String.valueOf(keyData.get("version"));
String ephemeralPublicKey = String.valueOf(keyData.get("ephemeralPublicKey"));
String data = String.valueOf(keyData.get("data"));

// 解密keyData
byte[] keyDataBytes = ECIES.decrypt(version, Hex.decodeHex(ephemeralPublicKey.toCharArray()), Base64.getDecoder().decode(data));

// 验证钥匙信息
verifyKeyData(keyDataBytes);

// 记录钥匙信息
recordKeyToKts(deviceOemId, keyId, keyType, deviceType, accountIdHash, keyDataBytes);

// 加密uiBundle
String uiBundleData = getUiBundleData(keyId);
Map<String, Object> encryptedUiBundle = ECIES.encrypt(uiBundleData, encryptionVersion, encryptionCertChain);

// 加密vehicleMobilizationData
String vehicleMobilizationData = getVehicleMobilizationData(keyId);
Map<String, Object> encryptedVehicleMobilizationData = ECIES.encrypt(vehicleMobilizationData);

// 返回数据
Map<String, Object> responseHeader = new HashMap<>();
responseHeader.put("statusCode", "200");
Map<String, Object> response = new HashMap<>();
response.put("responseHeader", responseHeader);
response.put("uiBundle", encryptedUiBundle);
response.put("vehicleMobilizationData", encryptedVehicleMobilizationData);
response.put("brand", "abc");
response.put("model", "xyz");
return response;
}

3.1.4、钥匙激活

对于车主侧钥匙处于未激活状态,如何进行激活,需要使用钥匙进行引擎激活

3.2、钥匙查询

从小米服务获取已经开通所有钥匙以及钥匙信息

上传文件

1、获取车厂已经开通的全部钥匙ID

2、通过钥匙ID获取钥匙的详细信息

3.3、钥匙删除

1、从车App发起删除钥匙流程

调用terminateDigitalKey接口

上传文件

钥匙删除成功后,设备会将删除凭证发送至车服务器,开发者需要实现Manage Key API,校验钥匙的删除凭证并通知车端删除该钥匙

代码示例

@PostMapping("/ccc/v1/manageKey") 
public Map<String, Object> manageKey(@RequestHeader("x-device-oemId") String deviceOemId, @RequestBody Map<String, Object> param) {
String keyId = String.valueOf(param.get("keyID"));
String action = String.valueOf(param.get("action"));
String terminationAttestation = String.valueOf(param.get("terminationAttestation"));
String vehicleOEMProprietaryData = String.valueOf(param.get("vehicleOEMProprietaryData"));

ManageKeyAction manageKeyAction = ManageKeyAction.valueOf(action);
// 本地删除钥匙
if (ManageKeyAction.TERMINATE == manageKeyAction && StringUtils.isNotEmpty(terminationAttestation)) {
// 验证钥匙删除凭证
verifyTerminationAttestation(keyId, terminationAttestation);

// 标记钥匙状态
updateKeyStatus(keyId, DigitalKeyStatus.TERMINATED);

// 通知车端删除钥匙
deleteKeyInVehicle(keyId);
}

// 返回数据
Map<String, Object> responseHeader = new HashMap<>();
responseHeader.put("statusCode", "200");
Map<String, Object> response = new HashMap<>();
response.put("responseHeader", responseHeader);
return response;
}

从钱包侧发起删除钥匙流程

流程同车App发起删除,仅发起路径不同

从车/车服务器发起的删除钥匙流程

此流程是通过云端接口远程删除设备上的车钥匙,车服务器需要分别调用小米服务器的Event Notification API和

Manage Key API进行删除请求

代码示例

public void keyTerminationEventNotification(String keyId, String keyValidFrom, String keyValidTo) { 
// 请求头
HttpHeaders header = new HttpHeaders();
header.add("x-requestId", UUID.randomUUID().toString());
header.add("x-timestamp", String.valueOf(System.currentTimeMillis()));
header.add("x-vehicle-oemId", "MOCK");
// 通知钥匙删除中
Map<String, Object> eventData = new HashMap<>();
eventData.put("status", 15);
eventData.put("keyValidTo", keyValidTo);
eventData.put("keyValidFrom", keyValidFrom);
eventData.put("reason", "Key is being terminated");
// 请求参数
Map<String, Object> param = new HashMap<>();
param.put("keyID", keyId);
param.put("eventType", "IN_TERMINATION");
param.put("eventData", eventData);

HttpEntity httpEntity = new HttpEntity(param, header);
ResponseEntity<Object> res = restTemplate.postForEntity(eventNotificationApi, httpEntity, Object.class);
logger.info("api response: {}", res.toString());
}

public void remoteTerminateKey(String keyId, String serverRemoteTerminationRequest) {
// 请求头
HttpHeaders header = new HttpHeaders();
header.add("x-requestId", UUID.randomUUID().toString());
header.add("x-timestamp", String.valueOf(System.currentTimeMillis()));
header.add("x-vehicle-oemId", "MOCK");

// 远程删除请求
Map<String, Object> param = new HashMap<>();
param.put("keyID", keyId);
param.put("action", "TERMINATE");
param.put("serverRemoteTerminationRequest", serverRemoteTerminationRequest);

HttpEntity httpEntity = new HttpEntity(param, header);
ResponseEntity<Object> res = restTemplate.postForEntity(manageKeyApi, httpEntity, Object.class);
logger.info("api response: {}", res.toString());
}

3.4、刷卡使用

具体内容可以参考CCC数字车钥匙规范

3.5、钥匙分享

1、调用startDigitalKeySharing接口调起钱包页面,进行钥匙分享

上传文件

2、钥匙分享的过程是在车主设备、relay server、好友设备这三方之间完成的,此过程不经过车服务器,具体内容可以参数CCC数字车钥匙规范

3、好友设备接收钥匙成功后,设备会发送分享钥匙的注册请求,通过Track Key API将钥匙数据注册到车服务器,此过程与车主注册钥匙类似,请参考云端注册钥匙的示例代码

4、激活分享钥匙以车厂设定的激活方式为准,如果车厂不需要,钥匙默认为激活状态

5、分享钥匙激活成功后,车服务器还需要调用车主设备服务器的Event Notification API将分享成功事件通知车主,这样车主设备也能显示分享的钥匙信息了

代码示例

public void sharedKeyAddEventNotification(String ownerKeyId, String keyValidFrom, String keyValidTo, List<SharedKey> sharedKeys) { 
// 请求头
HttpHeaders header = new HttpHeaders();
header.add("x-requestId", UUID.randomUUID().toString());
header.add("x-timestamp", String.valueOf(System.currentTimeMillis()));
header.add("x-vehicle-oemId", "MOCK");

// 组装分享钥匙列表
List<Map<String, Object>> sharedKeysData = new ArrayList<>();
for (SharedKey sharedKey : sharedKeys) {
Map<String, Object> sharedKeyData = new HashMap<>();
sharedKeyData.put("keyID", sharedKey.getKeyId());
Map<String, Object> keyConfiguration = new HashMap<>();
keyConfiguration.put("friendlyName", sharedKey.getFriendlyName());
keyConfiguration.put("rights", sharedKey.getRight());
keyConfiguration.put("keyValidTo", sharedKey.getValidTo());
keyConfiguration.put("keyValidFrom", sharedKey.getValidFrom());
sharedKeyData.put("keyConfiguration", keyConfiguration);
sharedKeyData.put("status", sharedKey.getStatus());
sharedKeyData.put("groupIdentifier", sharedKey.getGroupIdentifier);
sharedKeyData.put("deviceType", sharedKey.getDeviceType());
sharedKeysData.add(sharedKeyData);
}

// 事件通知数据
Map<String, Object> eventNotificationData = new HashMap<>();
eventNotificationData.put("keyID", ownerKeyId);
eventNotificationData.put("version", "1");
eventNotificationData.put("sharedKeysData", sharedKeysData);

// 加密事件通知数据
Map<String, Object> encryptedData = ECIES.encrypt(eventNotificationData);

// 通知分享钥匙添加成功
Map<String, Object> eventData = new HashMap<>();
eventData.put("status", 1);
eventData.put("sharedKeys", sharedKeys.size());
eventData.put("shareableKeys", MAX_SHARE_KEY_NUMBER - sharedKeys.size());
eventData.put("keyValidTo", keyValidTo);
eventData.put("keyValidFrom", keyValidFrom);
eventData.put("reason", "Shared key is added");
eventData.put("encryptedData", encryptedData);

// 请求参数
Map<String, Object> param = new HashMap<>();
param.put("keyID", ownerKeyId);
param.put("eventType", "SHARED_KEY_ADDED");
param.put("eventData", eventData);

HttpEntity httpEntity = new HttpEntity(param, header);
ResponseEntity<Object> res = restTemplate.postForEntity(eventNotificationApi, httpEntity, Object.class);
logger.info("api response: {}", res.toString());
}

3.6、远程车控(RKE)

上传文件

1、钱包侧可配置基常用RKE功能键,需提供信息如下信息:

functionID、actionID、以及功能描述

2、车厂App可自行实现远程车控逻辑

  • 注册钥匙事件监听,registerDigitalKeyEventCallback
  • 注册远程车控事件监听,registerRkeCallback
  • 请求车端车控当前状态,requestRkeStatus
  • 请求指定车控状态,requestRkeAction

关于RKE订阅待定

4、其他要求

NFC读卡器要求

车端NFC读卡器应符合CCC规范中要求的NFC-A的要求。

车端读卡器应不校验SAK、UID等参数,通过SELECT AID命令来选择车钥匙应用。如果SELECT AID命令返回9000,表明手机支持车钥匙应用。 验证方法如下:

1、在测试手机上开通一把车钥匙, 一张公交卡, 和一张空白门卡(或模拟一张门卡)

2、双击电源键,右上角设置菜单, 设置 - 快捷卡片设置 - 快捷选卡 关闭;双击电源键,手动选中公交卡, 测试车钥匙交易正常, 熄屏, 再次测试车钥匙交易正常; 双击电源键,手动选中门卡, 测试车钥匙交易正常,熄屏,再次测试车钥匙交易正常,关机,再次测试车钥匙交易正常。

3、双击电源键,右上角设置菜单, 设置 - 快捷卡片设置 - 快捷选卡 开启,选中门卡为默认卡片;熄屏, 测试车钥匙交易正常,关机,再次测试车钥匙交易正常。

无线充WPC和NFC刷卡冲突问题

对于车端WPC和NFC二合一设备,建议采用以下策略避免误唤醒手机刷卡页面:

1、根据车辆状态,设定NFC Polling启用和关闭,当用户需要二次刷卡点火或车钥匙配对场景下,打开NFC Polling,其他场景保持NFC关闭。

2、车主钥匙配对过程中,无线充应保持关闭。

常见问题说明

联调过程常见问题说明

1、车厂App如何判断当前设备是否具备开通CCC车钥匙能力?

  • 先调用接口isSupportedByDevice(判断是否为True) 。这样可以避免在某些过低版本上直接调用DKF APIs造成SDK Crash。isSupportedByDevice判断了DKF和小米智能卡的最低版本
  • 之后,调用 isCreateDigitalKeyPossible(是否返回DIGITAL_KEY_CREATION_POSSIBLE), 调用 getWirelessCapabilities来判断手机是否支持NFC/BLE/UWB, 这2个API 无顺序要求。
  • 以上判断完成后,就可以调用createDigitalKey发起配对流程。
  • 钱包配对流程启动后,会判断当前设备是否开放了机型白名单机制,通过onActivityResult中resultCode回调对应执行结果, 如果当前设备没有开放, 返回配对错误码是 DIGITAL_KEY_VEHICLE_OEM_NOT_SUPPORTED。

2、关于分享时applink问题,如果在安装版本正确时,出现无法打开原生App问题,如何排查?

  • 首先确认Applink是否通过验证,在终端中输入adb shell pm get-app-links com.miui.tsmclient,确认相关域名是否为verify
  • 如果不是,在终端执行adb shell pm verify-app-links --re-verify com.miui.tsmclient重新确认一下,或者进入设置-应用设置-应用管理-搜索小米智能卡结束进程,双击电源后,重新使用1命令查看

三、测试验收

1、测试/验收流程

上传文件

2、验收通过标准

用例通过率:

  • P4+P5用例通过率=100%(必过)
  • P3测试用例通过率≥90% (必过)

feature完成度:

  • 无B/C类问题遗留(必过)
  • Major 问题解决率 ≥90%,未解决的 Major 问题需经过产品、研发确认(参考)
  • 多语言通过标准: 中英翻译适配完成(必过),全部翻译适配完成(参考)

发现问题解决率

遗留 DI ≤10(必过)(DI根据bug级别来计算:DI= 致命Blocker级别的问题个数*10+严重Critical级别的问题个数*3+一般Major级别的问题个数*1+提示Minor级别的问题个数*0.1)

测试报告模板参考文档附件

四、生产上线

生产上线需进行相关配置,请发送邮件至did-carkey@xiaomi.com进行上线申请。
邮件内容:
1、提供测试报告及申请生产上线说明
2、提供品牌名称、品牌logo、卡面等素材(若在测试环境已提供则不用重复提供)
3、生产证书
4、提供生产环境测试白名单小米账号
5、提供车企App包名及签名

1、生产证书交换

与测试证书互签流程相同

2、服务端生产配置

业务后台相关配置

3、客户端生产配置

客户端访问白名单相关配置

上线流程

上传文件

五、新机上线

新机需由小米员工陪同现场测试或者发布后邮寄给车厂进行测试

适配流程同8

六、存量机适配

  • 车厂适配流程:车厂测试,小米邮件验收
上传文件

上一篇:
下一篇: