Swift 3-设备令牌现在被解析为“ 32BYTES”


94

我刚刚从Xcode 7更新到8 GM,并且在Swift 3兼容性问题中,我注意到我的设备令牌已停止工作。他们现在只读取'32BYTES'。

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
{
    print(deviceToken) // Prints '32BYTES'
    print(String(data: deviceToken , encoding: .utf8)) // Prints nil
}

在更新之前,我可以简单地将NSData发送到服务器,但是现在我很难解析令牌。

我在这里想念什么?

编辑:我只是测试转换回NSData,我看到了预期的结果。所以现在我只是对新的数据类型感到困惑。

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
{
    print(deviceToken) // Prints '32BYTES'
    print(String(data: deviceToken , encoding: .utf8)) // Prints nil

    let d = NSData(data: deviceToken)
    print(d) // Prints my device token
}

2
更改为NSData只会打印descriptionNSData。您仍然不会从中得到任何信息。
rmaddy16 2013年

Answers:


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

反操作(十六进制字符串->数据)在此处可用:stackoverflow.com/a/46663290/5252428
RokGregorič17年

4
%02x也可以
jqgsninimo

1
@Rok您能解释一下您的答案吗?令牌格式化为什么新格式?
simo

@simo是从Data到十六进制字符串的转换,您可以将其传递到Web服务/ API,以发送推送通知。
RokGregorič19年

一个很好的帖子,很好地解释了%02.2hhx%02x nshipster.com/apns-device-tokens/#overturned-in-ios-13
RokGregorič19年

35

我有同样的问题。这是我的解决方案:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    var token = ""
    for i in 0..<deviceToken.count {
        token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]])
    }
    print(token)
}

1
这是将编码NSData为字符串的另一种方法。我建议在答案中使用base64编码。这使用base16编码。
rmaddy16 2013年

@rmaddy您的方式也很有趣,但是如果您给我们一些代码指导,它将更加有帮助!
vivek agravat

29

这是我的Swift 3扩展名,用于获取以16为基数编码的十六进制字符串:

extension Data {
    var hexString: String {
        return map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
    }
}

我注意到“%02x”格式也可以使用。我也无法理解“ hh”的作用
andrei

1
@andrei“ hh”告诉字符串格式化程序将输入视为一个字符。但是,迅速地,数据是UInt8的集合,因此您不需要它
wyu

27

设备令牌从来不是一个字符串,当然也不是UTF-8编码的字符串。是数据 它是32个字节的不透明数据。

将不透明数据转换为字符串的唯一有效方法是对其进行编码-通常通过base64编码进行。

在Swift 3 / iOS 10中,只需使用Data base64EncodedString(options:)方法。


好吧,这里的区别是新的数据类型。我只是尝试将deviceToken转换为NSData,现在它像以前一样打印我的设备令牌。您是否有一个示例,说明如何在没有NSData的情况下如何处理此问题?因为这感觉很棘手,但也比他们期望我们做的要简单。
user1537360'9

3
我坚持我所说的。NSDataData,没关系。数据的字节不是,也永远不是字符串。该文档明确指出它是一组不透明的数据。您的代码曾经可以运行的事实很幸运。这总是错误的处理方式。只需通过对数据进行base64编码即可将数据转换为字符串。这是现在和以前的正确解决方案。
rmaddy16 2013年

如果您使用诸如Amazon SNS之类的服务,Base64解码将不起作用。将数据转换为十六进制字符(例如@satheeshwaran)的解决方案会生成类似于更改SDK之前的设备令牌字符串。
亚历山大

@Alexander谁说过Base64解码?问题和答案的重点是将原始数据编码而不是解码为字符串。进行此操作的唯一原因是查看原始数据。具体的编码方案无关紧要。另一个答案是使用基数16编码。我提到使用base 64编码。
rmaddy

@rmaddy我在评论中表示对Base64编码的歉意。
亚历山大

15

试试这个:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

   let token = String(data: deviceToken.base64EncodedData(), encoding: .utf8)?.trimmingCharacters(in: CharacterSet.whitespaces).trimmingCharacters(in: CharacterSet(charactersIn: "<>")) 
}

2
看来现在它返回了不同的令牌
ChikabuZ

8

试试这个

if #available(iOS 10.0, *) {
   let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
}

7

迅捷3

最好和最简单的方法。

deviceToken.base64EncodedString()

3
这是最简单的方法,但是如果要传递令牌,请小心服务器使用的是什么。许多API期望使用十六进制编码或Base-16。例如,Django推送通知。
sww314

4

这不是官方的答案(请在评论中看到),但是我最终还是这样做了,以使我的令牌恢复秩序。

let tokenData = deviceToken as NSData
let token = tokenData.description

// remove any characters once you have token string if needed
token = token.replacingOccurrences(of: " ", with: "")
token = token.replacingOccurrences(of: "<", with: ""
token = token.replacingOccurrences(of: ">", with: "")

出于我们后端API(Python)的目的,这最终成为“最干净的”解决方案\ _(_)_ /
¯– race_carr

1
这在iOS 10中不起作用。描述现在仅返回“ 32bytes”。
edopelawi's

@edopelawi,您忘了放在as NSData那里。当您将其设置为NSData时,即使在iOS 10上,数据也不会返回正确的值
Jakub

4
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

    let token = deviceToken.map({ String(format: "%02.2hhx", $0)}).joined()
     print("TOKEN: " + token)


}

4
尽管此代码块可以回答问题,但最好是提供一些解释来解释为什么这样做。
克里斯平,2017年

3

我就是这么做的

let token = String(format:"%@",deviceToken as CVarArg).components(separatedBy: CharacterSet.alphanumerics.inverted).joined(separator: "")

结果与

let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()

0

获取具有正确格式的设备令牌。

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) 
{
            var formattedToken = ""
            for i in 0..<deviceToken.count {
                formattedToken = formattedToken + String(format: "%02.2hhx", arguments: [deviceToken[i]])
            }
            print(formattedToken)
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.