美文网首页工具iOS集合NFC
iOS开发之NFC的使用

iOS开发之NFC的使用

作者: Streamsle | 来源:发表于2021-11-19 13:36 被阅读0次

    一、了解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 <CoreNFC/CoreNFC.h>
    

    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 <Foundation/Foundation.h>
    #import <CoreNFC/CoreNFC.h>
    
    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()<NFCNDEFReaderSessionDelegate>{
        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<NFCNDEFTag>> *)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 <Foundation/Foundation.h>
    #import <CoreNFC/CoreNFC.h>
    
    
    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 ()<NFCTagReaderSessionDelegate>{
        BOOL isReading;
    }
    
    @property (strong, nonatomic) NFCTagReaderSession *tagReaderSession;
    
    @property (strong, nonatomic) NFCNDEFMessage *message;
    
    @property(nonatomic,weak)id<NFCISO7816Tag> 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<NFCTag>> *)tags API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(watchos, macos, tvos){
        if (tags.count > 1){
            NSLog(@"读卡错误");
            return;
        }
        
        
        id<NFCISO7816Tag> 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<UInt8>)
         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的使用

        本文链接:https://www.haomeiwen.com/subject/wqzwzltx.html