1# HCE卡模拟开发指南 2 3## 简介 4近场通信(Near Field Communication,NFC)是一种短距高频的无线电技术,在13.56MHz频率运行,通信距离一般在10厘米距离内。HCE(Host Card Emulation),称为基于主机的卡模拟,表示不依赖安全单元芯片,电子设备上的应用程序模拟NFC卡片和NFC读卡器通信,实现NFC刷卡业务。 5 6## 场景介绍 7应用程序模拟NFC卡片,和NFC读卡器通信完成NFC刷卡业务。从使用场景上,可以分成HCE应用前台刷卡,和HCE应用后台刷卡。 8- HCE应用前台刷卡<br> 9前台刷卡是指在触碰NFC读卡器之前,用户先在电子设备上打开特定的应用程序,用户明确想使用所打开的应用程序和NFC读卡器进行刷卡操作。用户打开应用程序在前台,并且进入应用的刷卡页面之后,电子设备触碰NFC读卡器,只会把刷卡交易数据分发给前台应用。 10- HCE应用后台刷卡<br> 11后台刷卡是指不打开特定的HCE应用程序,电子设备触碰NFC读卡器后,根据NFC读卡器选择的应用ID(AID)匹配到HCE应用程序,并自动和匹配的HCE应用程序通信完成刷卡交易。如果匹配到多个HCE应用程序时,说明存在冲突,需要用户打开指定的应用才能完成刷卡。 12- HCE应用刷卡的约束条件<br> 131.不管是HCE应用前台还是后台刷卡,能够完成HCE应用程序NFC刷卡的条件是电子设备需要亮屏解锁。<br>2.module.json5文件中需要声明nfc卡模拟权限,具体见示例。<br>3.前台应用时需要调用start和stop注册和去注册AID,具体见示例。<br> 14 15## 接口说明 16 17NFC卡模拟完整的JS API说明以及实例代码请参考:[NFC卡模拟接口](../../reference/apis-connectivity-kit/js-apis-cardEmulation.md)。 18 19完成HCE卡模拟功能,可能使用到下面的接口。 20 21| 接口名 | 功能描述 | 22| ---------------------------------- | ------------------------------------------------------------------------------ | 23| start(elementName: ElementName, aidList: string[]): void | 启动HCE业务功能。包括设置当前应用为前台优先,动态注册AID列表。 | 24| stop(elementName: ElementName): void | 停止HCE业务功能。包括取消APDU数据接收的订阅,退出当前应用前台优先,释放动态注册的AID列表。 25| on(type: 'hceCmd', callback: AsyncCallback\<number[]>): void | 订阅回调,用于接收对端读卡设备发送的APDU数据。 26| transmit(response: number[]): Promise\<void> | 发送APDU数据到对端读卡设备。| | 27 28## 开发步骤 29 30### HCE应用前台刷卡 311. 在module.json5文件中声明NFC卡模拟权限,以及声明HCE特定的action。 322. import需要的NFC卡模拟模块和其他相关的模块。 333. 判断设备是否支持NFC能力和HCE能力。 344. 使能前台HCE应用程序优先处理NFC刷卡功能。 355. 订阅HCE APDU数据的接收。 366. 完成HCE刷卡APDU数据的接收和发送。 377. 退出应用程序NFC刷卡页面时,退出前台优先功能。 38 39```ts 40 "abilities": [ 41 { 42 "name": "EntryAbility", 43 "srcEntry": "./ets/entryability/EntryAbility.ts", 44 "description": "$string:EntryAbility_desc", 45 "icon": "$media:icon", 46 "label": "$string:EntryAbility_label", 47 "startWindowIcon": "$media:icon", 48 "startWindowBackground": "$color:start_window_background", 49 "exported": true, 50 "skills": [ 51 { 52 "entities": [ 53 "entity.system.home" 54 ], 55 "actions": [ 56 "action.system.home", 57 58 // actions须包含"ohos.nfc.cardemulation.action.HOST_APDU_SERVICE" 59 "ohos.nfc.cardemulation.action.HOST_APDU_SERVICE" 60 ] 61 } 62 ] 63 } 64 ], 65 "requestPermissions": [ 66 { 67 // 添加使用nfc卡模拟需要的权限 68 "name": "ohos.permission.NFC_CARD_EMULATION", 69 "reason": "$string:app_name", 70 } 71 ] 72``` 73 74```ts 75import { cardEmulation } from '@kit.ConnectivityKit'; 76import { BusinessError } from '@kit.BasicServicesKit'; 77import { hilog } from '@kit.PerformanceAnalysisKit'; 78import { AsyncCallback } from '@kit.BasicServicesKit'; 79import { AbilityConstant, UIAbility, Want, bundleManager } from '@kit.AbilityKit'; 80 81let hceElementName: bundleManager.ElementName; 82let hceService: cardEmulation.HceService; 83 84const hceCommandCb : AsyncCallback<number[]> = (error : BusinessError, hceCommand : number[]) => { 85 if (!error) { 86 if (hceCommand == null || hceCommand == undefined) { 87 hilog.error(0x0000, 'testTag', 'hceCommandCb has invalid hceCommand.'); 88 return; 89 } 90 // check the command, then transmit the response. 91 hilog.info(0x0000, 'testTag', 'hceCommand = %{public}s', JSON.stringify(hceCommand)); 92 let responseData = [0x90, 0x00]; // change the response depend on different received command. 93 hceService.transmit(responseData).then(() => { 94 hilog.info(0x0000, 'testTag', 'hceService transmit Promise success.'); 95 }).catch((err: BusinessError) => { 96 hilog.error(0x0000, 'testTag', 'hceService transmit Promise error = %{public}s', JSON.stringify(err)); 97 }); 98 } else { 99 hilog.error(0x0000, 'testTag', 'hceCommandCb error %{public}s', JSON.stringify(error)); 100 } 101} 102 103export default class EntryAbility extends UIAbility { 104 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 105 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 106 107 // 判断设备是否支持NFC能力和HCE能力 108 if (!canIUse("SystemCapability.Communication.NFC.Core")) { 109 hilog.error(0x0000, 'testTag', 'nfc unavailable.'); 110 return; 111 } 112 if (!cardEmulation.hasHceCapability()) { 113 hilog.error(0x0000, 'testTag', 'hce unavailable.'); 114 return; 115 } 116 117 hceElementName = { 118 bundleName: want.bundleName ?? '', 119 abilityName: want.abilityName ?? '', 120 moduleName: want.moduleName, 121 } 122 hceService = new cardEmulation.HceService(); 123 } 124 125 onForeground() { 126 // Ability has brought to foreground 127 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); 128 if (hceElementName != undefined) { 129 try { 130 // 调用接口使能前台HCE应用程序优先处理NFC刷卡功能 131 let aidList = ["A0000000031010", "A0000000031011"]; // change aid tobe correct. 132 hceService.start(hceElementName, aidList); 133 134 // 订阅HCE APDU数据的接收 135 hceService.on('hceCmd', hceCommandCb); 136 } catch (error) { 137 hilog.error(0x0000, 'testTag', 'hceService.start error = %{public}s', JSON.stringify(error)); 138 } 139 } 140 } 141 142 onBackground() { 143 // Ability has back to background 144 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); 145 // 退出应用程序NFC标签页面时,调用tag模块退出前台优先功能 146 if (hceElementName != undefined) { 147 try { 148 hceService.stop(hceElementName); 149 } catch (error) { 150 hilog.error(0x0000, 'testTag', 'hceService.stop error = %{public}s', JSON.stringify(error)); 151 } 152 } 153 } 154} 155``` 156 157### HCE应用后台刷卡 1581. 在module.json5文件中声明NFC卡模拟权限,声明HCE特定的action,声明应用能够处理的AID。 1592. import需要的NFC卡模拟模块和其他相关的模块。 1603. 判断设备是否支持NFC能力和HCE能力。 1614. 订阅HCE APDU数据的接收。 1625. 完成HCE刷卡APDU数据的接收和发送。 1636. 退出应用程序时,退出订阅功能。 164 165```ts 166 "abilities": [ 167 { 168 "name": "EntryAbility", 169 "srcEntry": "./ets/entryability/EntryAbility.ts", 170 "description": "$string:EntryAbility_desc", 171 "icon": "$media:icon", 172 "label": "$string:EntryAbility_label", 173 "startWindowIcon": "$media:icon", 174 "startWindowBackground": "$color:start_window_background", 175 "exported": true, 176 "skills": [ 177 { 178 "entities": [ 179 "entity.system.home" 180 ], 181 "actions": [ 182 "action.system.home", 183 184 // Add the nfc card emulation action to filter out for this application. 185 "ohos.nfc.cardemulation.action.HOST_APDU_SERVICE" 186 ] 187 } 188 ], 189 "metadata": [ 190 { 191 "name": "payment-aid", 192 "value": "A0000000031010" // change it tobe correct 193 }, 194 { 195 "name": "other-aid", 196 "value": "A0000000031011" // change it tobe correct 197 } 198 ] 199 } 200 ], 201 "requestPermissions": [ 202 { 203 // Add the permission for nfc card emulation. 204 "name": "ohos.permission.NFC_CARD_EMULATION", 205 "reason": "$string:app_name", 206 } 207 ] 208``` 209 210```ts 211import { cardEmulation } from '@kit.ConnectivityKit'; 212import { BusinessError } from '@kit.BasicServicesKit'; 213import { hilog } from '@kit.PerformanceAnalysisKit'; 214import { AsyncCallback } from '@kit.BasicServicesKit'; 215import { AbilityConstant, UIAbility, Want, bundleManager } from '@kit.AbilityKit'; 216 217let hceElementName : bundleManager.ElementName; 218let hceService: cardEmulation.HceService; 219 220const hceCommandCb : AsyncCallback<number[]> = (error : BusinessError, hceCommand : number[]) => { 221 if (!error) { 222 if (hceCommand == null || hceCommand == undefined) { 223 hilog.error(0x0000, 'testTag', 'hceCommandCb has invalid hceCommand.'); 224 return; 225 } 226 227 // check the command, then transmit the response. 228 hilog.info(0x0000, 'testTag', 'hceCommand = %{public}s', JSON.stringify(hceCommand)); 229 let responseData = [0x90, 0x00]; // change the response depend on different received command. 230 hceService.transmit(responseData).then(() => { 231 hilog.info(0x0000, 'testTag', 'hceService transmit Promise success.'); 232 }).catch((err: BusinessError) => { 233 hilog.error(0x0000, 'testTag', 'hceService transmit Promise error = %{public}s', JSON.stringify(err)); 234 }); 235 } else { 236 hilog.error(0x0000, 'testTag', 'hceCommandCb error %{public}s', JSON.stringify(error)); 237 } 238} 239 240export default class EntryAbility extends UIAbility { 241 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 242 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 243 244 // 判断设备是否支持NFC能力和HCE能力 245 if (!canIUse("SystemCapability.Communication.NFC.Core")) { 246 hilog.error(0x0000, 'testTag', 'nfc unavailable.'); 247 return; 248 } 249 if (!cardEmulation.hasHceCapability()) { 250 hilog.error(0x0000, 'testTag', 'hce unavailable.'); 251 return; 252 } 253 254 hceElementName = { 255 bundleName: want.bundleName ?? '', 256 abilityName: want.abilityName ?? '', 257 moduleName: want.moduleName, 258 } 259 hceService = new cardEmulation.HceService(); 260 hceService.on('hceCmd', hceCommandCb); 261 } 262 263 onForeground() { 264 // Ability has brought to foreground 265 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); 266 } 267 268 onDestroy() { 269 // Ability has back to destroy 270 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); 271 // 退出应用程序NFC标签页面时,调用tag模块退出前台优先功能 272 if (hceElementName != undefined) { 273 try { 274 hceService.stop(hceElementName); 275 } catch (error) { 276 hilog.error(0x0000, 'testTag', 'hceService.stop error = %{public}s', JSON.stringify(error)); 277 } 278 } 279 } 280} 281```