1# NFC标签读写开发指南
2
3## 简介
4近场通信(Near Field Communication,NFC)是一种短距高频的无线电技术,在13.56MHz频率运行,通信距离一般在10厘米距离内。电子设备可以通过NFC通信技术和NFC标签通信,从标签中读取数据,或写入数据到标签。
5NFC标签可能会支持一种或多种通信技术,具体技术如下:
6- NfcA (也称为 ISO 14443-3A)
7- NfcB (也称为 ISO 14443-3B)
8- NfcF (也称为 JIS 6319-4)
9- NfcV (也称为 ISO 15693)
10- IsoDep
11- NDEF
12- MifareClassic
13- MifareUltralight
14
15## 场景介绍
16电子设备通过NFC天线位置触碰NFC标签卡片,完成NFC标签卡片的读取或写入。从使用场景上,可以分成NFC标签前台读写,和NFC标签后台读写。
17- NFC标签前台读写<br>
18前台读写是指在触碰NFC标签之前,用户先在电子设备上打开特定的应用程序,用户明确想使用所打开的应用程序和NFC标签进行读写操作。用户打开应用程序在前台,并且进入应用的刷卡页面之后,电子设备触碰NFC标签,只会把读取到的卡片分发给前台应用。
19- NFC标签后台读写<br>
20后台读写是指不打开特定的NFC标签应用程序,电子设备触碰发现NFC标签后,根据NFC标签的技术类型,分发给能够处理的应用程序。如果能匹配到多个应用程序,则弹出应用选择器列举出应用列表给用户手动选择。用户选择指定的应用后,自动跳转到应用程序的NFC标签读写卡页面。
21- 标签读写约束条件<br>
22不管是前台读写,还是后台读写,电子设备能够发现NFC标签的前提条件是设备必须是亮屏和解锁状态。
23
24## 接口说明
25
26NFC标签读写完整的JS API说明以及实例代码请参考:[NFC标签接口](../../reference/apis-connectivity-kit/js-apis-nfcTag.md)。
27
28获取不同技术类型标签对象的接口说明如下表,根据不同技术的标签对象来执行NFC标签的读写。
29
30| 接口名                             | 功能描述                                                                       |
31| ---------------------------------- | ------------------------------------------------------------------------------ |
32| getNfcA(tagInfo: TagInfo): NfcATag                    | 获取NfcA技术类型的标签对象。                                                               |
33| getNfcB(tagInfo: TagInfo): NfcBTag                      | 获取NfcB技术类型的标签对象。                                                                |
34| getNfcF(tagInfo: TagInfo): NfcFTag                 | 获取NfcF技术类型的标签对象。                                                               |
35| getNfcV(tagInfo: TagInfo): NfcVTag                  | 获取NfcV技术类型的标签对象。                                                                |
36| getIsoDep(tagInfo: TagInfo): IsoDepTag | 获取IsoDep技术类型的标签对象。                                                                |
37| getNdef(tagInfo: TagInfo): NdefTag | 获取NDEF技术类型的标签对象。                                                            |
38| getMifareClassic(tagInfo: TagInfo): MifareClassicTag         | 获取MifareClassic技术类型的标签对象。                                                        |
39| getMifareUltralight(tagInfo: TagInfo): MifareUltralightTag         | 获取MifareUltralight技术类型的标签对象。                                                     |
40
41## 开发步骤
42
43### 前台读取标签
441. 在module.json5文件中声明NFC标签读取的权限,以及声明NFC标签特定的action。
452. import需要的tag模块和其他相关的模块。
463. 判断设备是否支持NFC能力。
474. 调用tag模块中前台优先的接口,使能前台应用程序优先处理所发现的NFC标签功能。
485. 获取特定技术类型的NFC标签对象。
496. 执行读写接口完成标签数据的读取或写入数据到标签。
507. 退出应用程序NFC标签页面时,调用tag模块退出前台优先功能。
51
52```ts
53    "abilities": [
54      {
55        "name": "EntryAbility",
56        "srcEntry": "./ets/entryability/EntryAbility.ts",
57        "description": "$string:EntryAbility_desc",
58        "icon": "$media:icon",
59        "label": "$string:EntryAbility_label",
60        "startWindowIcon": "$media:icon",
61        "startWindowBackground": "$color:start_window_background",
62        "exported": true,
63        "skills": [
64          {
65            "entities": [
66              "entity.system.home"
67            ],
68            "actions": [
69              "action.system.home",
70
71              // Add the nfc tag action to filter out for this application.
72              "ohos.nfc.tag.action.TAG_FOUND"
73            ]
74          }
75        ]
76      }
77    ],
78    "requestPermissions": [
79      {
80        // Add the permission for nfc tag operations.
81        "name": "ohos.permission.NFC_TAG",
82        "reason": "$string:app_name",
83      }
84    ]
85```
86
87```ts
88import { tag } from '@kit.ConnectivityKit';
89import { BusinessError } from '@kit.BasicServicesKit';
90import { hilog } from '@kit.PerformanceAnalysisKit';
91import { AbilityConstant, UIAbility, Want, bundleManager } from '@kit.AbilityKit';
92
93let nfcTagElementName: bundleManager.ElementName;
94let foregroundRegister: boolean;
95
96async function readerModeCb(error : BusinessError, tagInfo : tag.TagInfo) {
97  if (!error) {
98    // 获取特定技术类型的NFC标签对象
99    if (tagInfo == null || tagInfo == undefined) {
100      hilog.error(0x0000, 'testTag', 'readerModeCb tagInfo is invalid');
101      return;
102    }
103    if (tagInfo.uid == null || tagInfo.uid == undefined) {
104      hilog.error(0x0000, 'testTag', 'readerModeCb uid is invalid');
105      return;
106    }
107    if (tagInfo.technology == null || tagInfo.technology == undefined || tagInfo.technology.length == 0) {
108      hilog.error(0x0000, 'testTag', 'readerModeCb technology is invalid');
109      return;
110    }
111
112    // 执行读写接口完成标签数据的读取或写入数据到标签
113    // use the IsoDep technology to access this nfc tag.
114    let isoDep : tag.IsoDepTag | null = null;
115    for (let i = 0; i < tagInfo.technology.length; i++) {
116      if (tagInfo.technology[i] == tag.ISO_DEP) {
117        try {
118          isoDep = tag.getIsoDep(tagInfo);
119        } catch (error) {
120          hilog.error(0x0000, 'testTag', 'readerModeCb getIsoDep error = %{public}s', JSON.stringify(error));
121          return;
122        }
123      }
124      // use other technology to access this nfc tag if necessary.
125    }
126    if (isoDep == undefined) {
127      hilog.error(0x0000, 'testTag', 'readerModeCb getIsoDep is invalid');
128      return;
129    }
130
131    // connect to this nfc tag using IsoDep technology.
132    try {
133        isoDep.connect();
134    } catch (error) {
135        hilog.error(0x0000, 'testTag', 'readerModeCb isoDep.connect() error = %{public}s', JSON.stringify(error));
136        return;
137    }
138    if (!isoDep.isConnected()) {
139      hilog.error(0x0000, 'testTag', 'readerModeCb isoDep.isConnected() false.');
140      return;
141    }
142
143    // transmit data to the connected tag.
144    let cmdData = [0x01, 0x02, 0x03, 0x04]; // please change the raw data to be correct.
145    try {
146      isoDep.transmit(cmdData).then((response : number[]) => {
147        hilog.info(0x0000, 'testTag', 'readerModeCb isoDep.transmit() response = %{public}s.', JSON.stringify(response));
148      }).catch((err : BusinessError)=> {
149        hilog.error(0x0000, 'testTag', 'readerModeCb isoDep.transmit() err = %{public}s.', JSON.stringify(err));
150        return;
151      });
152    } catch (businessError) {
153      hilog.error(0x0000, 'testTag', 'readerModeCb isoDep.transmit() businessError = %{public}s.', JSON.stringify(businessError));
154      return;
155    }
156  } else {
157    hilog.info(0x0000, 'testTag', 'readerModeCb readerModeCb error %{public}s', JSON.stringify(error));
158  }
159}
160
161export default class EntryAbility extends UIAbility {
162  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
163    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
164
165    // 判断设备是否支持NFC能力
166    if (!canIUse("SystemCapability.Communication.NFC.Core")) {
167      hilog.error(0x0000, 'testTag', 'nfc unavailable.');
168      return;
169    }
170
171    nfcTagElementName = {
172      bundleName: want.bundleName ?? '',
173      abilityName: want.abilityName ?? '',
174      moduleName: want.moduleName,
175    }
176  }
177
178  onForeground() {
179    // Ability has brought to foreground
180    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
181    if (nfcTagElementName != undefined) {
182      // 调用tag模块中前台优先的接口,使能前台应用程序优先处理所发现的NFC标签功能
183      let techList : number[] = [tag.NFC_A, tag.NFC_B, tag.NFC_F, tag.NFC_V];
184      try {
185        tag.on('readerMode', nfcTagElementName, techList, readerModeCb);
186        foregroundRegister = true;
187      } catch (error) {
188        hilog.error(0x0000, 'testTag', 'on readerMode error = %{public}s', JSON.stringify(error));
189      }
190    }
191  }
192
193  onBackground() {
194    // Ability has back to background
195    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
196    // 退出应用程序NFC标签页面时,调用tag模块退出前台优先功能
197    if (foregroundRegister) {
198      foregroundRegister = false;
199      try {
200        tag.off('readerMode', nfcTagElementName);
201      } catch (error) {
202        hilog.error(0x0000, 'testTag', 'off readerMode error = %{public}s', JSON.stringify(error));
203      }
204    }
205  }
206}
207```
208
209### 后台读取标签
2101. 在module.json5文件中声明NFC标签读取的权限,声明NFC标签特定的action,以及声明本应用程序的能够处理的NFC标签技术类型。
2112. import需要的tag模块和其他相关的模块。
2123. 获取特定技术类型的NFC标签对象。
2134. 执行读写接口完成标签数据的读取或写入数据到标签。
214
215```ts
216    "abilities": [
217      {
218        "name": "EntryAbility",
219        "srcEntry": "./ets/entryability/EntryAbility.ts",
220        "description": "$string:EntryAbility_desc",
221        "icon": "$media:icon",
222        "label": "$string:EntryAbility_label",
223        "startWindowIcon": "$media:icon",
224        "startWindowBackground": "$color:start_window_background",
225        "exported": true,
226        "skills": [
227          {
228            "entities": [
229              "entity.system.home"
230            ],
231            "actions": [
232              "action.system.home",
233
234              // Add the nfc tag action to filter out for this application.
235              "ohos.nfc.tag.action.TAG_FOUND"
236            ],
237            "uris": [
238              {
239                  "type":"tag-tech/NfcA"
240              },
241              {
242                  "type":"tag-tech/IsoDep"
243              }
244              // Add other technologies if necessary,
245              // such as: NfcB/NfcF/NfcV/Ndef/MifareClassic/MifareUL/NdefFormatable
246            ]
247          }
248        ]
249      }
250    ],
251    "requestPermissions": [
252      {
253        // Add the permission for nfc tag operations.
254        "name": "ohos.permission.NFC_TAG",
255        "reason": "$string:app_name",
256      }
257    ]
258```
259
260```ts
261import { tag } from '@kit.ConnectivityKit';
262import { BusinessError } from '@kit.BasicServicesKit';
263import { hilog } from '@kit.PerformanceAnalysisKit';
264import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
265
266export default class EntryAbility extends UIAbility {
267  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
268    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
269
270    // 获取特定技术类型的NFC标签对象
271    let tagInfo : tag.TagInfo;
272    try {
273      tagInfo = tag.getTagInfo(want);
274    } catch (error) {
275      hilog.error(0x0000, 'testTag', 'getTagInfo error = %{public}s', JSON.stringify(error));
276      return;
277    }
278
279    if (tagInfo == null || tagInfo == undefined) {
280      hilog.error(0x0000, 'testTag', 'tagInfo is invalid');
281      return;
282    }
283    if (tagInfo.uid == null || tagInfo.uid == undefined) {
284      hilog.error(0x0000, 'testTag', 'uid is invalid');
285      return;
286    }
287    if (tagInfo.technology == null || tagInfo.technology == undefined || tagInfo.technology.length == 0) {
288      hilog.error(0x0000, 'testTag', 'technology is invalid');
289      return;
290    }
291
292    // 执行读写接口完成标签数据的读取或写入数据到标签
293    // use the IsoDep technology to access this nfc tag.
294    let isoDep : tag.IsoDepTag | null = null;
295    for (let i = 0; i < tagInfo.technology.length; i++) {
296      if (tagInfo.technology[i] == tag.ISO_DEP) {
297        try {
298          isoDep = tag.getIsoDep(tagInfo);
299        } catch (error) {
300          hilog.error(0x0000, 'testTag', 'getIsoDep error = %{public}s', JSON.stringify(error));
301          return;
302        }
303      }
304      // use other technology to access this nfc tag if necessary.
305    }
306    if (isoDep == undefined) {
307      hilog.error(0x0000, 'testTag', 'getIsoDep is invalid');
308      return;
309    }
310
311    // connect to this nfc tag using IsoDep technology.
312    try {
313        isoDep.connect();
314    } catch (error) {
315        hilog.error(0x0000, 'testTag', 'isoDep.connect() error = %{public}s', JSON.stringify(error));
316        return;
317    }
318    if (!isoDep.isConnected()) {
319      hilog.error(0x0000, 'testTag', 'isoDep.isConnected() false.');
320      return;
321    }
322
323    // transmit data to the connected tag.
324    let cmdData = [0x01, 0x02, 0x03, 0x04]; // please change the raw data to be correct.
325    try {
326      isoDep.transmit(cmdData).then((response : number[]) => {
327        hilog.info(0x0000, 'testTag', 'isoDep.transmit() response = %{public}s.', JSON.stringify(response));
328      }).catch((err : BusinessError)=> {
329        hilog.error(0x0000, 'testTag', 'isoDep.transmit() err = %{public}s.', JSON.stringify(err));
330        return;
331      });
332    } catch (businessError) {
333      hilog.error(0x0000, 'testTag', 'isoDep.transmit() businessError = %{public}s.', JSON.stringify(businessError));
334      return;
335    }
336  }
337}
338```