iOS NFC 功能開發(fā)

在項目開發(fā)中,使用到了NFC功能被碗,然后對NFC功能進行了研究和使用總結(jié)。記錄下來可以方便后續(xù)的使用。

NFC的官方文檔:https://developer.apple.com/documentation/corenfc/nfctagreadersession?language=objc

1木柬、NFC簡介

NFC(Near Field Communication,NFC)近場通信,是一種短距高頻的無線電技術淹办,在13.56MHz頻率運行于10厘米距離內(nèi)眉枕。其傳輸速度有106 Kbit/秒、212 Kbit/秒或者424 Kbit/秒三種怜森。

使用了NFC技術的設備(比如手機)可以在彼此靠近的情況下進行數(shù)據(jù)交換速挑,是由非接觸式射頻識別(RFID)及互連互通技術整合演變而來,通過在單一芯片上集成感應式讀卡器副硅、感應式卡片和點對點通信的功能姥宝,利用移動終端實現(xiàn)移動支付、電子票務恐疲、門禁腊满、移動身份識別套么、防偽等應用。目前碳蛋,蘋果的CoreNFC對NFC的格式支持有限胚泌,暫時僅支持NDEF格式。

2疮蹦、NDEF 簡介

NDEF(NFC Data Exchange Format)是一種能夠在NFC設備或者標簽之間進行信息交換的數(shù)據(jù)格式诸迟。NDEF格式由各種 NDEF Messages 和 NDEF Records 組成。NDEF格式使用了一種容易理解的格式來存儲和交換信息愕乎,如:URI阵苇、純文本等等。

NFC標簽感论,像Mifare Classic卡片可以配置為NDEF標簽,通過一個NFC設備寫入的數(shù)據(jù)可以被其他NDEF兼容的設備訪問绅项。NDEF消息還可以用于兩個活躍的NFC設備之間“點對點”模式交換數(shù)據(jù)。

一比肄、NFC 啟動前配置

1快耿、修改開發(fā)者賬號中 APP ID 模塊權限,勾選NFC功能

APP ID
?? NFC 模塊

2芳绩、修改項目中配置掀亥,添加 NFC 功能模塊

添加 NFC 功能模塊
添加 NFC 模塊成功
配置文件生成 . entitlements 文件

3、配置文件配置NFC權限

添加 NFCReaderUsageDescription 權限描述
<key>NFCReaderUsageDescription</key>
<string>App Requires NFC to read the card details</string>

添加 iso7816 協(xié)議描述
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>A000000243001300000001FF</string>
<string>A0000002430013000000010109</string>
<string>A00000024300130000000101</string>
<string>00000000000000</string>
</array>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
<string>TAG</string>
</array>

添加 NFC 權限描述
添加 iso7816 協(xié)議描述

二妥色、NFC 實際應用使用

1搪花、NFC 代碼使用

導入頭文件

#import <CoreNFC/CoreNFC.h>

@property (nonatomic, strong) NFCTagReaderSession *session;
@property ( strong , nonatomic ) id<NFCISO7816Tag> currentTag;

啟用NFC功能代碼,以下是使用 NFCTagReaderSession 進行的操作嘹害。

if (@available(iOS 13.0, *)) {
    // 初始化 NFC 設置代理 NFCTagReaderSessionDelegate
    self.session = [[NFCTagReaderSession alloc]
                initWithPollingOption:NFCPollingISO14443 delegate:self queue:nil];
    // NFC 顯示提示信息
    self.session.alertMessage = @"準備掃描撮竿,請將卡片貼近手機";
    // 開啟 NFC
    [self.session beginSession];

} else {
     [AlertView showAlertTitle:ALERT withMessage:NFC_NOT_SUPPORT onView:self];
}

以下是使用 NFCTagReaderSessionDelegate 進行的操作。

#pragma mark - NFCNDEFReaderSessionDelegate
//讀取失敗回調(diào)-讀取成功后還是會回調(diào)這個方法
- (void)tagReaderSessionDidBecomeActive:(NFCTagReaderSession *)session  API_AVAILABLE(ios(13.0)){
    NSLog(@"tagReaderSessionDidBecomeActive");
}

