Schnelle 3-Geräte-Token werden jetzt als "32BYTES" analysiert.

94

Ich habe gerade von Xcode 7 auf 8 GM aktualisiert und inmitten der Swift 3-Kompatibilitätsprobleme festgestellt, dass meine Gerätetoken nicht mehr funktionieren. Sie lesen jetzt nur noch '32BYTES'.

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

Vor dem Update konnte ich die NSData einfach an meinen Server senden, aber jetzt fällt es mir schwer, das Token tatsächlich zu analysieren.

Was vermisse ich hier?

Bearbeiten: Ich teste gerade die Konvertierung zurück zu NSData und sehe die erwarteten Ergebnisse. Jetzt bin ich nur noch verwirrt über den neuen Datentyp.

    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
}
user1537360
quelle
2
Ändern, um NSDataeinfach das descriptionvon zu drucken NSData. Daraus ergibt sich immer noch kein String.
rmaddy

Antworten:

189
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
    print(token)
}
Rok Gregorič
quelle
Die inverse Operation (hex String -> Data) ist hier verfügbar: stackoverflow.com/a/46663290/5252428
Rok Gregorič
4
%02xist auch okay.
jqgsninimo
1
@Rok kannst du bitte deine antwort erklären In welchem ​​neuen Format wurde das Token formatiert?
Simo
@simo ist eine Konvertierung von Daten in eine hexadezimale Zeichenfolge, die Sie an einen Webdienst / eine Web-API übergeben können, um Push-Benachrichtigungen senden zu können.
Rok Gregorič
Ein guter Beitrag mit einer guten Erklärung der Unterschiede zwischen %02.2hhxund %02x nshipster.com/apns-device-tokens/#overturned-in-ios-13
Rok Gregorič
35

Ich hatte das gleiche Problem. Das ist meine Lösung:

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)
}
Oleg
quelle
1
Dies ist ein alternativer Ansatz zum Codieren von NSDatain eine Zeichenfolge. Ich schlug vor, in meiner Antwort die Base64-Codierung zu verwenden. Dies verwendet die Base16-Codierung.
rmaddy
@rmaddy dein Weg ist auch interessant, aber es wäre hilfreicher, wenn du uns eine Anleitung mit Code gibst !!!
Vivek Agravat
29

Hier ist meine Swift 3-Erweiterung, um eine Base-16-codierte Hex-Zeichenfolge zu erhalten:

extension Data {
    var hexString: String {
        return map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
    }
}
Phatmann
quelle
Ich habe festgestellt, dass das Format "% 02x" auch funktioniert. Ich kann auch nicht verstehen, was "hh" tut
andrei
1
@andrei "hh" weist den String-Formatierer an, die Eingabe als Zeichen zu behandeln. In Kürze ist Data jedoch eine Sammlung von UInt8, sodass Sie es nicht benötigen
wyu
27

Das Geräte-Token war noch nie eine Zeichenfolge und schon gar nicht eine UTF-8-codierte Zeichenfolge. Es sind Daten. Es sind 32 Bytes undurchsichtiger Daten.

Die einzig gültige Möglichkeit, die undurchsichtigen Daten in eine Zeichenfolge zu konvertieren, besteht darin, sie zu codieren - normalerweise über eine Base64-Codierung.

Verwenden Sie in Swift 3 / iOS 10 einfach die Data base64EncodedString(options:)Methode.

rmaddy
quelle
Nun, der Unterschied hier ist der neue Datentyp. Ich habe gerade versucht, das deviceToken in NSData zu konvertieren, und es druckt jetzt mein Geräte-Token wie zuvor. Haben Sie ein Beispiel, wie Sie ohne NSData damit umgehen würden? Weil sich das hackig anfühlt, aber auch einfacher als das, was sie von uns zu erwarten scheinen.
user1537360
3
Ich stehe zu dem, was ich gesagt habe. NSDataoder Dataes spielt keine Rolle. Die Bytes der Daten sind keine Zeichenfolge und waren es auch nie. In der Dokumentation wird eindeutig angegeben, dass es sich um einen undurchsichtigen Datensatz handelt. Die Tatsache, dass Ihr Code früher funktioniert hat, ist Glück. Es war immer die falsche Art, damit umzugehen. Konvertieren Sie einfach die Daten in eine Zeichenfolge, indem base64 die Daten codiert. Das ist jetzt und früher die richtige Lösung.
rmaddy
Die Base64-Dekodierung funktioniert nicht, wenn Sie einen Dienst wie Amazon SNS verwenden. Lösungen, die die Daten in hexadezimale Zeichen konvertieren, wie z. B. @satheeshwaran , erzeugen Geräte-Token-Zeichenfolgen, die denen vor den Änderungen am SDK ähneln.
Alexander
@ Alexander Wer hat etwas über Base64-Dekodierung gesagt? Der springende Punkt der Frage und der Antworten ist, die Rohdaten zu codieren , nicht zu dekodieren, in eine Zeichenfolge. Der einzige Grund, dies zu tun, ist das Anzeigen der Rohdaten. Das spezifische Codierungsschema ist irrelevant. Die andere Antwort verwendet die Basis-16-Codierung. Ich erwähnte die Verwendung der Base 64-Codierung.
rmaddy
@rmaddy Ich meinte Base64-Codierung in meinem Kommentar, ich entschuldige mich.
Alexander
15

Versuche dies:

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

   let token = String(data: deviceToken.base64EncodedData(), encoding: .utf8)?.trimmingCharacters(in: CharacterSet.whitespaces).trimmingCharacters(in: CharacterSet(charactersIn: "<>")) 
}
Benutzer
quelle
2
Es scheint, dass es jetzt andere Token
zurückgibt
8

Versuche dies

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

Swift 3

Der beste und einfachste Weg.

deviceToken.base64EncodedString()
Maselko
quelle
3
Dies ist am einfachsten, aber seien Sie vorsichtig, was Ihr Server verwendet, wenn Sie das Token übergeben. Viele APIs erwarten mit Hex-Codierung oder Base-16. Zum Beispiel Django Push-Benachrichtigungen.
sww314
4

Diese Antwort wurde nicht als offizielle Antwort angegeben (siehe in einem Kommentar), aber ich habe sie letztendlich getan, um mein Token wieder in Ordnung zu bringen.

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: "")
Bill Burgess
quelle
Für die Zwecke unserer Backend-API (Python) war dies die "sauberste" Lösung ¯ \ _ (ツ) _ / ¯
race_carr
1
Dies funktioniert unter iOS 10 nicht. Die Beschreibung gibt jetzt nur noch "32 Byte" zurück.
Edopelawi
@edopelawi du hast vergessen dort zu setzen as NSData. Wenn Sie als NSData not Data angeben, wird der korrekte Wert auch unter iOS 10 zurückgegeben
Jakub
4
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

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


}
PacoG
quelle
4
Während dieser Codeblock die Frage beantworten kann, ist es am besten, wenn Sie eine kleine Erklärung dafür geben könnten, warum dies so ist.
Crispin
3

Ich habe das gerade gemacht,

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

es gab das gleiche Ergebnis wie,

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

Holen Sie sich das Gerätetoken mit dem richtigen Format.

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)
}
Basir Alam
quelle