一、了解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中
同时生成.entitlements文件
2.1.2 添加权限描述
Privacy - NFC Scan Usage Description
String
官方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
注意: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)
}
本文主要是手机nfc与ISO7816协议间的交互。例如上海交通卡遵守的是ISO7816协议,可以正常获取上海交通卡的余额等信息。(卡的Aid可以从交通卡ipa包中获取)