如何使用 CoreNFC 将 NFC 标签有效负载转换为 URL?

Posted

技术标签:

【中文标题】如何使用 CoreNFC 将 NFC 标签有效负载转换为 URL?【英文标题】:How I can convert NFC tag payload to URL using CoreNFC? 【发布时间】:2020-08-10 08:58:40 【问题描述】:

我正在尝试编写一个函数,用于将 NFC 标签有效负载数据转换为 URL 以在 safari 中打开它,但由于某种原因它没有打开,因为它无法将其转换为 URL。我的代码在这里:

 func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) 
    var result = ""
      for payload in messages[0].records
          print("-> \(payload)") //Prints the Entire NFC Payload on the Tag.
        result += String.init(data: payload.payload, encoding: .utf16) ?? "Format not supported"
      
      DispatchQueue.main.async 
        guard let url = URL(string: result) else  return 
        UIApplication.shared.open(url)

      

【问题讨论】:

String.init(data: payload.payload, encoding: .utf16) 产生什么? developer.apple.com/documentation/corenfc/nfcndefpayload/… 另外,你能检查一下typeNameFormat 吗? let urls = messages[0].records.flatMap $0.wellKnownTypeURIPayload ; urls.forEach print("anUrl: \($0.absoluteString)" 另外,像这样附加网址?分块? 【参考方案1】:

您需要解码有效载荷,因为它按照 NFC 论坛技术规范中的描述进行编码(例如 NFCForum-TS-NDEF_1.0.pdf,在可能的地方抓取它,但在“白色方向” - 这个文件需要购买)

NDEF 是复杂的格式,为了正确解码,您需要遵守所有功能(无需实现所有功能,但您需要准备好理解负载中出现的所有数据)。

简而言之,对于 URL 类型的解码,您需要对两种类型的有效负载做出反应(我的代码在 Objective-C 中,但可以用 Swift 重写):

NSDictionary *urlData; // <- Desired URL placed here
NSString *payloadType = [[NSString alloc] initWithData:payload.type encoding:NSUTF8StringEncoding];
if ([@"Sp" isEqualToString:payloadType]) 
    urlData = [NDEFProcessor parseSmartPoster:payload.payload];
 else if ([@"U" isEqualToString:payloadType]) 
    urlData = [NDEFProcessor parseUriPrimitive:payload.payload];

NDEFProcessor 函数在哪里:

+ (NSString *) uriPrefixForType: (uint8_t) type 
    switch (type) 
        default: return @"";
        case 0x01: return @"http://www.";
        case 0x02: return @"https://www.";
        case 0x03: return @"http://";
        case 0x04: return @"https://";
        case 0x05: return @"tel:";
        case 0x06: return @"mailto:";
    

+ (NSDictionary *) parseUriPrimitive:(NSData *) payload 
    NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
    int schemeType = ((uint8_t *) payload.bytes) [0];
    NSString *uriRaw = [[NSString alloc] initWithBytes:payload.bytes  + 1 length:payload.length - 1 encoding:NSUTF8StringEncoding];
    NSString *proto = [NDEFProcessor uriPrefixForType:schemeType];
    [result setObject: proto
            forKey: @"PROTO"];
    [result setObject: uriRaw
            forKey: @"RAW"];
    [result setObject: [NSString stringWithFormat:@"%@%@", proto, uriRaw]
            forKey: @"URI"];
    return [NSDictionary dictionaryWithDictionary:result];


+ (NSDictionary *) parseSmartPoster:(NSData *) payload 
    NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
    int pos = 0;
    uint8_t recordHeader;
    do 
        recordHeader = ((uint8_t *) payload.bytes)[pos];
        uint8_t recordLength = ((uint8_t *) payload.bytes)[pos + 2];
        uint8_t recordType = ((uint8_t *) payload.bytes) [pos + 3];
        if (recordType == 0x55) 
            // URI
            NSDictionary *uriDictionary = [self parseUriPrimitive:[payload subdataWithRange:NSMakeRange(pos + 4, recordLength)]];
            if (uriDictionary != nil) 
                [result addEntriesFromDictionary:uriDictionary];
            
        
    pos = pos + recordLength + 4;
     while ((pos < payload.length) || ((recordHeader & (1 << 6)) != 0x40));
    return [NSDictionary dictionaryWithDictionary:result];

【讨论】:

developer.apple.com/documentation/corenfc/nfcndefpayload/… 对于您的大多数情况来说还不够吗? @Larme,在 Smart Poster 记录的情况下,记录存在于两个“子记录”中:text+Uri。在这种情况下,您需要在两个原始 Uri+Text 中“反编译”复杂的 Sp 记录。我不确定 Apple - 它能否处理复杂的记录。

以上是关于如何使用 CoreNFC 将 NFC 标签有效负载转换为 URL?的主要内容,如果未能解决你的问题,请参考以下文章

iOS CoreNFC - 类“NFTechnologyEvent”未加载或不存在

NFC iOS 13 读写故障

iOS NFC

iOS12如何设置NFC后台读取关联域

当 TLV 字段使用 3 字节长度格式时,CoreNFC 不会读取

CoreNFC 短信只产生双字节字符?