- (void)tagReaderSession:(NFCTagReaderSession *)session didInvalidateWithError:(NSError *)error  API_AVAILABLE(ios(13.0)){
    NSLog(@"readerSession:didInvalidateWithError: (%@)", [error localizedDescription]);
}

- (void)tagReaderSession:(NFCTagReaderSession *)session didDetectTags:(NSArray<__kindof id<NFCTag>> *)tags   API_AVAILABLE(ios(13.0)){
     NSLog(@"readerSession:didDetectTags");
    if ([tags count] > 1) {
        [session setAlertMessage:@"More than 1 tag is detected, please try again"];
        [session restartPolling];
        return;
    }
    
     id<NFCTag> firstTag =  tags[0];
     NSLog(@"firstTag %@",firstTag);
    
    if (firstTag.type == NFCTagTypeMiFare) {
        [session setAlertMessage:@"A tag that is not iso7816 is detected, please try again with tag iso7816"];
        NSLog(@"session restartPolling");
        [session restartPolling];
    }
    
//    NSString *requestId = [Utils generateSecureKey];

    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void) {
        
    if (@available(iOS 13.0, *)) {
        if (firstTag.type == NFCTagTypeISO7816Compatible) {
            id<NFCISO7816Tag> iso7816Tag = [firstTag asNFCISO7816Tag];
            @try {
                
                NSLog(@"Tag7816.initialSelectedAID:%@",iso7816Tag.initialSelectedAID);
                   __weak typeof(self) weakSelf = self;
                [self.session connectToTag:iso7816Tag completionHandler:^(NSError * _Nullable error) {
                       __strong typeof(weakSelf) strongSelf = weakSelf;
                       if (error){
                           NSLog(@"TconnectToTag:%@",error);
                           return;
                       }
                       self.currentTag = iso7816Tag;
                       self.session.alertMessage = @"已識別到NFC";
                       // 這里就可以開始執(zhí)行指令和cpu卡交互了笔呀。
                       [self sendApduSingle:@"00A400000112501"];//16進制指令
                }];

            
//
                dispatch_async(dispatch_get_main_queue(), ^{
        
                    [session setAlertMessage:@"Reading Completed, session going to close"];
                    [session invalidateSession];
                });// update UI main queue
              }
            @catch (NSException *exception) {
                 [session invalidateSession];
                  NSString *exe =[NSString stringWithFormat:@"%@\n%@\n%@",exception.name,exception.description,exception.userInfo];
//                  [AlertView showAlertTitle:ALERT withMessage:exe onView:self];
                NSLog(@"exception==%@",exception);
              }// catch
              @finally {
              }// finally
        }
     } else {
         dispatch_async(dispatch_get_main_queue(), ^{
            // Fallback on earlier versions
             NSLog(@"Fallback on earlier versions");
//            [AlertView showAlertTitle:ALERT withMessage:NFC_NOT_SUPPORT onView:self];
         });// update UI main queue
      }
   });// background queue
}

二幢踏、NFC寫數(shù)據(jù)的能力

NFC寫數(shù)據(jù)的功能主要表現(xiàn)為可以寫數(shù)據(jù)到對應的卡上(和具體硬件進行交互,比如CPU卡)注:本文主要是手機nfc與CPU卡就ISO7816協(xié)議間的交互许师。

1房蝉、什么是CPU卡

CPU 卡又叫智能卡,卡內(nèi)具有中央處理器(CPU)微渠、隨機存儲器(RAM)惨驶、程序存儲器(ROM)、數(shù)據(jù)存儲器(EEPROM)以及片內(nèi)操作系統(tǒng)(COS)敛助。CPU 卡可適用于金融粗卜、保險、*纳击、政府行業(yè)等多個領域续扔,具有用戶空間大攻臀、讀取速度快、支持一卡多用等特點纱昧,并已經(jīng)通過中國人民銀行和國家商秘委的認證刨啸。

