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```