【问题标题】:iOS 11 - How does one read/parse the NDEF Message from CoreNFC?iOS 11 - 如何从 CoreNFC 读取/解析 NDEF 消息?
【发布时间】:2017-06-08 20:40:09
【问题描述】:

我有一堆标签是 URL 标签,内容为“http://WEBSITE.com”。假设网站是 youtube 所以http://youtube.com。当我在 Android 等设备上扫描它们时,它会保留 http 或 https。

我正在尝试使用 Core NFC 框架扫描这些相同的标签。我扫描它们,得到一堆字节,我使用 NSSString initWithData 和 UTF8 编码进行转换。我回来了\^Cyoutube.com。我想得到http://youtube.com

如何拦截有效负载以获得所需的内容?如果我假设字符串前面的http,我应该怎么知道它是http还是https甚至ftp?

编辑 1:

我对以下纯文本记录的答案代码有疑问。在为“hello world”制作文本记录时,我从控制台得到以下输出:

2017-06-09 12:45:35.151806-0400 testNFC[2963:190724] 有效载荷字符串:https://www.enhelloworld

2017-06-09 12:45:35.154959-0400 testNFC[2963:190724] 有效载荷数据:

获取我使用的字符串

NSString *nfcMessage = [nfcType stringByAppendingString:[[[NSString alloc] initWithData:payload.payload encoding:NSUTF8StringEncoding] substringFromIndex:1]];

nfcType 是您的函数的返回值,但对于 None 情况,我返回 @"";

我期待只是打个招呼。

