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刷卡的条件是电子设备需要亮屏解锁。 142、module.json5文件中需要声明nfc卡模拟权限,具体见示例。 153、前台应用时需要调用start和stop注册和去注册AID,具体见示例。 16 17## 接口说明 18 19NFC卡模拟完整的JS API说明以及实例代码请参考:[NFC卡模拟接口](../../reference/apis-connectivity-kit/js-apis-cardEmulation.md)。 20 21完成HCE卡模拟功能,可能使用到下面的接口。 22 23| 接口名 | 功能描述 | 24| ---------------------------------- | ------------------------------------------------------------------------------ | 25| start(elementName: ElementName, aidList: string[]): void | 启动HCE业务功能。包括设置当前应用为前台优先,动态注册AID列表。 | 26| stop(elementName: ElementName): void | 停止HCE业务功能。包括取消APDU数据接收的订阅,退出当前应用前台优先,释放动态注册的AID列表。 27| on(type: 'hceCmd', callback: AsyncCallback\<number[]>): void | 订阅回调,用于接收对端读卡设备发送的APDU数据。 28| transmit(response: number[]): Promise\<void> | 发送APDU数据到对端读卡设备。| | 29 30## 开发步骤 31 32### HCE应用前台刷卡 331. 在module.json5文件中声明NFC卡模拟权限,以及声明HCE特定的action。 342. import需要的NFC卡模拟模块和其他相关的模块。 353. 判断设备是否支持NFC能力和HCE能力。 364. 使能前台HCE应用程序优先处理NFC刷卡功能。 375. 订阅HCE APDU数据的接收。 386. 完成HCE刷卡APDU数据的接收和发送。 397. 退出应用程序NFC刷卡页面时,退出前台优先功能。 40 41```ts 42 "abilities": [ 43 { 44 "name": "EntryAbility", 45 "srcEntry": "./ets/entryability/EntryAbility.ts", 46 "description": "$string:EntryAbility_desc", 47 "icon": "$media:icon", 48 "label": "$string:EntryAbility_label", 49 "startWindowIcon": "$media:icon", 50 "startWindowBackground": "$color:start_window_background", 51 "exported": true, 52 "skills": [ 53 { 54 "entities": [ 55 "entity.system.home" 56 ], 57 "actions": [ 58 "action.system.home", 59 60 // Add the nfc card emulation action to filter out for this application. 61 "ohos.nfc.cardemulation.action.HOST_APDU_SERVICE" 62 ] 63 } 64 ] 65 } 66 ], 67 "requestPermissions": [ 68 { 69 // Add the permission for nfc card emulation. 70 "name": "ohos.permission.NFC_CARD_EMULATION", 71 "reason": "$string:app_name", 72 } 73 ] 74``` 75 76```ts 77import { cardEmulation } from '@kit.ConnectivityKit'; 78import { BusinessError } from '@kit.BasicServicesKit'; 79import { hilog } from '@kit.PerformanceAnalysisKit'; 80import { AsyncCallback } from '@kit.BasicServicesKit'; 81import { AbilityConstant, UIAbility, Want, bundleManager } from '@kit.AbilityKit'; 82 83let hceElementName: bundleManager.ElementName; 84let hceService: cardEmulation.HceService; 85 86const hceCommandCb : AsyncCallback<number[]> = (error : BusinessError, hceCommand : number[]) => { 87 if (!error) { 88 if (hceCommand == null || hceCommand == undefined) { 89 hilog.error(0x0000, 'testTag', 'hceCommandCb has invalid hceCommand.'); 90 return; 91 } 92 // check the command, then transmit the response. 93 hilog.info(0x0000, 'testTag', 'hceCommand = %{public}s', JSON.stringify(hceCommand)); 94 let responseData = [0x90, 0x00]; // change the response depend on different received command. 95 hceService.transmit(responseData).then(() => { 96 hilog.info(0x0000, 'testTag', 'hceService transmit Promise success.'); 97 }).catch((err: BusinessError) => { 98 hilog.error(0x0000, 'testTag', 'hceService transmit Promise error = %{public}s', JSON.stringify(err)); 99 }); 100 } else { 101 hilog.error(0x0000, 'testTag', 'hceCommandCb error %{public}s', JSON.stringify(error)); 102 } 103} 104 105export default class EntryAbility extends UIAbility { 106 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 107 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 108 109 // 判断设备是否支持NFC能力和HCE能力 110 if (!canIUse("SystemCapability.Communication.NFC.Core")) { 111 hilog.error(0x0000, 'testTag', 'nfc unavailable.'); 112 return; 113 } 114 if (!cardEmulation.hasHceCapability()) { 115 hilog.error(0x0000, 'testTag', 'hce unavailable.'); 116 return; 117 } 118 119 hceElementName = { 120 bundleName: want.bundleName ?? '', 121 abilityName: want.abilityName ?? '', 122 moduleName: want.moduleName, 123 } 124 hceService = new cardEmulation.HceService(); 125 } 126 127 onForeground() { 128 // Ability has brought to foreground 129 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); 130 if (hceElementName != undefined) { 131 try { 132 // 调用接口使能前台HCE应用程序优先处理NFC刷卡功能 133 let aidList = ["A0000000031010", "A0000000031011"]; // change aid tobe correct. 134 hceService.start(hceElementName, aidList); 135 136 // 订阅HCE APDU数据的接收 137 hceService.on('hceCmd', hceCommandCb); 138 } catch (error) { 139 hilog.error(0x0000, 'testTag', 'hceService.start error = %{public}s', JSON.stringify(error)); 140 } 141 } 142 } 143 144 onBackground() { 145 // Ability has back to background 146 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); 147 // 退出应用程序NFC标签页面时,调用tag模块退出前台优先功能 148 if (hceElementName != undefined) { 149 try { 150 hceService.stop(hceElementName); 151 } catch (error) { 152 hilog.error(0x0000, 'testTag', 'hceService.stop error = %{public}s', JSON.stringify(error)); 153 } 154 } 155 } 156} 157``` 158 159### HCE应用后台刷卡 1601. 在module.json5文件中声明NFC卡模拟权限,声明HCE特定的action,声明应用能够处理的AID。 1612. import需要的NFC卡模拟模块和其他相关的模块。 1623. 判断设备是否支持NFC能力和HCE能力。 1634. 订阅HCE APDU数据的接收。 1645. 完成HCE刷卡APDU数据的接收和发送。 1656. 退出应用程序时,退出订阅功能。 166 167```ts 168 "abilities": [ 169 { 170 "name": "EntryAbility", 171 "srcEntry": "./ets/entryability/EntryAbility.ts", 172 "description": "$string:EntryAbility_desc", 173 "icon": "$media:icon", 174 "label": "$string:EntryAbility_label", 175 "startWindowIcon": "$media:icon", 176 "startWindowBackground": "$color:start_window_background", 177 "exported": true, 178 "skills": [ 179 { 180 "entities": [ 181 "entity.system.home" 182 ], 183 "actions": [ 184 "action.system.home", 185 186 // Add the nfc card emulation action to filter out for this application. 187 "ohos.nfc.cardemulation.action.HOST_APDU_SERVICE" 188 ] 189 } 190 ], 191 "metadata": [ 192 { 193 "name": "payment-aid", 194 "value": "A0000000031010" // change it tobe correct 195 }, 196 { 197 "name": "other-aid", 198 "value": "A0000000031011" // change it tobe correct 199 } 200 ] 201 } 202 ], 203 "requestPermissions": [ 204 { 205 // Add the permission for nfc card emulation. 206 "name": "ohos.permission.NFC_CARD_EMULATION", 207 "reason": "$string:app_name", 208 } 209 ] 210``` 211 212```ts 213import { cardEmulation } from '@kit.ConnectivityKit'; 214import { BusinessError } from '@kit.BasicServicesKit'; 215import { hilog } from '@kit.PerformanceAnalysisKit'; 216import { AsyncCallback } from '@kit.BasicServicesKit'; 217import { AbilityConstant, UIAbility, Want, bundleManager } from '@kit.AbilityKit'; 218 219let hceElementName : bundleManager.ElementName; 220let hceService: cardEmulation.HceService; 221 222const hceCommandCb : AsyncCallback<number[]> = (error : BusinessError, hceCommand : number[]) => { 223 if (!error) { 224 if (hceCommand == null || hceCommand == undefined) { 225 hilog.error(0x0000, 'testTag', 'hceCommandCb has invalid hceCommand.'); 226 return; 227 } 228 229 // check the command, then transmit the response. 230 hilog.info(0x0000, 'testTag', 'hceCommand = %{public}s', JSON.stringify(hceCommand)); 231 let responseData = [0x90, 0x00]; // change the response depend on different received command. 232 hceService.transmit(responseData).then(() => { 233 hilog.info(0x0000, 'testTag', 'hceService transmit Promise success.'); 234 }).catch((err: BusinessError) => { 235 hilog.error(0x0000, 'testTag', 'hceService transmit Promise error = %{public}s', JSON.stringify(err)); 236 }); 237 } else { 238 hilog.error(0x0000, 'testTag', 'hceCommandCb error %{public}s', JSON.stringify(error)); 239 } 240} 241 242export default class EntryAbility extends UIAbility { 243 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 244 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 245 246 // 判断设备是否支持NFC能力和HCE能力 247 if (!canIUse("SystemCapability.Communication.NFC.Core")) { 248 hilog.error(0x0000, 'testTag', 'nfc unavailable.'); 249 return; 250 } 251 if (!cardEmulation.hasHceCapability()) { 252 hilog.error(0x0000, 'testTag', 'hce unavailable.'); 253 return; 254 } 255 256 hceElementName = { 257 bundleName: want.bundleName ?? '', 258 abilityName: want.abilityName ?? '', 259 moduleName: want.moduleName, 260 } 261 hceService = new cardEmulation.HceService(); 262 hceService.on('hceCmd', hceCommandCb); 263 } 264 265 onForeground() { 266 // Ability has brought to foreground 267 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); 268 } 269 270 onDestroy() { 271 // Ability has back to destroy 272 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); 273 // 退出应用程序NFC标签页面时,调用tag模块退出前台优先功能 274 if (hceElementName != undefined) { 275 try { 276 hceService.stop(hceElementName); 277 } catch (error) { 278 hilog.error(0x0000, 'testTag', 'hceService.stop error = %{public}s', JSON.stringify(error)); 279 } 280 } 281 } 282} 283```