先了解几个概念 什么是NFC? NDEF指的是什么? 什么是CoreNFC?
NFC框架
什么是 NFC
NFC(Near Field Communication)即近距离无线通讯技术。该技术由飞利浦公司和索尼公司共同开发,可以在移动设备、消费类电子产品、PC 和智能控件工具间进行近距离无线通信。NFC提供了一种简单、触控式的解决方案,可以让消费者简单直观地交换信息、访问内容与服务。 NFC通信技术,允许电子设备之间进行非接触式点对点数据传输(在十厘米内)交换数据。这个技术由免接触式射频识别(RFID)演变而来,并向下兼容RFID,主要用于手机等手持设备中提供M2M(Machine to Machine)的通信。由于近场通讯具有天然的安全性。 NFC是一种短距高频的无线电技术,在13.56MHz频率运行于10厘米距离内。其传输速度有106 Kbit/秒、212 Kbit/秒或者424 Kbit/秒三种。目前近场通信已通过成为ISO/IEC IS 18092国际标准、ECMA-340标准与ETSI TS 102 190标准。NFC采用主动和被动两种读取模式。
NDEF指的是什么?
NFC Data Exchange Format : NFC数据交换格式,NFC组织约定的NFC tag中的数据格式。 NDEF是轻量级的紧凑的二进制格式,可带有URL、vCard和NFC定义的各种数据类型。 NDEF的由各种数据记录组成,而各个记录由报头(Header)和有效载荷(Payload)组成,其中NDEF记录的数据类型和大小由记录载荷的报头注明,这里的报头包含3部分,分别为Length、Type和Identifier.。 NFC Data Exchange Format : NFC数据交换格式,NFC组织约定的NFC tag中的数据格式。
什么是CoreNFC?
CoreNFC是苹果推出的支持NFC通讯的框架,CoreNFC读取的是NDEF标签的数据。
支持的设备:
iOS开发
plist配置: Privacy - NFC Scan Usage Description分析:
引入NFC库 #import <CoreNFC/CoreNFC.h> 执行协议
**注意⚠️:读取功能iOS11系统开始可以使用,写入功能iOS13系统才可以使用。 **
NFCNDEFReaderSession *session;//nfc会话
NFCNDEFMessage *message;//扫描的消息体结构
//MARK:开始扫描nfc
-(void)startByNFCScaning:(void(^)(NSString *))finishBlock{
if (!NFCNDEFReaderSession.readingAvailable) {
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"扫不到" message:@"设备不支持" preferredStyle:UIAlertControllerStyleAlert];
[alertVC addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self.vc presentViewController:alertVC animated:YES completion:nil];
return;
}
if (self.session) {
NSLog(@"nfc已经存在");
return;
}
self.isWrite = NO;
self.session = [[NFCNDEFReaderSession alloc]initWithDelegate:self queue:nil invalidateAfterFirstRead:NO];
self.session.alertMessage = @"把你的iPhone放在一个NDEF标签附近读信息。";
[self.session beginSession];
NSLog(@"开始扫描");
self.finishBlock = finishBlock;
}
-(void)writeByNFCScaning:(NSString *)message {
if (!NFCNDEFReaderSession.readingAvailable) {
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"扫不到" message:@"设备不支持" preferredStyle:UIAlertControllerStyleAlert];
[alertVC addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self.vc presentViewController:alertVC animated:YES completion:nil];
return;
}
if (self.session) {
NSLog(@"nfc已经存在");
return;
}
self.isWrite = YES;
self.writeMessage = message;
self.session = [[NFCNDEFReaderSession alloc]initWithDelegate:self queue:nil invalidateAfterFirstRead:false];
self.session.alertMessage = @"把你的iPhone放在一个NDEF标签附近写信息。";
[self.session beginSession];
NSLog(@"开始写入");
}
//MARK:NFCNDEFReaderSessionDelegate
//error
- (void)readerSession:(NFCNDEFReaderSession *)session didInvalidateWithError:(NSError *)error{
if (error &&
error.code != NFCReaderSessionInvalidationErrorFirstNDEFTagRead &&
error.code != NFCReaderSessionInvalidationErrorUserCanceled) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"通信错误" message:error.description?:@"异常" preferredStyle:UIAlertControllerStyleAlert];
[alertVC addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self.vc presentViewController:alertVC animated:YES completion:nil];
});
}
self.session = nil;
}
//message
-(void)readerSession:(NFCNDEFReaderSession *)session didDetectNDEFs:(NSArray<NFCNDEFMessage *> *)messages{
self.session.alertMessage = @"识别成功";
[self.session invalidateSession];
dispatch_async(dispatch_get_main_queue(), ^{
self.message = messages.firstObject;
[self dataHandle];
});
}
//新方法
//新message
- (void)readerSession:(NFCNDEFReaderSession *)session didDetectTags:(NSArray<__kindof id<NFCNDEFTag>> *)tags API_AVAILABLE(ios(13.0)){
if (tags.count > 1) {
self.session.alertMessage = @"检测到多个标记,请删除所有标记并重试。";
[self tagRemovalDetect:tags.firstObject];
return;
}
id<NFCNDEFTag> tag = tags.firstObject;
[self.session connectToTag:tag completionHandler:^(NSError * _Nullable error) {
if (error != nil) {
[self.session restartPolling];
return;
}
//查询状态
[tag queryNDEFStatusWithCompletionHandler:^(NFCNDEFStatus status, NSUInteger capacity, NSError * _Nullable error) {
if (error != nil) {
[self.session invalidateSessionWithErrorMessage:@"无法确定NDEF状态。请再试一次。"];
return;
}
if (self.isWrite) {//写入
if (status == NFCNDEFStatusReadOnly) {
[self.session invalidateSessionWithErrorMessage:@"标记不可写。"];
return;
}else if (status == NFCNDEFStatusReadWrite){
if (self.message.length > capacity) {
[self.session invalidateSessionWithErrorMessage:@"标签容量太小。最小大小要求是\(self.ndefMessage!.length)字节。"];
return;
}
[tag writeNDEF:self.message completionHandler:^(NSError * _Nullable error) {
if (error != nil) {
[self.session invalidateSessionWithErrorMessage:@"更新标签失败了。请再试一次。"];
}else{
self.session.alertMessage = @"更新成功!";
[self.session invalidateSession];
}
}];
} else {
[self.session invalidateSessionWithErrorMessage:@"标签不是NDEF格式的。"];
}
}else{//读取
if (status == NFCNDEFStatusNotSupported) {
self.session.alertMessage = @"标签不兼容NDEF";
[self.session invalidateSession];
return;
}
[tag readNDEFWithCompletionHandler:^(NFCNDEFMessage * _Nullable message, NSError * _Nullable error) {
NSString *statusMessage;
if (nil != error || nil == message) {
statusMessage = @"读取NDEF from标签失败";
}else{
statusMessage = @"识别成功";
dispatch_async(dispatch_get_main_queue(), ^{
self.message = message;
[self dataHandle];
});
}
self.session.alertMessage = statusMessage;
[self.session invalidateSession];
}];
}
}];
}];
}
//写入
- (void)readerSessionDidBecomeActive:(NFCNDEFReaderSession *)session API_AVAILABLE(ios(13.0)){
if (self.isWrite) {
NFCNDEFPayload *urlPayload = [NFCNDEFPayload wellKnownTypeURIPayloadWithString:self.writeMessage];
NSLog(@"初始化写入数据:%@",self.writeMessage);
self.message = [[NFCNDEFMessage alloc]initWithNDEFRecords:@[urlPayload]];
NSLog(@"MessageSize=%d",self.message.length);
}
}
//解析数据处理
-(void)dataHandle{
NFCNDEFPayload *payload = self.message.records.firstObject;
NSString *title = [[NSString alloc]initWithData:payload.payload encoding:NSUTF8StringEncoding];
NSString *type = [[NSString alloc]initWithData:payload.type encoding:NSUTF8StringEncoding];
if (@available(iOS 13.0, *)) {
switch (payload.typeNameFormat) {
case NFCTypeNameFormatNFCWellKnown:{
if (type != nil) {
NSURL *url = [payload wellKnownTypeURIPayload];
if (url.absoluteString != nil) {
title = url.absoluteString;
}else{
title = title;
}
}
}
break;
case NFCTypeNameFormatAbsoluteURI:{
if (title != nil) {
title = title;
}
}
break;
case NFCTypeNameFormatMedia:{
if (type != nil) {
title = type;
}
}
break;
case NFCTypeNameFormatNFCExternal:
case NFCTypeNameFormatEmpty:
case NFCTypeNameFormatUnknown:
case NFCTypeNameFormatUnchanged:{
title = @"...";
}
break;
default:
title = @"...";
break;
}
title = [title componentsSeparatedByString:@","].lastObject;
}
if (self.finishBlock) {
self.finishBlock(title);
}
}
//轮询
-(void)tagRemovalDetect:(id<NFCNDEFTag>)tag API_AVAILABLE(ios(13.0)){
[self.session connectToTag:tag completionHandler:^(NSError * _Nullable error) {
if (error != nil || !tag.isAvailable) {
NSLog(@"Restart polling");
[self.session restartPolling];
return;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(500 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self tagRemovalDetect:tag];
});
}];
}