【问题讨论】:

    标签: ios xcode nfc ndef


    【解决方案1】:

    为此,您首先需要确保您的 NDEF 标记格式正确。您可以使用 Android 手机或these reader accessoriesan NDEF writing app 之一。

    实现以下方法:

    - (NSString *)getType:(NSData *)NDEFData {
    
        NSString *firstByte = [self getFirstByte:NDEFData];
    
        if ([firstByte isEqualToString:@"00"]) {
            return @"None";
        } else if ([firstByte isEqualToString:@"01"]) {
            return @"http://www.";
        } else if ([firstByte isEqualToString:@"02"]) {
            return @"https://www.";
        } else if ([firstByte isEqualToString:@"03"]) {
            return @"http://";
        } else if ([firstByte isEqualToString:@"04"]) {
            return @"https://";
        } else if ([firstByte isEqualToString:@"05"]) {
            return @"tel:";
        } else if ([firstByte isEqualToString:@"06"]) {
            return @"mailto:";
        } else if ([firstByte isEqualToString:@"07"]) {
            return @"ftp://anonymous:anonymous@";
        } else if ([firstByte isEqualToString:@"08"]) {
            return @"ftp://ftp.";
        } else if ([firstByte isEqualToString:@"09"]) {
            return @"ftps://";
        } else if ([firstByte isEqualToString:@"0A"]) {
            return @"sftp://";
        } else if ([firstByte isEqualToString:@"0B"]) {
            return @"smb://";
        } else if ([firstByte isEqualToString:@"0C"]) {
            return @"nfs://";
        } else if ([firstByte isEqualToString:@"0D"]) {
            return @"ftp://";
        } else if ([firstByte isEqualToString:@"0E"]) {
            return @"dav://";
        } else if ([firstByte isEqualToString:@"0F"]) {
            return @"news:";
        } else if ([firstByte isEqualToString:@"10"]) {
            return @"telnet://";
        } else if ([firstByte isEqualToString:@"11"]) {
            return @"imap:";
        } else if ([firstByte isEqualToString:@"12"]) {
            return @"rtsp://";
        } else if ([firstByte isEqualToString:@"13"]) {
            return @"urn:";
        } else if ([firstByte isEqualToString:@"14"]) {
            return @"pop:";
        } else if ([firstByte isEqualToString:@"15"]) {
            return @"sip:";
        } else if ([firstByte isEqualToString:@"16"]) {
            return @"sips:";
        } else if ([firstByte isEqualToString:@"17"]) {
            return @"tftp:";
        } else if ([firstByte isEqualToString:@"18"]) {
            return @"btspp://";
        } else if ([firstByte isEqualToString:@"19"]) {
            return @"btl2cap://";
        } else if ([firstByte isEqualToString:@"1A"]) {
            return @"btgoep://";
        } else if ([firstByte isEqualToString:@"1B"]) {
            return @"tcpobex://";
        } else if ([firstByte isEqualToString:@"1C"]) {
            return @"irdaobex://";
        } else if ([firstByte isEqualToString:@"1D"]) {
            return @"file://";
        } else if ([firstByte isEqualToString:@"1E"]) {
            return @"urn:epc:id:";
        } else if ([firstByte isEqualToString:@"1F"]) {
            return @"urn:epc:tag:";
        } else if ([firstByte isEqualToString:@"20"]) {
            return @"urn:epc:pat:";
        } else if ([firstByte isEqualToString:@"21"]) {
            return @"urn:epc:raw:";
        } else if ([firstByte isEqualToString:@"22"]) {
            return @"urn:epc:";
        } else if ([firstByte isEqualToString:@"23"]) {
            return @"urn:nfc:";
        }
    
        return @"";
    
    }
    
    /*!
    * gets the the NDEF content
    */
    - (NSString *)getNDEFContent:(NSData *)data {
         NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
         return [dataString substringFromIndex:2];
    }
    
    /*!
     * gets the first byte of the input NSData
     */
    - (NSString *)getFirstByte:(NSData *)data {
         return [[self dataToHexString:data] substringToIndex:2];
    }
    
    /*!
     * transforms NSData to NSString
     */
    - (NSString *)dataToHexString:(NSData *)data;
    {
        // get the length of the data
        NSUInteger bytesCount = data.length;
        if (bytesCount) {
            // string with all the Hex characters
            const char *hexChars = "0123456789ABCDEF";
            // put bytes into an array and initialize the response array
            const unsigned char *dataBuffer = data.bytes;
            char *chars = malloc(sizeof(char) * (bytesCount * 2 + 1));
            char *s = chars;
            // go through data bytes making the transformations so a hex will literally translate to a string, so for example 0x0A will translate to "0A"
            for (unsigned i = 0; i < bytesCount; ++i) {
                // get hexChars character at binary AND between the current byte and 0xF0 bitwise to the right by 4 index and assign it to the current chars pointer
                *s++ = hexChars[((*dataBuffer & 0xF0) >> 4)];
                // get hexChars character at binary AND between the current byte and 0x0F index and assign it to the current chars pointer
                *s++ = hexChars[(*dataBuffer & 0x0F)];
                dataBuffer++;
            }
            *s = '\0';
            // chars to string
            NSString *hexString = [NSString stringWithUTF8String:chars];
            free(chars);
            return hexString;
        }
        return @"";
    }
    

    并调用getType方法:

    [self getType:yourNDEFPayloadNSData]
    
    • 我假设所有方法都在同一个类中,

    • payload NSData 符合 NDEF,但我根据 NFCNDEFPayload payload 对代码进行建模

    【讨论】:

    • 两个问题。 1. 所有可能的开始扩展都是可能的吗?您从哪里获得将数字与扩展名相关联的列表(即 0C 作为 nfs://)? 2. 我是否正确假设在我从你提供的函数中获取类型之后,我可以通过转换为字符串并获取索引 2 之后的所有内容来获取有效负载的内容?我很困惑你的函数是否只是开始,或者它是否将 NSData 完全转换为最终输出,包括扩展。
    • 1.是的,它是所有可能的开始扩展,其余的都是保留的。该列表来自NFC论坛URI记录类型定义技术规范(NFCForum-TS-RTD_URI_1.0 2006-07-24)archive.eet-china.com/www.eet-china.com/ARTICLES/2006AUG/PDF/…
    • 2.该代码仅返回协议字符串,它需要另一个函数来获取其余数据,正如您所说,您可能必须使用substringFromIndex,我将更新代码。
    • 谢谢。一切似乎都在工作。最后一个问题,你知道如何判断设备是否支持NFC吗?我不想在 iPhone 6 和 6S 设备上显示 NFC 按钮。
    • 这个场景有一个 NFCError 类型称为 NFCReaderErrorUnsupportedFeature 但我无法得到它,所以我现在最好的猜测是尝试创建一个会话并等待委托中的错误。
    【解决方案2】:

    NFC NDEF 消息负载比您预期的要复杂得多。但 CoreNFC 不支持解析 NFC NDEF 消息负载。我创建了一个开源解析器VYNFCKit 来解析有效负载。示例项目在 Objective-C 和 Swift 中都可用。查看我的教程https://medium.com/@vinceyuan/reading-and-parsing-nfc-tag-on-ios-11-60f4bc7a11ea

    【讨论】:

    • 我试过了,到目前为止效果很好。真正的救星!
    • 我一直在寻找一个完整的解决方案。我一直在努力寻找一个完整的规范。应该是公认的答案。
    【解决方案3】:

    关于您的 EDIT1: 您使用了错误的记录类型。 您需要编写“文本记录”,而不是“URI 记录”。 如果您手头有一部 Android 手机,您可以使用“NFC TagWriter by NFC”之类的工具来写入正确的记录。 这对您的用例可能并不重要,但请考虑与 Android 手机的互操作性。其他应用。他们会尝试打开“https://www.enhelloworld”而不是显示“Hello World”,使用 EN 编码作为文本字符串。

    【讨论】:

    • 我在 Android 手机上使用了应用程序 NFC Tools 并进行了文本记录选项。我在应用程序中看到“记录 0 - UTF-8 (en) : text/plain hello world 这是给我 https 等的那个。我相信它的格式正确,但我不是 100%。
    • 您需要区分上面报告的“类型”(即 URI 记录的类型)和记录类型本身(CoreNFC 中的 typeNameFormat)。这可以是以下枚举之一:case absoluteURI,case empty case media case nfcExternal case nfcWellKnown case changed case unknown
    • 所以您认为 CoreNFC 会报告 typeNameFormat 的绝对URI 以外的其他内容?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多