【问题标题】:Swift 3 - device tokens are now being parsed as '32BYTES'Swift 3 - 设备令牌现在被解析为“32BYTES”
【发布时间】:2017-01-22 13:15:02
【问题描述】:

我刚刚从 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
}

【问题讨论】:

  • 更改为NSData 只是打印NSDatadescription。你仍然没有从中得到字符串。

标签: ios swift swift3


【解决方案1】:

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

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)
}

【讨论】:

    【解决方案2】:
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    
        let token = deviceToken.map({ String(format: "%02.2hhx", $0)}).joined()
         print("TOKEN: " + token)
    
    
    }
    

    【讨论】:

    • 虽然这个代码块可能会回答这个问题,但最好能稍微解释一下为什么会这样。
    【解决方案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()
    

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

      • 这里的区别在于新的数据类型。我刚刚尝试将 deviceToken 转换为 NSData,它现在像以前一样打印我的设备令牌。您有没有 NSData 的情况下如何处理此问题的示例?因为这感觉很老套,但也比他们期望我们做的更直接。
      • 我坚持我所说的。 NSDataData,没关系。数据的字节不是,也从来不是字符串。文档清楚地表明它是一组不透明的数据。您的代码曾经可以工作的事实是运气。处理它的方法总是不正确的。只需通过base64编码数据将数据转换为字符串。这是现在和以前的正确解决方案。
      • 如果您使用 Amazon SNS 等服务,Base64 解码将不起作用。将数据转换为十六进制字符的解决方案(例如 @satheeshwaran 的)会生成类似于 SDK 更改之前的设备令牌字符串。
      • @Alexander 谁说过Base64解码?问题和答案的重点是将原始数据编码,而不是解码成字符串。这样做的唯一原因是查看原始数据。具体的编码方案无关紧要。另一个答案是使用 base 16 编码。我提到使用 base 64 编码。
      • @rmaddy 我在评论中指的是 Base64 编码,我深表歉意。
      【解决方案5】:
      func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
          let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
          print(token)
      }
      

      【讨论】:

      • 逆运算(十六进制字符串 -> 数据)在这里可用:stackoverflow.com/a/46663290/5252428
      • %02x 也可以。
      • @Rok 你能解释一下你的答案吗?令牌格式化的新格式是什么?
      • @simo 这是从数据到十六进制字符串的转换,您可以将其传递给 Web 服务/API 以便能够发送推送通知。
      • 一篇很好的帖子,很好地解释了%02.2hhx%02xnshipster.com/apns-device-tokens/#overturned-in-ios-13之间的区别
      【解决方案6】:

      这不是官方答案(在评论中看到),但这是我最终为了让我的令牌恢复正常所做的。

      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) 而言,这最终成为“最干净”的解决方案¯\_(ツ)_/¯
      • 这在 iOS 10 中不起作用。描述现在只返回“32bytes”。
      • @edopelawi 你忘了把as NSData 放在那里。即使在 iOS 10 上,当您输入 NSData 而不是数据时,数据也会返回正确的值
      【解决方案7】:

      斯威夫特 3

      最好和最简单的方法。

      deviceToken.base64EncodedString()
      

      【讨论】:

      • 这是最简单的方法,但是如果您要交出令牌,请注意您的服务器正在使用什么。许多 API 期望使用 Hex 编码或 Base-16。例如,Django 推送通知。
      【解决方案8】:

      试试这个

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

      【讨论】:

        【解决方案9】:

        试试这个:

        func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        
           let token = String(data: deviceToken.base64EncodedData(), encoding: .utf8)?.trimmingCharacters(in: CharacterSet.whitespaces).trimmingCharacters(in: CharacterSet(charactersIn: "<>")) 
        }
        

        【讨论】:

        • 现在好像返回了不同的token
        【解决方案10】:

        这是我的 Swift 3 扩展,用于获取 base-16 编码的十六进制字符串:

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

        【讨论】:

        • 我注意到“%02x”格式也可以。我也无法理解“hh”是做什么的
        • @andrei "hh" 告诉字符串格式化程序将输入视为字符。但是在 swift 中,Data 是 UInt8 的集合,所以你不需要它
        【解决方案11】:

        我遇到了同样的问题。这是我的解决方案:

        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)
        }
        

        【讨论】:

        • 这是将NSData 编码为字符串的另一种方法。我建议在我的回答中使用 base64 编码。这使用 base16 编码。
        • @rmaddy 你的方式也很有趣,但如果你给我们一些代码指导会更有帮助!!!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-28
        • 1970-01-01
        相关资源
        最近更新 更多