Swift 3 - i token del dispositivo vengono ora analizzati come "32BYTES"


94

Ho appena aggiornato da Xcode 7 a 8 GM e tra i problemi di compatibilità di Swift 3 ho notato che i token del mio dispositivo hanno smesso di funzionare. Adesso leggono solo "32BYTES".

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

Prima dell'aggiornamento ero in grado di inviare semplicemente NSData al mio server, ma ora ho difficoltà ad analizzare effettivamente il token.

Cosa mi manca qui?

Modifica: sto solo testando la conversione in NSData e vedo i risultati attesi. Quindi ora sono solo confuso sul nuovo tipo di dati.

    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
Il passaggio a NSDatastampa semplicemente il file descriptiondi NSData. Ancora non ottieni una stringa da quello.
rmaddy

Risposte:


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

L'operazione inversa (hex String -> Dati) è disponibile qui: stackoverflow.com/a/46663290/5252428
Rok Gregorič

4
%02xva bene anche.
jqgsninimo

1
@Rok puoi spiegare la tua risposta? qual è il nuovo formato in cui è stato formattato il token?
simo

@simo che è una conversione da dati a stringa esadecimale che puoi passare a un servizio web / API per poter inviare notifiche push.
Rok Gregorič

Un buon post con una buona spiegazione delle differenze tra %02.2hhxe %02x nshipster.com/apns-device-tokens/#overturned-in-ios-13
Rok Gregorič

35

Ho avuto lo stesso problema. Questa è la mia soluzione:

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
Questo è un approccio alternativo alla codifica di NSDatain una stringa. Ho suggerito di utilizzare la codifica base64 nella mia risposta. Questo utilizza la codifica base16.
rmaddy

Anche @rmaddy è interessante, ma sarebbe più utile se ci fornissi una guida con il codice !!!
vivek agravat

29

Ecco la mia estensione Swift 3 per ottenere una stringa esadecimale codificata in base 16:

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

Ho notato che funziona anche il formato "% 02x". Inoltre non riesco a capire cosa fa "hh"
andrei

1
@andrei "hh" dice al formattatore di stringhe di trattare l'input come un carattere. Tuttavia, in modo rapido, i dati sono una raccolta di UInt8, quindi non ne hai bisogno
wyu

27

Il token del dispositivo non è mai stato una stringa e certamente non una stringa codificata UTF-8. Sono dati. Sono 32 byte di dati opachi.

L'unico modo valido per convertire i dati opachi in una stringa è codificarli, comunemente tramite una codifica base64.

In Swift 3 / iOS 10, usa semplicemente il Data base64EncodedString(options:)metodo.


Bene, la differenza qui è il nuovo tipo di dati. Ho appena provato a convertire il deviceToken in NSData e ora stampa il token del mio dispositivo proprio come prima. Hai un esempio di come gestiresti questo problema senza NSData? Perché questo sembra hacky, ma anche più semplice di quello che sembrano aspettarsi da noi.
user1537360

3
Rispetto quello che ho detto. NSDatao Datanon importa. I byte dei dati non sono e non sono mai stati una stringa. La documentazione afferma chiaramente che si tratta di un insieme opaco di dati. Il fatto che il tuo codice abbia funzionato è fortuna. È sempre stato il modo sbagliato di gestirlo. Converti semplicemente i dati in una stringa codificando i dati in base64. Questa è la soluzione corretta ora e prima.
rmaddy

La decodifica Base64 non funziona se utilizzi un servizio come Amazon SNS. Le soluzioni che convertono i dati in caratteri esadecimali, come quelli di @satheeshwaran , producono stringhe di token del dispositivo che assomigliano a quelle precedenti alle modifiche all'SDK.
Alexander il

@Alexander Chi ha parlato della decodifica Base64? Il punto centrale della domanda e delle risposte è codificare i dati grezzi, non decodificarli, in una stringa. L'unico motivo per fare tutto ciò è visualizzare i dati grezzi. Lo schema di codifica specifico è irrilevante. L'altra risposta sta usando la codifica base 16. Ho menzionato l'utilizzo della codifica base 64.
rmaddy

@rmaddy intendevo la codifica Base64 nel mio commento, mi scuso.
Alexander

15

Prova questo:

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

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

2
Sembra che ora ritorni un token diverso
ChikabuZ

8

prova questo

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

7

Swift 3

Il modo migliore e più semplice.

deviceToken.base64EncodedString()

3
Questo è più semplice, ma fai attenzione a cosa sta usando il tuo server se stai consegnando il token. Molte API si aspettano con codifica Hex o Base-16. Ad esempio, Django Push Notifications.
sww314

4

Questa non è stata dichiarata come risposta ufficiale (l'ho vista in un commento), ma è ciò che alla fine ho fatto per rimettere in ordine il mio token.

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

ai fini della nostra API backend (Python), questa è risultata la soluzione "più pulita" ¯ \ _ (ツ) _ / ¯
race_carr

1
Questo non funziona in iOS 10. La descrizione ora restituisce solo "32 byte".
edopelawi

@edopelawi ti sei dimenticato di mettere as NSDatalì. quando metti NSData non Dati restituirà il valore corretto anche su 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
Sebbene questo blocco di codice possa rispondere alla domanda, sarebbe meglio se tu potessi fornire una piccola spiegazione del motivo per cui lo fa.
Crispin

3

L'ho appena fatto

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

ha dato il risultato come,

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

0

Ottieni il token del dispositivo con il formato corretto.

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)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.