Swift 3 - mã thông báo thiết bị hiện đang được phân tích cú pháp thành '32BYTES'


94

Tôi vừa cập nhật từ Xcode 7 lên GM 8 và giữa các vấn đề tương thích với Swift 3, tôi nhận thấy rằng các mã thông báo thiết bị của tôi đã ngừng hoạt động. Bây giờ họ chỉ đọc '32BYTES'.

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

Trước khi cập nhật, tôi có thể chỉ cần gửi NSData đến máy chủ của mình, nhưng bây giờ tôi đang gặp khó khăn khi thực sự phân tích mã thông báo.

Tôi còn thiếu gì ở đây?

Chỉnh sửa: Tôi vừa thử nghiệm chuyển đổi trở lại NSData và tôi thấy kết quả mong đợi. Vì vậy, bây giờ tôi chỉ nhầm lẫn về kiểu dữ liệu mới.

    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
Thay đổi để NSDatađơn giản in ra descriptioncủa NSData. Bạn vẫn không nhận được một chuỗi từ đó.
rmaddy 14/09/2016

Câu trả lời:


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

Các hoạt động nghịch đảo (hex String -> Data) có sẵn ở đây: stackoverflow.com/a/46663290/5252428
Rok Gregorič

4
%02xcũng được.
jqgsninimo

1
@Rok bạn có thể vui lòng giải thích câu trả lời của bạn không? định dạng mới mà mã thông báo được định dạng là gì?
simo

@simo đó là chuyển đổi từ Dữ liệu sang chuỗi thập lục phân mà bạn có thể chuyển tới dịch vụ web / API để có thể gửi thông báo đẩy.
Rok Gregorič

Một bài tốt với một lời giải thích tốt về sự khác nhau giữa %02.2hhx%02x nshipster.com/apns-device-tokens/#overturned-in-ios-13
Rok Gregorič

35

Tôi đã từng gặp vấn đề tương tự. Đây là giải pháp của tôi:

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
Đây là một cách tiếp cận thay thế để mã hóa NSDatachuỗi thành một chuỗi. Tôi đã đề xuất sử dụng mã hóa base64 trong câu trả lời của mình. Điều này sử dụng mã hóa base16.
rmaddy

@rmaddy theo cách của bạn cũng thú vị nhưng sẽ hữu ích hơn nếu bạn cung cấp cho chúng tôi một số hướng dẫn bằng mã !!!
vivek agravat

29

Đây là tiện ích mở rộng Swift 3 của tôi để lấy chuỗi hex được mã hóa base-16:

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

Tôi nhận thấy rằng định dạng "% 02x" cũng hoạt động. Tôi cũng không thể hiểu những gì "hh" không
andrei

1
@andrei "hh" yêu cầu trình định dạng chuỗi coi đầu vào là một ký tự. Tuy nhiên, trong nhanh chóng, dữ liệu là một tập hợp các uint8, vì vậy bạn không cần nó
wyu

27

Mã thông báo thiết bị chưa bao giờ là một chuỗi và chắc chắn không phải là một chuỗi được mã hóa UTF-8. Đó là dữ liệu. Đó là 32 byte dữ liệu không rõ ràng.

Cách hợp lệ duy nhất để chuyển đổi dữ liệu không rõ ràng thành một chuỗi là mã hóa nó - thường là thông qua mã hóa base64.

Trong Swift 3 / iOS 10, chỉ cần sử dụng Data base64EncodedString(options:)phương pháp này.


Sự khác biệt ở đây là kiểu Dữ liệu mới. Tôi vừa thử chuyển đổi deviceToken sang NSData và nó hiện in mã thông báo thiết bị của tôi giống như trước đây. Bạn có một ví dụ về cách bạn sẽ giải quyết vấn đề này mà không có NSData không? Bởi vì điều này cảm thấy khó hiểu, nhưng cũng đơn giản hơn những gì họ có vẻ mong đợi chúng ta làm.
user1537360 14/09/16

3
Tôi đứng trước những gì tôi đã nói. NSDatahoặc Data, nó không quan trọng. Các byte dữ liệu không phải và chưa bao giờ là một chuỗi. Tài liệu nói rõ rằng đó là một bộ dữ liệu không rõ ràng. Thực tế là mã của bạn được sử dụng để hoạt động là may mắn. Đó luôn là cách không chính xác để xử lý nó. Chỉ cần chuyển đổi dữ liệu thành chuỗi bằng cách mã hóa dữ liệu base64. Đó là giải pháp thích hợp bây giờ và trước đây.
rmaddy 14/09/2016

Giải mã Base64 không hoạt động nếu bạn sử dụng một dịch vụ như Amazon SNS. Các giải pháp chuyển đổi dữ liệu thành các ký tự thập lục phân, chẳng hạn như @satheeshwaran , tạo ra chuỗi mã thông báo thiết bị giống với chuỗi trước khi thay đổi đối với SDK.
Alexander

@Alexander Ai nói gì về giải mã Base64? Toàn bộ điểm của câu hỏi và câu trả lời là mã hóa dữ liệu thô, không phải giải mã, thành một chuỗi. Lý do duy nhất để làm điều này là để xem dữ liệu thô. Lược đồ mã hóa cụ thể không liên quan. Câu trả lời khác là sử dụng mã hóa cơ sở 16. Tôi đã đề cập đến việc sử dụng mã hóa cơ sở 64.
rmaddy

@rmaddy Ý tôi là mã hóa Base64 trong nhận xét của mình, tôi xin lỗi.
Alexander

15

Thử cái này:

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

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

2
Có vẻ như bây giờ nó trả về mã thông báo khác
ChikabuZ

8

thử cái này

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

7

Swift 3

Cách tốt nhất và dễ dàng nhất.

deviceToken.base64EncodedString()

3
Điều này là dễ dàng nhất, nhưng hãy cẩn thận với máy chủ của bạn đang sử dụng nếu bạn đang chuyển giao mã thông báo. Nhiều API mong đợi với mã hóa Hex hoặc Base-16. Ví dụ, Django Push Notifications.
sww314

4

Câu hỏi này không được nêu là câu trả lời chính thức (xem nó trong một bình luận), nhưng cuối cùng tôi đã làm để lấy lại mã thông báo của mình theo thứ tự.

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: "")

cho các mục đích của API phụ trợ của chúng tôi (Python), điều này đã trở thành giải pháp "sạch nhất" ¯ \ _ (ツ) _ / ¯
race_carr 22/02/17

1
Điều này không hoạt động trong iOS 10. Mô tả hiện chỉ trả về "32byte".
edopelawi

@edopelawi bạn quên đặt as NSDataở đó. khi bạn đặt là NSData chứ không phải Dữ liệu sẽ trả về giá trị chính xác ngay cả trên 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
Mặc dù khối mã này có thể trả lời câu hỏi, nhưng tốt nhất là bạn có thể cung cấp một chút giải thích cho lý do tại sao nó lại như vậy.
Crispin

3

Tôi vừa làm điều này,

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

nó cho kết quả giống như,

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

0

Nhận mã thông báo thiết bị với định dạng thích hợp.

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)
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.