如何将设备令牌(NSData)转换为NSString?

She*_*lam 145 iphone cocoa-touch objective-c nsstring nsdata

我正在实施推送通知.我想将我的APNS令牌保存为字符串.

- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
{
    NSString *tokenString = [NSString stringWithUTF8String:[newDeviceToken bytes]]; //[[NSString alloc]initWithData:newDeviceToken encoding:NSUTF8StringEncoding];
    NSLog(@"%@", tokenString);
    NSLog(@"%@", newDeviceToken);
}
Run Code Online (Sandbox Code Playgroud)

第一行代码打印为null.第二个打印令牌.如何将newDeviceToken作为NSString?

Sas*_*cha 219

如果有人想在Swift中这样做:

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
    var tokenString = ""

    for i in 0..<deviceToken.length {
        tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
    }

    print("tokenString: \(tokenString)")
}
Run Code Online (Sandbox Code Playgroud)

编辑:对于Swift 3

Swift 3引入了Data具有值语义的类型.要将其转换deviceToken为String,您可以执行以下操作:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
    print(token)
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么这必须如此复杂,操作系统给我们一个字符串有什么问题,因为这是每个人都需要的?谢谢你的解决方案. (117认同)
  • 我重构了:`let token = deviceToken.map {String(格式:"%02.2hhx",$ 0)}.join()`http://qiita.com/mono0926/items/3cf0dca3029f32f54a09 (16认同)
  • 你能解释"%02.2hhx"的作用吗? (6认同)
  • @Sascha我希望你批准我的编辑你非常有用的答案:) (3认同)
  • 我不建议使用.description,因为这不能保证稳定。在这里查看我的答案:http://stackoverflow.com/questions/9372815/how-can-i-convert-my-device-token-nsdata-into-an-nsstring/39754930#39754930 (2认同)

Shu*_*ank 153