2、CPU 卡的標準化

由于當前世界各國經(jīng)濟正在向國際化方向發(fā)展识脆,全球化的金融服務系統(tǒng)紛紛建立起來设联,這就帶來了一個卡的互操作性問題。同一張卡灼捂,在不同的國家离例、不同的環(huán)境下都要能夠使用。要解決這個問題悉稠,只有制定一系列國際標準宫蛆,使CPU卡及其接口設備制造商按照統(tǒng)一的標準,制造統(tǒng)一接口規(guī)格的產(chǎn)品的猛,以保證不同國家耀盗、不同行業(yè)都采用統(tǒng)一的CPU卡軟硬件技術規(guī)范開發(fā)應用系統(tǒng),這樣才能實現(xiàn)不同廠家生產(chǎn)的CPU卡之間的互換性和接口設備的共享卦尊。國際標準化組織從1987年開始叛拷,相繼制定和頒布了CPU卡的國際標準碗誉。有關CPU卡本身的標準有:
ISO 10536:識別卡-非接觸式的集成電路卡
ISO 7816:識別卡-帶觸點的集成電路卡
ISO7816-1:規(guī)定卡的物理特性匣沼。卡的物理特性中描述了卡應達到的防護紫外線的能力赚楚、X光照射的劑量淌友、卡和觸點的機械強度、抗電磁干擾能力等等骇陈。
ISO7816-2:規(guī)定卡的尺寸和位置震庭。
ISO7816-3:規(guī)定卡的電信號和傳輸協(xié)議。傳輸協(xié)議包括兩種:同步傳輸協(xié)議和異步傳輸協(xié)議
ISO7816-4:規(guī)定卡的行業(yè)間交換用命令你雌。包括:在卡與讀寫間傳送的命令和應答信息內(nèi)容器联;在卡中的文件、數(shù)據(jù)結(jié)構(gòu)及訪問方法婿崭;定義在卡中的文件和數(shù)據(jù)訪問權限及安全結(jié)構(gòu)拨拓。

3、有關金融領域CPU卡應用的標準有:

ISO 9992:金融交易卡-集成電路卡與受卡接受設備之間的信息
ISO 14443:識別卡-非接觸卡規(guī)范(距離10cm)
ISO 10202:金融交易卡-使用集成電路卡的金融交易系統(tǒng)的安全結(jié)構(gòu)
EMV:支付系統(tǒng)的集成電路卡規(guī)范和支付系統(tǒng)的集成電路卡終端規(guī)范氓栈。中國金融集成電路(IC)卡規(guī)范:1998年3月中國人民銀行等近十家金融單位在采用國際標準和國外先進技術的原則下渣磷,以ISO標準和Europay、Mastercard授瘦、Visa三大組織研制的EMV96為基礎醋界,結(jié)合國內(nèi)CPU卡的應用實際需要竟宋,對我國金融CPU卡的基本應用作出了具體規(guī)定。

NFC 寫入 CPU卡方法,使用的是NFCTagReaderSession

- (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實例是用于后面發(fā)送指令的對象形纺。
    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";
        // 這里就可以開始執(zhí)行指令和cpu卡交互了逐样。
        [self sendApduSingle:@"00A400000112501"];//16進制指令
    }];
}
// 發(fā)送指令的示例代碼:
-(void)sendApduSingle:(NSString *)apduStr{
    //  apduStr 是發(fā)送的指令字符串蜗字,比如 00A5030004B000000033434561
    NSData *apduData = [self convertHexStrToData:apduStr]; // 把指令轉(zhuǎn)成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就是上面協(xié)議中拿到的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];
        }
        // 拿到返回的數(shù)據(jù)了脂新,根據(jù)具體的業(yè)務需求去寫代碼挪捕。。戏羽。担神。
        [self invalidateSession];
    }];
}


//將字符串轉(zhuǎn)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轉(zhuǎn)字符串
-(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);
}

