• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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        "metadata": [
64          {
65            "name": "payment-aid",
66            "value": "A0000000031010" // 修改为正确的aid
67          },
68          {
69            "name": "other-aid",
70            "value": "A0000000031011" // 修改为正确的aid
71          }
72        ]
73      }
74    ],
75    "requestPermissions": [
76      {
77        // 添加使用nfc卡模拟需要的权限
78        "name": "ohos.permission.NFC_CARD_EMULATION",
79        "reason": "$string:app_name",
80      }
81    ]
82```
83
84```ts
85import { cardEmulation } from '@kit.ConnectivityKit';
86import { BusinessError } from '@kit.BasicServicesKit';
87import { hilog } from '@kit.PerformanceAnalysisKit';
88import { AsyncCallback } from '@kit.BasicServicesKit';
89import { AbilityConstant, UIAbility, Want, bundleManager } from '@kit.AbilityKit';
90
91let hceElementName: bundleManager.ElementName;
92let hceService: cardEmulation.HceService;
93
94const hceCommandCb : AsyncCallback<number[]> = (error : BusinessError, hceCommand : number[]) => {
95  if (!error) {
96    if (hceCommand == null || hceCommand == undefined) {
97      hilog.error(0x0000, 'testTag', 'hceCommandCb has invalid hceCommand.');
98      return;
99    }
100    // 检查指令,发送response
101    hilog.info(0x0000, 'testTag', 'hceCommand = %{public}s', JSON.stringify(hceCommand));
102    let responseData = [0x90, 0x00]; // 根据接收到的不同命令更改response
103    hceService.transmit(responseData).then(() => {
104      hilog.info(0x0000, 'testTag', 'hceService transmit Promise success.');
105    }).catch((err: BusinessError) => {
106      hilog.error(0x0000, 'testTag', 'hceService transmit Promise error = %{public}s', JSON.stringify(err));
107    });
108  } else {
109    hilog.error(0x0000, 'testTag', 'hceCommandCb error %{public}s', JSON.stringify(error));
110  }
111}
112
113export default class EntryAbility extends UIAbility {
114  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
115    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
116
117    // 判断设备是否支持NFC能力和HCE能力
118    if (!canIUse("SystemCapability.Communication.NFC.Core")) {
119      hilog.error(0x0000, 'testTag', 'nfc unavailable.');
120      return;
121    }
122    if (!cardEmulation.hasHceCapability()) {
123      hilog.error(0x0000, 'testTag', 'hce unavailable.');
124      return;
125    }
126
127    hceElementName = {
128      bundleName: want.bundleName ?? '',
129      abilityName: want.abilityName ?? '',
130      moduleName: want.moduleName,
131    }
132    hceService = new cardEmulation.HceService();
133  }
134
135  onForeground() {
136    // 应用进入前台
137    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
138    if (hceElementName != undefined) {
139      try {
140        // 调用接口使能前台HCE应用程序优先处理NFC刷卡功能
141        let aidList = ["A0000000031010", "A0000000031011"]; // 修改为正确的aid
142        hceService.start(hceElementName, aidList);
143
144        // 订阅HCE APDU数据的接收
145        hceService.on('hceCmd', hceCommandCb);
146      } catch (error) {
147        hilog.error(0x0000, 'testTag', 'hceService.start error = %{public}s', JSON.stringify(error));
148      }
149    }
150  }
151
152  onBackground() {
153    // 应用退到后台
154    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
155    // 退出应用程序NFC标签页面时,调用tag模块退出前台优先功能
156    if (hceElementName != undefined) {
157      try {
158        hceService.stop(hceElementName);
159      } catch (error) {
160        hilog.error(0x0000, 'testTag', 'hceService.stop error = %{public}s', JSON.stringify(error));
161      }
162    }
163  }
164}
165```
166
167### HCE应用后台刷卡
1681. 在module.json5文件中声明NFC卡模拟权限,声明HCE特定的action,声明应用能够处理的AID。
1692. import需要的NFC卡模拟模块和其他相关的模块。
1703. 判断设备是否支持NFC能力和HCE能力。
1714. 订阅HCE APDU数据的接收。
1725. 完成HCE刷卡APDU数据的接收和发送。
1736. 退出应用程序时,退出订阅功能。
174
175```ts
176    "abilities": [
177      {
178        "name": "EntryAbility",
179        "srcEntry": "./ets/entryability/EntryAbility.ts",
180        "description": "$string:EntryAbility_desc",
181        "icon": "$media:icon",
182        "label": "$string:EntryAbility_label",
183        "startWindowIcon": "$media:icon",
184        "startWindowBackground": "$color:start_window_background",
185        "exported": true,
186        "skills": [
187          {
188            "entities": [
189              "entity.system.home"
190            ],
191            "actions": [
192              "action.system.home",
193
194              // actions须包含"ohos.nfc.cardemulation.action.HOST_APDU_SERVICE"
195              "ohos.nfc.cardemulation.action.HOST_APDU_SERVICE"
196            ]
197          }
198        ],
199        "metadata": [
200          {
201            "name": "payment-aid",
202            "value": "A0000000031010" // 修改为正确的aid
203          },
204          {
205            "name": "other-aid",
206            "value": "A0000000031011" // 修改为正确的aid
207          }
208        ]
209      }
210    ],
211    "requestPermissions": [
212      {
213        // 添加使用nfc卡模拟需要的权限
214        "name": "ohos.permission.NFC_CARD_EMULATION",
215        "reason": "$string:app_name",
216      }
217    ]
218```
219
220```ts
221import { cardEmulation } from '@kit.ConnectivityKit';
222import { BusinessError } from '@kit.BasicServicesKit';
223import { hilog } from '@kit.PerformanceAnalysisKit';
224import { AsyncCallback } from '@kit.BasicServicesKit';
225import { AbilityConstant, UIAbility, Want, bundleManager } from '@kit.AbilityKit';
226
227let hceElementName : bundleManager.ElementName;
228let hceService: cardEmulation.HceService;
229
230const hceCommandCb : AsyncCallback<number[]> = (error : BusinessError, hceCommand : number[]) => {
231  if (!error) {
232    if (hceCommand == null || hceCommand == undefined) {
233      hilog.error(0x0000, 'testTag', 'hceCommandCb has invalid hceCommand.');
234      return;
235    }
236
237    // 检查指令,发送response
238    hilog.info(0x0000, 'testTag', 'hceCommand = %{public}s', JSON.stringify(hceCommand));
239    let responseData = [0x90, 0x00]; // change the response depend on different received command.
240    hceService.transmit(responseData).then(() => {
241      hilog.info(0x0000, 'testTag', 'hceService transmit Promise success.');
242    }).catch((err: BusinessError) => {
243      hilog.error(0x0000, 'testTag', 'hceService transmit Promise error = %{public}s', JSON.stringify(err));
244    });
245  } else {
246    hilog.error(0x0000, 'testTag', 'hceCommandCb error %{public}s', JSON.stringify(error));
247  }
248}
249
250export default class EntryAbility extends UIAbility {
251  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
252    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
253
254    // 判断设备是否支持NFC能力和HCE能力
255    if (!canIUse("SystemCapability.Communication.NFC.Core")) {
256      hilog.error(0x0000, 'testTag', 'nfc unavailable.');
257      return;
258    }
259    if (!cardEmulation.hasHceCapability()) {
260      hilog.error(0x0000, 'testTag', 'hce unavailable.');
261      return;
262    }
263
264    hceElementName = {
265      bundleName: want.bundleName ?? '',
266      abilityName: want.abilityName ?? '',
267      moduleName: want.moduleName,
268    }
269    hceService = new cardEmulation.HceService();
270    hceService.on('hceCmd', hceCommandCb);
271  }
272
273  onForeground() {
274    // 应用进入前台
275    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
276  }
277
278  onDestroy() {
279    // 退出应用
280    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
281    // 退出应用程序NFC标签页面时,调用tag模块退出前台优先功能
282    if (hceElementName != undefined) {
283      try {
284        hceService.stop(hceElementName);
285      } catch (error) {
286        hilog.error(0x0000, 'testTag', 'hceService.stop error = %{public}s', JSON.stringify(error));
287      }
288    }
289  }
290}
291```