有人用这帮我.我只是路过

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {

    const unsigned *tokenBytes = [deviceToken bytes];
    NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                         ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                         ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                         ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];

    [[MyModel sharedModel] setApnsToken:hexToken];
}
Run Code Online (Sandbox Code Playgroud)

  • `重要:APNs设备令牌长度可变.苹果说,不要硬编码. (8认同)
  • 这会是一个更好的解决方案吗?`const unsigned*tokenBytes = [deviceToken bytes]; NSMutableString*hexToken = [NSMutableString string]; for(NSUInteger byteCount = 0; byteCount*4 <[deviceToken length]; byteCount ++){[hexToken appendFormat:@"%08x",ntohl(tokenBytes [byteCount])]; }` (5认同)
  • 这是最好的解决方案,因为encondig字节为十六进制,意味着你可以计算它;) (4认同)
  • 在XCode 5上,我必须转换deviceToken以使其编译:const unsigned*tokenBytes =(const unsigned*)[deviceToken bytes]; (4认同)
  • 令牌很快将超过32个字节,因此需要在每个字节上进行循环,而不是8个硬编码整数. (3认同)

Vla*_*kiy 128

你可以用它

- (NSString *)stringWithDeviceToken:(NSData *)deviceToken {
    const char *data = [deviceToken bytes];
    NSMutableString *token = [NSMutableString string];

    for (NSUInteger i = 0; i < [deviceToken length]; i++) {
        [token appendFormat:@"%02.2hhX", data[i]];
    }

    return [token copy];
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案,因为它比使用`description`更安全. (9认同)
  • 这是Objective-C中唯一能够处理令牌大小即将增加的正确答案. (7认同)
  • 我使用了 `[tokenappendFormat:@"%02.2hhx", data[i]];`,因为 Amazon SNS 需要小写。 (2认同)

小智 46

用这个 :

NSString * deviceTokenString = [[[[deviceToken description]
                         stringByReplacingOccurrencesOfString: @"<" withString: @""] 
                        stringByReplacingOccurrencesOfString: @">" withString: @""] 
                       stringByReplacingOccurrencesOfString: @" " withString: @""];

NSLog(@"The generated device token string is : %@",deviceTokenString);
Run Code Online (Sandbox Code Playgroud)

  • 使用描述似乎是一个坏主意:没有什么可以确保iOS的更高版本不会改变此调用的实现和结果. (124认同)
  • 从Swift 3/iOS 10开始,设备令牌上的.description返回"32字节".所以是的,不要使用它. (37认同)
  • @madewulf非常高兴你指出如何使用描述这是一个如此糟糕的想法..如果你提出了另一种选择,它本来会更好 (19认同)
  • 实际上,这是一个非常糟糕的主意. (15认同)
  • 这里有[deviceToken字节]的解决方案符合要求. (6认同)
  • 从iOS 13开始,[NSData description]的行为已更改,此代码将生成无效的令牌字符串。请使用[此答案](/sf/ask/656097081/#24979958) (5认同)
  • 为什么Apple会改变它,可以使用这种实现. (3认同)
  • 确实,这是Apple论坛中的一些线程,描述了iOS 13中的“描述”更改。[此处](https://forums.developer.apple.com/thread/119111)和[此处](https:// forums。 developer.apple.com/thread/117545) (2认同)

Ana*_*and 41

对于那些想要在Swift 3和最简单的方法

func extractTokenFromData(deviceToken:Data) -> String {
    let token = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
    return token.uppercased();
}
Run Code Online (Sandbox Code Playgroud)


Zeb*_*Zeb 15

这是我的解决方案,它在我的应用程序中运行良好:

    NSString* newToken = [[[NSString stringWithFormat:@"%@",deviceToken] 
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""];
Run Code Online (Sandbox Code Playgroud)
  • 转换NSDataNSStringstringWithFormat
  • 修剪"<>"
  • 删除空格

  • 这只是隐式调用`-description`,所以它并不比接受的答案更安全. (10认同)
  • 不,这真的在deviceToken上调用`description`就像jszumski说的那样. (5认同)

小智 15

在 iOS 13 中,描述将采用不同的格式。请使用以下代码获取设备令牌。

- (NSString *)fetchDeviceToken:(NSData *)deviceToken {
    NSUInteger len = deviceToken.length;
    if (len == 0) {
        return nil;
    }
    const unsigned char *buffer = deviceToken.bytes;
    NSMutableString *hexString  = [NSMutableString stringWithCapacity:(len * 2)];
    for (int i = 0; i < len; ++i) {
        [hexString appendFormat:@"%02x", buffer[i]];
    }
    return [hexString copy];
}
Run Code Online (Sandbox Code Playgroud)


jqg*_*imo 10

说明%02.2hhx在高投票答案

  • %:介绍x转化说明符。
  • 02:转换后的值的最小宽度为2。如果转换后的值的字节数少于字段宽度,则应0在左侧用填充。
  • .2:给出x转换说明符出现的最小位数。
  • hh:指定x转换说明符适用于有符号的char或无符号的char参数(该参数将根据整数提升而提升,但是在打印之前,其值应转换为有符号的char或无符号的char)。
  • x:无符号参数应以“ dddd”形式转换为无符号十六进制格式;使用字母“ abcdef”。精度指定出现的最小位数;如果要转换的值可以用较少的数字表示,则应将其扩展为前导零。默认精度为1。以零的显式精度转换零的结果应为无字符。

有关更多详细信息,请参见IEEE printf规范


根据以上解释,我认为更改%02.2hhx%02x或更好%.2x

对于Swift 5,以下方法都是可行的:

deviceToken.map({String(format: "%02x", $0)}).joined()
Run Code Online (Sandbox Code Playgroud)
deviceToken.map({String(format: "%.2x", $0)}).joined()
Run Code Online (Sandbox Code Playgroud)
deviceToken.reduce("", {$0 + String(format: "%02x", $1)})
Run Code Online (Sandbox Code Playgroud)
deviceToken.reduce("", {$0 + String(format: "%.2x", $1)})
Run Code Online (Sandbox Code Playgroud)

测试如下:

let deviceToken = (0..<32).reduce(Data(), {$0 + [$1]})
print(deviceToken.reduce("", {$0 + String(format: "%.2x", $1)}))
// Print content:
// 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Run Code Online (Sandbox Code Playgroud)


Ole*_*yuk 9

我认为将deviceToken转换为十六进制字节字符串是没有意义的.为什么?您将它发送到您的后端,在那里它将被转换回字节以推送到APNS.所以,使用NSData的方法base64EncodedStringWithOptions,将其推送到服务器,然后使用反向base64decoded数据:)这是如此容易:)

NSString *tokenString = [tokenData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
Run Code Online (Sandbox Code Playgroud)

  • 我只是不想to窃@Oleg Shanyuk的答案。由于它只是根据他的回答翻译成另一种语言的语言,因此他值得未来投票。如果我添加另一个答案,它将给我赞成别人研究的答案。希望这证明编辑是正确的。 (2认同)

Sur*_*rma 8

在iOS 13中description会损坏,请使用此功能

let deviceTokenString = deviceToken.map { String(format: "%02x", $0) }.joined()
Run Code Online (Sandbox Code Playgroud)

为了清楚起见,让我们分解并解释每个部分:

映射方法对序列的每个元素进行操作。由于Data是Swift中的字节序列,因此将对deviceToken中的每个字节评估传递的闭包。String(format :)初始化程序使用%02x格式说明符评估数据中的每个字节(由匿名参数$ 0表示),以生成零填充的2位十六进制表示形式的字节/ 8位整数。在收集了由map方法创建的每个字节表示形式之后,joind()将每个元素连接为一个字符串。

PS不使用描述在iOS 12和iOS 13中提供了不同的字符串,并且根据将来的范围是不安全的。开发人员不应该依赖特定格式来描述对象。

// iOS 12
(deviceToken as NSData).description // "<965b251c 6cb1926d e3cb366f dfb16ddd e6b9086a 8a3cac9e 5f857679 376eab7C>"

// iOS 13
(deviceToken as NSData).description // "{length = 32, bytes = 0x965b251c 6cb1926d e3cb366f dfb16ddd ... 5f857679 376eab7c }"
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请阅读This


Fat*_*tie 6

2020年

令牌作为文本...

let tat = deviceToken.map{ data in String(format: "%02.2hhx", data) }.joined()
Run Code Online (Sandbox Code Playgroud)

或者如果你愿意的话

let tat2 = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
Run Code Online (Sandbox Code Playgroud)

(结果是一样的)