需要注意點:使用NFC也需要打開藍牙權限

如果沒有藍牙權限,可能會崩潰始花,需求申請藍牙權限妄讯。

    <key>NSBluetoothAlwaysUsageDescription</key>
    <string>Bluetooth open</string>
    <key>NSBluetoothPeripheralUsageDescription</key>
    <string>App need your approval to access to the bluetooth</string>

注意點:

NDEF 的 URI 格式 限制
這些情況下無法使用后臺 NFC 功能:

重啟手機后,沒有解鎖過
有一個 NFC 進程正在運行
Apple 錢包正在使用
相機正在使用
飛行模式下

具體 iOS NFC 開發(fā)流程

AppleID 開通 NFC Tag Reading 功能酷宵。
工程進行描述文案等配置亥贸。
代碼開發(fā)。
如果需要支持后臺掃描浇垦,還需要支持 Universal Link 功能炕置。
Universal Link 功能使用參考文檔

NFC和CPU卡交互我的項目中并沒有使用到,全部內(nèi)容如有問題男韧,歡迎大佬及時糾正和補充朴摊。

參考文獻:

NFC 蘋果官網(wǎng)
NFC 與 CPU卡交互
NFCNDEFReaderSession 參考文檔
iOS開發(fā)之NFC的使用
iOS NFC

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市此虑,隨后出現(xiàn)的幾起案子甚纲,更是在濱河造成了極大的恐慌,老刑警劉巖朦前,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件介杆,死亡現(xiàn)場離奇詭異,居然都是意外死亡韭寸,警方通過查閱死者的電腦和手機春哨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恩伺,“玉大人赴背,你說我怎么就攤上這事。” “怎么了癞尚?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵耸三,是天一觀的道長。 經(jīng)常有香客問我浇揩,道長仪壮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任胳徽,我火速辦了婚禮积锅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘养盗。我一直安慰自己缚陷,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布往核。 她就那樣靜靜地躺著箫爷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪聂儒。 梳的紋絲不亂的頭發(fā)上虎锚,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音衩婚,去河邊找鬼窜护。 笑死,一個胖子當著我的面吹牛非春,可吹牛的內(nèi)容都是我干的柱徙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼奇昙,長吁一口氣:“原來是場噩夢啊……” “哼护侮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起储耐,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤羊初,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后弧岳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡业踏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年禽炬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勤家。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡腹尖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伐脖,到底是詐尸還是另有隱情热幔,我是刑警寧澤乐设,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站绎巨,受9級特大地震影響近尚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜场勤,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一戈锻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧和媳,春花似錦格遭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至她倘,卻和暖如春璧微,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背帝牡。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工往毡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人靶溜。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓开瞭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親罩息。 傳聞我的和親對象是個殘疾皇子嗤详,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 一、NFC的使用范圍 蘋果在iOS11上推出了NFC的功能瓷炮,開發(fā)者可以根據(jù)自身的需要使用這個功能進行開發(fā)葱色。NFC有...
    nick5683閱讀 2,416評論 2 3
  • 一、NFC的使用范圍 蘋果在iOS11上推出了NFC的功能娘香,開發(fā)者可以根據(jù)自身的需要使用這個功能進行開發(fā)苍狰。NFC有...
    三國韓信閱讀 4,009評論 3 23
  • 一、了解NFCiOS開發(fā)關于NFC的使用烘绽,其實官方文檔已經(jīng)很詳細了淋昭,先上官方文檔:文檔地址:https://dev...
    Streamsle閱讀 14,619評論 23 35
  • 昨天公司突然有個要用到NFC 功能的項目,我一想前幾年挺火的安接,網(wǎng)上肯定也有不少例子翔忽,覺得分分鐘搞定的,然而…… 雖...
    FlyFighting閱讀 36,399評論 6 58
  • 0x00 概述 許多提供NFC功能的基于Android的設備已經(jīng)支持NFC卡模擬。在大多數(shù)情況下歇式,該卡由設備中的單...
    Killshadow閱讀 12,259評論 2 8