Swift 3 - token perangkat sekarang sedang diurai sebagai '32BYTES'

94

Saya baru saja memperbarui dari Xcode 7 ke 8 GM dan di tengah masalah kompatibilitas Swift 3, saya perhatikan bahwa token perangkat saya telah berhenti berfungsi. Mereka sekarang hanya membaca '32BYTES'.

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

Sebelum pembaruan saya dapat dengan mudah mengirim NSData ke server saya, tetapi sekarang saya mengalami kesulitan untuk benar-benar mem-parse token.

Apa yang kulewatkan di sini?

Sunting: Saya baru saja menguji konversi kembali ke NSData dan saya melihat hasil yang diharapkan. Jadi sekarang saya hanya bingung tentang tipe Data baru.

    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
}
pengguna1537360
sumber
2
Mengubah menjadi NSDatahanya mencetak descriptiondari NSData. Anda masih belum mendapatkan string dari itu.
rmaddy

Jawaban:

189
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
    print(token)
}
Rok Gregorič
sumber
Operasi terbalik (Hex String -> Data) tersedia di sini: stackoverflow.com/a/46663290/5252428
Rok Gregorič
4
%02xtidak apa-apa juga.
jqgsninimo
1
@Rok bisakah Anda menjelaskan jawaban Anda? Apa format baru token itu diformat?
simo
@simo itu adalah konversi dari Data ke string heksadesimal yang dapat Anda berikan ke layanan web / API untuk dapat mengirim pemberitahuan push.
Rok Gregorič
Kiriman yang bagus dengan penjelasan yang baik tentang perbedaan antara %02.2hhxdan %02x nshipster.com/apns-device-tokens/#overturned-in-ios-13
Rok Gregorič
35

Saya memiliki masalah yang sama. Ini solusi saya:

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
sumber
1
Ini adalah pendekatan alternatif untuk menyandikan NSDatamenjadi string. Saya menyarankan menggunakan pengkodean base64 dalam jawaban saya. Ini menggunakan pengkodean base16.
rmaddy
@rmaddy cara Anda juga menarik tetapi akan lebih membantu jika Anda memberi kami beberapa panduan dengan kode !!!
vivek agravat
29

Ini ekstensi Swift 3 saya untuk mendapatkan string hex yang dikodekan base-16:

extension Data {
    var hexString: String {
        return map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
    }
}
phatmann.dll
sumber
Saya perhatikan bahwa format "% 02x" juga berfungsi. Saya juga tidak mengerti apa yang "hh" lakukan
andrei
1
@andrei "hh" memberi tahu pemformat string untuk memperlakukan masukan sebagai karakter. Namun dalam sekejap, Data adalah kumpulan UInt8, jadi Anda tidak membutuhkannya
wyu
27

Token perangkat tidak pernah berupa string dan tentu saja bukan string berenkode UTF-8. Itu data. Ini 32 byte data buram.

Satu-satunya cara yang valid untuk mengubah data buram menjadi string adalah dengan menyandikannya - biasanya melalui pengkodean base64.

Di Swift 3 / iOS 10, cukup gunakan Data base64EncodedString(options:)metode ini.

rmaddy
sumber
Nah perbedaannya di sini adalah tipe Data baru. Saya baru saja mencoba mengonversi deviceToken ke NSData dan sekarang mencetak token perangkat saya seperti sebelumnya. Apakah Anda punya contoh bagaimana Anda akan menangani ini tanpa NSData? Karena ini terasa hacky, tetapi juga lebih mudah daripada yang mereka harapkan dari kita.
pengguna1537360
3
Saya mendukung apa yang saya katakan. NSDataatau Data, tidak masalah. Byte dari data bukan dan tidak pernah menjadi string. Dokumentasi dengan jelas menyatakan bahwa ini adalah kumpulan data yang tidak jelas. Fakta bahwa kode Anda dulu berfungsi adalah keberuntungan. Itu selalu cara yang salah untuk menanganinya. Cukup ubah data menjadi string dengan base64 menyandikan data. Itulah solusi yang tepat sekarang dan sebelumnya.
rmaddy
Dekode Base64 tidak berfungsi jika Anda menggunakan layanan seperti Amazon SNS. Solusi yang mengubah data menjadi karakter heksadesimal, seperti @satheeshwaran , menghasilkan string token perangkat yang mirip dengan yang sebelum perubahan pada SDK.
Alexander
@Alexander Siapa yang mengatakan sesuatu tentang decoding Base64? Inti dari pertanyaan dan jawabannya adalah menyandikan data mentah, bukan mendekode, menjadi sebuah string. Satu-satunya alasan untuk melakukan semua ini adalah untuk melihat data mentah. Skema pengkodean spesifik tidak relevan. Jawaban lainnya adalah menggunakan pengkodean basis 16. Saya sebutkan menggunakan pengkodean basis 64.
rmaddy
@rmaddy Maksud saya pengkodean Base64 dalam komentar saya, maaf.
Alexander
15

Coba ini:

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

   let token = String(data: deviceToken.base64EncodedData(), encoding: .utf8)?.trimmingCharacters(in: CharacterSet.whitespaces).trimmingCharacters(in: CharacterSet(charactersIn: "<>")) 
}
pengguna
sumber
2
Tampaknya sekarang ia mengembalikan token yang berbeda
ChikabuZ
8

coba ini

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

Cepat 3

Cara terbaik dan termudah.

deviceToken.base64EncodedString()
Maselko
sumber
3
Ini paling mudah, tetapi hati-hati dengan apa yang server Anda gunakan jika Anda menyerahkan tokennya. Banyak API mengharapkan dengan Hex encoded atau Base-16. Misalnya, Pemberitahuan Push Django.
sww314
4

Yang ini tidak dinyatakan sebagai jawaban resmi (lihat di komentar), tetapi itulah yang akhirnya saya lakukan untuk mendapatkan token saya kembali.

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
sumber
untuk tujuan API backend kami (Python), ini akhirnya menjadi solusi "terbersih" ¯ \ _ (ツ) _ / ¯
race_carr
1
Ini tidak bekerja di iOS 10. Deskripsi sekarang hanya mengembalikan "32bytes".
edopelawi
@edopelawi anda lupa taruh as NSDatadisana. ketika Anda meletakkan sebagai NSData tidak Data akan mengembalikan nilai yang benar bahkan di iOS 10
Jakub
4
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

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


}
PacoG
sumber
4
Meskipun blok kode ini mungkin menjawab pertanyaan tersebut, akan lebih baik jika Anda memberikan sedikit penjelasan mengapa hal itu terjadi.
Crispin
3

Saya baru saja melakukan ini,

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

itu memberikan hasil yang sama seperti,

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

Dapatkan token perangkat dengan format yang tepat.

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
sumber