iOS开发之NFC的使用

一、了解NFC
iOS开发关于NFC的使用,其实官方文档已经很详细了,先上官方文档:
文档地址:https://developer.apple.com/documentation/corenfc?language=objc
支持NFC的设备:
1、iOS11上的手机只支持读的功能,可以通过手机的NFC功能读标签.
2、iOS13以上的系统支持写的功能。
3、支持NFC的最低设备为iPhone 7和iPhone 7Plus

二、读取NFC标签NDEF
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中的数据格式。
详情可以参考:https://blog.csdn.net/vampire_armand/article/details/39372953
1、导入头文件
object-c

#import 

swift

import CoreNFC

2、读取NDEF格式的NFC
2.1本地配置
参考官方文档:https://developer.apple.com/documentation/corenfc/adding_support_for_background_tag_reading
2.1.1打开读取NFC标签权限,Xcode打开权限后会自动同步到开发者的Appid中

image.png
image.png

同时生成.entitlements文件


image.png

2.1.2 添加权限描述
Privacy - NFC Scan Usage Description
String


image.png

官方demo地址
[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(用于扫描NDEF格式的NFC,iOS11-iOS12只读不能写,iOS13以后可以读可写)
代码

#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);
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

#pragma mark - 单例方法
+(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{
            NSLog(@"%@",@"该机型不支持NFC功能!");
            return NFCSupportStatusDeviceNo;
        }
    }
    else {
        NSLog(@"%@",@"当前系统不支持NFC功能!");
        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 = @"准备扫描,请将卡片贴近手机";
        [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(@"扫描超时");
    }
    if (error.code == 200) {
        NSLog(@"取消扫描");
    }
}

//读取成功回调iOS11-iOS12
- (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

3、读取带标签的NFC
[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(可以扫描iso15693、iso7816、felica、miFare等NFC,可以读、写,但是必须有Aid)
3.1 需要在info.plist中添加对应的标签,标签为数组,添加所适配NFC的Aid

image.png

注意:swift项目中,如果不使用某标签,info.plist就不要添加,初始化的时候也不要带该标签,如果info.plist添加了该标签,一定要加Aid,否则会导致无法唤起NFC扫描的页面。
3.2代码
object-c
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

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功能!");
        return NFCSupportStatusnSystemNo;
    }
}
+(NFCSupportsStatus)isSupportsNFCWrite{
    if (@available(iOS 13.0,*)) {
        if (NFCNDEFReaderSession.readingAvailable == YES) {
            return NFCSupportStatusYes;
        }
        else{
            NSLog(@"%@",@"该机型不支持NFC功能!");
            return NFCSupportStatusDeviceNo;
        }
    }
    else {
        NSLog(@"%@",@"当前系统不支持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];
    //这里的Tag7816实例是用于后面发送指令的对象。
    if (Tag7816 == nil){
        NSLog(@"读取到的非7816卡片");
        return;
    }
    // 这里获取到的AID就是第一步中在info.plist中设置的ID (A000000000)这个值一般是卡商提供的,代表卡的应用表示。
    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";
        // 这里就可以开始执行指令和cpu卡交互了。
        [self sendApduSingle:@"00A400000112501"];//16进制指令

        
    }];
}
// 发送指令的示例代码:
-(void)sendApduSingle:(NSString *)apduStr{
    //  apduStr 是发送的指令字符串,比如 00A5030004B000000033434561
    NSData *apduData = [self convertHexStrToData:apduStr]; // 把指令转成data格式
    NFCISO7816APDU *cmd = [[NFCISO7816APDU alloc]initWithData:apduData];  // 初始化 NFCISO7816APDU。
    
    __block NSData *recvData = nil;
    __block NSError *lerror = nil;
    __block BOOL bRecv = NO;
    __block int lsw = 0;
    NSLog(@"send data => %@", apduData);
    
    // 这里的Tag7816就是上面协议中拿到的tag
    [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
- (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;
}


//NSData转字符串
-(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

Swift

import UIKit
import CoreNFC

class SwiftNFCManager: NSObject ,NFCTagReaderSessionDelegate{
    enum NFCSupportsStatus : NSInteger {
        case NFCSupportStatusYes = 0 //支持
        case NFCSupportStatusDeviceNo = 1 //硬件不支持
        case NFCSupportStatusnSystemNo = 2//系统不支持
    }
    typealias  block = (Data,Bool) -> Void
    var completeHandle:block?
    typealias  NFCScanSuccessBlock = (String) -> Void
    typealias  NFCScanErrorBlock = (String) -> Void
    var delegate:NfcProtocol?
    var isReading:Bool?
    var scanSuccessBlock:NFCScanSuccessBlock?
    var scanErrorBlock:NFCScanErrorBlock?
    var tagSession:NFCTagReaderSession?
    var currentTag:NFCISO7816Tag?
    static let shared = SwiftNFCManager()
    
    class func isSupportsNFCReading()->NFCSupportsStatus{
        if #available(iOS 11.0, *){
            if NFCNDEFReaderSession.readingAvailable == true{
                return NFCSupportsStatus.NFCSupportStatusYes
            }else{
                print("该机型不支持NFC功能!")
                return NFCSupportsStatus.NFCSupportStatusDeviceNo
            }
        }else{
            print("当前系统不支持NFC功能!")
            return NFCSupportsStatus.NFCSupportStatusnSystemNo
        }
    }
    class func isSupportsNFCWrite()->NFCSupportsStatus{
        if #available(iOS 13.0, *){
            if NFCNDEFReaderSession.readingAvailable == true{
                return NFCSupportsStatus.NFCSupportStatusYes
            }else{
                print("该机型不支持NFC功能!")
                return NFCSupportsStatus.NFCSupportStatusDeviceNo
            }
        }else{
            print("当前系统不支持NFC写入功能!")
            return NFCSupportsStatus.NFCSupportStatusnSystemNo
        }
    }
    func startScanNFC(successBlock:@escaping NFCScanSuccessBlock,errorBlock:@escaping NFCScanErrorBlock) {
        scanSuccessBlock = successBlock
        scanErrorBlock = errorBlock
        isReading = true
        self.beginScan()
    }
    func beginScan() {
        if #available(iOS 11.0, *){
            tagSession = NFCTagReaderSession(pollingOption: [.iso14443, .iso15693, .iso18092], delegate: self, queue: nil)
            tagSession?.alertMessage = "Hold your iPhone near an NFC Type 2 tag."
               tagSession?.begin()
        }
    }
    //停止扫描
    func invalidateSession() {
        self.tagSession?.invalidate()
    }
    
    
    //MARK: NFCTagReaderSessionDelegate
     
     func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
         print("tagReaderSessionDidBecomeActive")
     }
     
     func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
         scanErrorBlock!("扫描NFC失败")
         print("error:\(error)")
     }
     
     func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
         
         if tags.count > 1 {
             print("读卡错误")
             scanErrorBlock!("读卡错误")
             session.alertMessage = "More than 1 tags was found. Please present only 1 tag."
             return
         }
         
         
         let Tag7816:NFCTag = tags.first!
         switch Tag7816 {
         case .feliCa(_):
             print("NFCFeliCaTag")
         case let .iso7816(tag):
             // 这里获取到的AID就是第一步中在info.plist中设置的ID (A000000000)这个值一般是卡商提供的,代表卡的应用表示。
             self.tagSession?.connect(to: Tag7816, completionHandler: {[weak self] (error) in
                 if error != nil {
                     print("TconnectToTag:\(String(describing: error))")
                     session.invalidate(errorMessage: "Connection error. Please try again.")
                     self?.delegate?.connectNfcError()
                     return
                 }
                 self?.delegate?.connectNfcSuccess()
                 self?.currentTag = tag
                 self?.tagSession?.alertMessage = "已经识别到NFC"
                 self?.invalidateSession()
             })
         case .iso15693(_):
             print("NFCISO15693Tag")
         case .miFare(_):
             print("NFCMiFareTag")
         @unknown default:
             session.invalidate(errorMessage: "Tag not valid.")
             return
         }

     }
     

     
     func sendApduSingle(apduStr:String,comPlete:block){
         let sendData:Data = self.convertHexStrToData(hexStr: apduStr)
         let cmd:NFCISO7816APDU = NFCISO7816APDU.init(data: sendData)!
         var resultError:NSError?
         var result:Data?
         self.currentTag?.sendCommand(apdu: cmd, completionHandler: { [weak self] (resultData, sw1, sw2, error) in
             print("resultData:\(resultData)\nsw1:\(sw1)\nsw2:\(sw2)\nerror:\(String(describing: error))")
             print("rusultData转16进制:\(String(describing: self?.string(from: resultData)))")

             result = resultData
             resultError = error as NSError?
         })
         
         if resultError == nil{
             comPlete(result ?? Data.init(),true)
         }else{
             comPlete(Data.init(),false)
         }
     }
     
     
     
     //将十六进制字符串转化为 Data
     func convertHexStrToData(hexStr:String) -> Data {
         let bytes = self.bytes(from: hexStr)
 //        let bytes = hexStr.bytes(from: hexStr)
         return Data.init(_:bytes)
     }
     
     // 将16进制字符串转化为 [UInt8]
       // 使用的时候直接初始化出 Data
       // Data(bytes: Array)
     func bytes(from hexStr: String) -> [UInt8] {
         assert(hexStr.count % 2 == 0, "输入字符串格式不对,8位代表一个字符")
         var bytes = [UInt8]()
         var sum = 0
         // 整形的 utf8 编码范围
         let intRange = 48...57
         // 小写 a~f 的 utf8 的编码范围
         let lowercaseRange = 97...102
         // 大写 A~F 的 utf8 的编码范围
         let uppercasedRange = 65...70
         for (index, c) in hexStr.utf8CString.enumerated() {
             var intC = Int(c.byteSwapped)
             if intC == 0 {
                 break
             } else if intRange.contains(intC) {
                 intC -= 48
             } else if lowercaseRange.contains(intC) {
                 intC -= 87
             } else if uppercasedRange.contains(intC) {
                 intC -= 55
             } else {
                 assertionFailure("输入字符串格式不对,每个字符都需要在0~9,a~f,A~F内")
             }
             sum = sum * 16 + intC
             // 每两个十六进制字母代表8位,即一个字节
             if index % 2 != 0 {
                 bytes.append(UInt8(sum))
                 sum = 0
             }
         }
         return bytes
     }
     //讲Data转String
     func string(from data: Data) -> String {
             return String(format: "%@", data as CVarArg)
         }

demo

本文主要是手机nfc与ISO7816协议间的交互。例如上海交通卡遵守的是ISO7816协议,可以正常获取上海交通卡的余额等信息。(卡的Aid可以从交通卡ipa包中获取)

你可能感兴趣的:(iOS开发之NFC的使用)