What is NFC

NFC is a short-range high frequency wireless communication technology that enables the exchange of data between devices over about a 10 cm distance
In fact, the official documents are already very detailed. https://developer.apple.com/documentation/corenfc?language=objc
NFC-enabled devices:
1 , The mobile phone on iOS11 only supports the function of reading, and the tag can be read through the NFC API
The system above iOS13 supports the NFC writing API
The minimum devices that support NFC are iPhone 7 and iPhone 7Plus
Read the NFC tag NDEF
NDEF refers to NFC Data Exchange Format: NFC data exchange format, the data format in the NFC tag agreed by the NFC organization.
NDEF is a lightweight compact binary format that can carry various data types defined by URL, vCard and NFC.
NDEF is composed of various data records, and each record is composed of a header (Header) and a payload (Payload). The data type and size of the NDEF record are indicated by the header of the record payload. The header here contains 3 parts, which are Length, Type and Identifier..
Read more from https://blog.csdn.net/vampire_armand/article/details/39372953
1.Import the header file
object-c
#import <CoreNFC/CoreNFC.h>
Code language: HTML, XML (xml)
swift
# import CoreNFC
Code language: PHP (php)
2.Read NFC 2.1 local configuration in NDEF format
Please refer to : https://developer.apple.com/documentation/corenfc/adding_support_for_background_tag_reading
Open the permission to read NFC tags, Xcode will automatically synchronize to the developer after opening the permission in Appid

Then generate .entitlements file and add permission description
Privacy – NFC Scan Usage Description
String
Official demo address
[Building an NFC Tag-Reader App] Read NFC tags with NDEF messages in your app.
https://developer.apple.com/documentation/corenfc/building_an_nfc_tag-reader_app?language=objc (for scanning NDEF format NFC, iOS11-iOS12 read-only but not writeable, iOS13 and later can read and write)
import
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, NFCSupportsStatus) {
NFCSupportStatusYes,
NFCSupportStatusDeviceNo,
NFCSupportStatusnSystemNo,
};
API_AVAILABLE(ios(11.0))
typedef void(^NFCScanSuccessBlock)(NFCNDEFMessage *message);
typedef void(^NFCScanErrorBlock)(NSError *error);
API_AVAILABLE(ios(13.0))
typedef void(^NFCWriteSuccessBlock)(void);
typedef void(^NFCWritErrorBlock)(NSError *error);
API_AVAILABLE(ios(11.0))
@interface NFCManager : NSObject
@property(nonatomic,copy)NFCScanSuccessBlock scanSuccessBlock;
@property(nonatomic,copy)NFCScanErrorBlock scanErrorBlock;
@property(nonatomic,copy)NFCWriteSuccessBlock writeSuccessBlock;
@property(nonatomic,copy)NFCWritErrorBlock writErrorBlock;
+(NFCManager *)sharedInstance;
+(NFCSupportsStatus)isSupportsNFCReading;
-(void)scanTagWithSuccessBlock:(NFCScanSuccessBlock)scanSuccessBlock andErrorBlock:(NFCScanErrorBlock)scanErrorBlock;
@end
NS_ASSUME_NONNULL_END
import “NFCManager.h”
@interface NFCManager(){
BOOL isReading;
}
@property (strong, nonatomic) NFCNDEFReaderSession *session;
@property (strong, nonatomic) NFCNDEFMessage *message;
@end
@implementation NFCManager
+(NFCManager *)sharedInstance{
static dispatch_once_t onceToken;
static NFCManager * sSharedInstance;
dispatch_once(&onceToken, ^{
sSharedInstance = [[NFCManager alloc] init];
});
return sSharedInstance;
}
+(NFCSupportsStatus)isSupportsNFCReading{
if (@available(iOS 11.0,*)) {
if (NFCNDEFReaderSession.readingAvailable == YES) {
return NFCSupportStatusYes;
}
else{
return NFCSupportStatusDeviceNo;
}
}
else {
return NFCSupportStatusnSystemNo;
}
-(void)scanTagWithSuccessBlock:(NFCScanSuccessBlock)scanSuccessBlock andErrorBlock:(NFCScanErrorBlock)scanErrorBlock{
self.scanSuccessBlock=scanSuccessBlock;
self.scanErrorBlock=scanErrorBlock;
isReading=YES;
[self beginScan];
}
-(void)beginScan{
if (@available(iOS 11.0, *)) {
self.session = [[NFCNDEFReaderSession alloc]initWithDelegate:self queue:nil invalidateAfterFirstRead:NO];
self.session.alertMessage = @”scan start”;
[self.session beginSession];
}
}
-(void)invalidateSession{
[self.session invalidateSession];
}
pragma mark – NFCNDEFReaderSessionDelegate
(void)readerSession:(NFCNDEFReaderSession *)session didInvalidateWithError:(NSError *)error API_AVAILABLE(ios(11.0)){
NSLog(@”%@”,error);
if (error.code == 201) {
NSLog(@”Timeout”);
}
if (error.code == 200) {
NSLog(@”Cancel”);
}
}
(void)readerSession:(NFCNDEFReaderSession )session didDetectNDEFs:(NSArray)messages
API_AVAILABLE(ios(11.0)){
dispatch_async(dispatch_get_main_queue(), ^{
if (self->isReading) {
if (@available(iOS 11.0, *)) {
for (NFCNDEFMessage *message in messages) {
session.alertMessage = @”读取成功;
[self invalidateSession];
if (self.scanSuccessBlock) {
self.scanSuccessBlock(message);
}
}
}
}
else{
//ios11-ios12下没有写入功能返回失败
session.alertMessage = @”读取失败;
[self invalidateSession];
} });
}
//读取成功回调iOS13
(void)readerSession:(NFCNDEFReaderSession *)session didDetectTags:(NSArray<__kindof id> *)tags API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(watchos, macos, tvOS){
dispatch_async(dispatch_get_main_queue(), ^{
if (tags.count>1) {
session.alertMessage=@”存在多个标签多个标签;
[session restartPolling];
return;
}
id tag=tags.firstObject;
[session connectToTag:tag completionHandler:^(NSError * _Nullable error) {
if (error) {
session.alertMessage = @”连接NFC标签失败标签失败;
[self invalidateSession];
return;
}
[tag queryNDEFStatusWithCompletionHandler:^(NFCNDEFStatus status, NSUInteger capacity, NSError * _Nullable error) {
if (error) {
session.alertMessage = @”查询NFC标签状态失败;
[self invalidateSession];
return;
}
if (status == NFCNDEFStatusNotSupported) {
session.alertMessage = @”标签不是NDEF格式;
[self invalidateSession];
return;
}
if (self->isReading) {
//读
[tag readNDEFWithCompletionHandler:^(NFCNDEFMessage * _Nullable message, NSError * _Nullable error) {
if (error) {
session.alertMessage = @”读取NFC标签失败标签失败;
[self invalidateSession];
}
else if (message==nil) {
session.alertMessage = @”NFC标签为空;
[self invalidateSession];
return;
}
else {
session.alertMessage = @”读取成功;
[self invalidateSession];
if (self.scanSuccessBlock) {
self.scanSuccessBlock(message);
}
}
}];
}
else{
//写数据
[tag writeNDEF:self.message completionHandler:^(NSError * _Nullable error) {
if (error) {
session.alertMessage = @”写入失败;
if (self.writErrorBlock) {
self.writErrorBlock(error);
}
}
else {
session.alertMessage = @”写入成功;
if (self.writeSuccessBlock) {
self.writeSuccessBlock();
}
}
[self invalidateSession];
}];
}
}];
}];
});
}
(void)readerSessionDidBecomeActive:(NFCNDEFReaderSession *)session API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(watchos, macos, tvOS){
}
@end
Code language: JavaScript (javascript)
3 Read NFC with tags
>[Creating NFC Tags from Your iPhone] Save data to tags, and interact with them using native tag protocols.
https://developer.apple.com/documentation/corenfc/creating_nfc_tags_from_your_iphone (can scan iso15693, NFC such as iso7816, felica, miFare, etc. can read and write, but must have Aid)
You need to add the corresponding tag in info.plist
, the tag is an array, and add the Aid of the adapted NFC

Note: In the swift project, if you don’t use a certain tag, don’t add it to info.plist, and don’t bring this tag during initialization. If you add this tag to info.plist, you must add Aid, otherwise it will not be able to evoke NFC scanning. page.
Demo Code
NFCManager.h
import
import
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, NFCSupportsStatus) {
NFCSupportStatusYes,
NFCSupportStatusDeviceNo,
NFCSupportStatusnSystemNo,
};
API_AVAILABLE(ios(11.0))
typedef void(^NFCScanSuccessBlock)(NFCNDEFMessage *message);
typedef void(^NFCScanErrorBlock)(NSError *error);
typedef void(^NFCWriteSuccessBlock)(void);
typedef void(^NFCWritErrorBlock)(NSError *error);
API_AVAILABLE(ios(11.0))
@interface NFCManager : NSObject
@property(nonatomic,copy)NFCScanSuccessBlock scanSuccessBlock;
@property(nonatomic,copy)NFCScanErrorBlock scanErrorBlock;
@property(nonatomic,copy)NFCWriteSuccessBlock writeSuccessBlock;
@property(nonatomic,copy)NFCWritErrorBlock writErrorBlock;
@property(nonatomic,assign) BOOL moreTag;
+(NFCManager *)sharedInstance;
-(void)scanTagWithSuccessBlock:(NFCScanSuccessBlock)scanSuccessBlock andErrorBlock:(NFCScanErrorBlock)scanErrorBlock;
-(void)writeMessage:(NFCNDEFMessage *)message ToTagWithSuccessBlock:(NFCWriteSuccessBlock)writeSuccessBlock andErrorBlock:(NFCWritErrorBlock)writErrorBlock;
+(NFCSupportsStatus)isSupportsNFCReading;
+(NFCSupportsStatus)isSupportsNFCWrite;
@end
NS_ASSUME_NONNULL_END
Code language: JavaScript (javascript)
NFCManager.m
import “NFCManager.h”
@interface NFCManager (){
BOOL isReading;
}
@property (strong, nonatomic) NFCTagReaderSession *tagReaderSession;
@property (strong, nonatomic) NFCNDEFMessage *message;
@property(nonatomic,weak)id currentTag;
@end
@implementation NFCManager
pragma mark –
+(NFCManager *)sharedInstance{
static dispatch_once_t onceToken;
static NFCManager * sSharedInstance;
dispatch_once(&onceToken, ^{
sSharedInstance = [[NFCManager alloc] init];
});
return sSharedInstance;
}
-(void)scanTagWithSuccessBlock:(NFCScanSuccessBlock)scanSuccessBlock andErrorBlock:(NFCScanErrorBlock)scanErrorBlock{
self.scanSuccessBlock=scanSuccessBlock;
self.scanErrorBlock=scanErrorBlock;
isReading=YES;
[self beginScan];
}
-(void)writeMessage:(NFCNDEFMessage *)message ToTagWithSuccessBlock:(NFCWriteSuccessBlock)writeSuccessBlock andErrorBlock:(NFCWritErrorBlock)writErrorBlock{
self.message=message;
self.writeSuccessBlock=writeSuccessBlock;
self.writErrorBlock=writErrorBlock;
isReading=NO;
[self beginScan];
}
+(NFCSupportsStatus)isSupportsNFCReading{
if (@available(iOS 11.0,)) { if (NFCNDEFReaderSession.readingAvailable == YES) { return NFCSupportStatusYes; } else{ NSLog(@”%@”,@”该机型不支持NFC功能!”); return NFCSupportStatusDeviceNo; } } else { NSLog(@”%@”,@”当前系统不支持NFC功能不支持NFC功能!”); return NFCSupportStatusnSystemNo; } } +(NFCSupportsStatus)isSupportsNFCWrite{ if (@available(iOS 13.0,)) {
if (NFCNDEFReaderSession.readingAvailable == YES) {
return NFCSupportStatusYes;
}
else{
NSLog(@”%@”,@”该机型不支持NFC功能!”);
return NFCSupportStatusDeviceNo;
}
}
else {
NSLog(@”%@”,@”当前系统不支持NFC功能不支持NFC功能!”);
return NFCSupportStatusnSystemNo;
}
}
-(void)beginScan{
if (@available(iOS 11.0, *)) {
self.tagReaderSession = [[NFCTagReaderSession alloc]initWithPollingOption:NFCPollingISO14443 delegate:self queue:dispatch_queue_create(“beckhams”,DISPATCH_QUEUE_SERIAL)];
self.tagReaderSession.alertMessage = @”message”;
[self.tagReaderSession beginSession];
}
}
-(NFCNDEFMessage)createAMessage{ NSString type = @”U”;
NSData* typeData = [type dataUsingEncoding:NSUTF8StringEncoding];
NSString* identifier = @”12345678″;
NSData* identifierData = [identifier dataUsingEncoding:NSUTF8StringEncoding];
NSString* payload1 = @”ahttps://www.baidu.com”;
NSData* payloadData1 = [payload1 dataUsingEncoding:NSUTF8StringEncoding];
if (@available(iOS 13.0, *)) {
NFCNDEFPayload *NDEFPayload1=[[NFCNDEFPayload alloc]initWithFormat:NFCTypeNameFormatNFCWellKnown type:typeData identifier:identifierData payload:payloadData1];
NFCNDEFMessage* message = [[NFCNDEFMessage alloc]initWithNDEFRecords:@[NDEFPayload1]];
return message;
} else {
return nil;
}
}
-(void)invalidateSession{
[self.tagReaderSession invalidateSession];
}
(void)tagReaderSession:(NFCTagReaderSession *)session didDetectTags:(NSArray<__kindof id> *)tags API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(watchos, macos, tvos){
if (tags.count > 1){
NSLog(@”读卡错误;
return;
} id Tag7816 = [tags.firstObject asNFCISO7816Tag];
if (Tag7816 == nil){
NSLog(@”读取到的非7816卡片;
return;
}
}
NSLog(@”Tag7816.initialSelectedAID:%@”,Tag7816.initialSelectedAID);
__weak typeof(self) weakSelf = self;
[self.tagReaderSession connectToTag:Tag7816 completionHandler:^(NSError * _Nullable error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (error){
NSLog(@”TconnectToTag:%@”,error);
return;
}
self.currentTag = Tag7816;
self.tagReaderSession.alertMessage = @”已识别到NFC;
[self sendApduSingle:@”00A400000112501″]; }];
}
-(void)sendApduSingle:(NSString *)apduStr{
// apduStr : 00A5030004B000000033434561
NSData *apduData = [self convertHexStrToData:apduStr];
NFCISO7816APDU *cmd = [[NFCISO7816APDU alloc]initWithData:apduData];
__block NSData *recvData = nil;
__block NSError *lerror = nil;
__block BOOL bRecv = NO;
__block int lsw = 0;
NSLog(@”send data => %@”, apduData);
[self.currentTag sendCommandAPDU:cmd completionHandler:^(NSData * _Nonnull responseData, uint8_t sw1, uint8_t sw2, NSError * _Nullable error) {
NSLog(@”——resp:%@ sw:%02x%02x error:%@”, responseData, sw1, sw2, error);
NSLog(@”responseData十六进制%@”, [self convertApduListDataToHexStr:responseData]);
lerror = error;
lsw = sw1;
lsw = (lsw << 8) | sw2;
if (responseData) {
recvData = [[NSData alloc]initWithData:responseData];
}
[self invalidateSession];
}];
}
(NSData *)convertHexStrToData:(NSString *)str {
if (!str || [str length] == 0) {
return nil;
}
NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
NSRange range;
if ([str length] % 2 == 0) {
range = NSMakeRange(0, 2);
} else {
range = NSMakeRange(0, 1);
}
for (NSInteger i = range.location; i < [str length]; i += 2) {
unsigned int anInt;
NSString *hexCharStr = [str substringWithRange:range];
NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr]; [scanner scanHexInt:&anInt]; NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1]; [hexData appendData:entity]; range.location += range.length; range.length = 2; }
return hexData;
}
-(NSString *)convertApduListDataToHexStr:(NSData *)data{
if (!data || [data length] == 0) {
return @””;
}
NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
unsigned char *dataBytes = (unsigned char*)bytes;
for (NSInteger i = 0; i < byteRange.length; i++) {
NSString *hexStr = [NSString stringWithFormat:@”%x”, (dataBytes[i]) & 0xff];
if ([hexStr length] == 2) {
[string appendString:hexStr];
} else {
[string appendFormat:@”0%@”, hexStr];
}
}
}];
return [string uppercaseString];
}
(void)tagReaderSession:(NFCTagReaderSession *)session didInvalidateWithError:(NSError *)error API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(watchos, macos, tvos){
NSLog(@”%@”,error);
}
@end
Code language: JavaScript (javascript)
This article is mainly about the interaction between mobile phone nfc and ISO7816 protocol.