Swift 3 - โทเค็นอุปกรณ์ถูกแยกวิเคราะห์เป็น '32BYTES'


94

ฉันเพิ่งอัปเดตจาก 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
}

2
การเปลี่ยนเป็นการNSDataพิมพ์descriptionไฟล์NSData. คุณยังไม่ได้รับสตริงจากนั้น
rmaddy

คำตอบ:


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

การดำเนินการผกผัน (hex String -> Data) มีอยู่ที่นี่: stackoverflow.com/a/46663290/5252428
Rok Gregorič

4
%02xก็โอเคเหมือนกัน
jqgsninimo

1
@ ร็อคคุณช่วยอธิบายคำตอบของคุณได้ไหม? รูปแบบใหม่ที่โทเค็นถูกฟอร์แมตเป็นอย่างไร
simo

@simo เป็นการแปลงจากข้อมูลเป็นสตริงเลขฐานสิบหกที่คุณสามารถส่งผ่านไปยังบริการเว็บ / API เพื่อให้สามารถส่งการแจ้งเตือนแบบพุชได้
Rok Gregorič

โพสต์ที่ดีพร้อมคำอธิบายที่ดีเกี่ยวกับความแตกต่างระหว่าง%02.2hhxและ%02x nshipster.com/apns-device-tokens/#overturned-in-ios-13
Rok Gregorič

35

ผมมีปัญหาเหมือนกัน. นี่คือทางออกของฉัน:

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
นี่เป็นวิธีอื่นในการเข้ารหัสNSDataเป็นสตริง ฉันแนะนำให้ใช้การเข้ารหัส base64 ในคำตอบของฉัน ใช้การเข้ารหัส base16
rmaddy

@rmaddy วิธีของคุณก็น่าสนใจเช่นกัน แต่จะมีประโยชน์มากกว่านี้ถ้าคุณให้คำแนะนำกับเราด้วยรหัส !!!
vivek agravat

29

นี่คือส่วนขยาย Swift 3 ของฉันเพื่อรับสตริงฐานสิบหกที่เข้ารหัสฐาน 16:

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

ฉันสังเกตว่ารูปแบบ "% 02x" ก็ใช้ได้เช่นกัน ฉันไม่เข้าใจเหมือนกันว่า "hh" ทำอะไร
Andrei

1
@andrei "hh" บอกให้ตัวจัดรูปแบบสตริงถือว่าอินพุตเป็นตัวอักษร อย่างไรก็ตามในความรวดเร็ว Data เป็นชุดของ UInt8 ดังนั้นคุณไม่จำเป็นต้องใช้
wyu

27

โทเค็นอุปกรณ์ไม่เคยเป็นสตริงและไม่ใช่สตริงที่เข้ารหัส UTF-8 อย่างแน่นอน เป็นข้อมูล เป็นข้อมูลทึบแสง 32 ไบต์

วิธีเดียวที่ถูกต้องในการแปลงข้อมูลทึบแสงเป็นสตริงคือการเข้ารหัส - โดยทั่วไปจะใช้การเข้ารหัส base64

ใน Swift 3 / iOS 10 เพียงแค่ใช้Data base64EncodedString(options:)วิธีนี้


ความแตกต่างที่นี่คือประเภทข้อมูลใหม่ ฉันเพิ่งลองแปลง deviceToken เป็น NSData และตอนนี้มันก็พิมพ์โทเค็นอุปกรณ์ของฉันเหมือนเดิม คุณมีตัวอย่างวิธีจัดการกับสิ่งนี้โดยไม่มี NSData หรือไม่? เนื่องจากสิ่งนี้ให้ความรู้สึกแฮ็ค แต่ก็ตรงไปตรงมามากกว่าที่พวกเขาคาดหวังให้เราทำ
user1537360

3
ฉันยืนตามสิ่งที่ฉันพูด NSDataหรือDataมันไม่สำคัญ ไบต์ของข้อมูลไม่ใช่และไม่เคยเป็นสตริง เอกสารระบุชัดเจนว่าเป็นชุดข้อมูลทึบแสง ความจริงที่ว่ารหัสของคุณใช้ในการทำงานคือโชค เป็นวิธีจัดการที่ไม่ถูกต้องเสมอมา เพียงแค่แปลงข้อมูลเป็นสตริงโดย base64 เข้ารหัสข้อมูล นั่นเป็นทางออกที่เหมาะสมทั้งในตอนนี้และก่อนหน้านี้
rmaddy

การถอดรหัส Base64 จะไม่ทำงานหากคุณใช้บริการเช่น Amazon SNS โซลูชันที่แปลงข้อมูลเป็นอักขระเลขฐานสิบหกเช่น@satheeshwaranจะสร้างสตริงโทเค็นอุปกรณ์ที่คล้ายกับรายการก่อนการเปลี่ยนแปลงใน SDK
Alexander

@Alexander ใครพูดอะไรเกี่ยวกับการถอดรหัส Base64? ประเด็นทั้งหมดของคำถามและคำตอบคือการเข้ารหัสข้อมูลดิบไม่ใช่ถอดรหัสเป็นสตริง เหตุผลเดียวที่จะดำเนินการนี้คือการดูข้อมูลดิบ รูปแบบการเข้ารหัสเฉพาะไม่เกี่ยวข้อง คำตอบอื่น ๆ คือการใช้การเข้ารหัสฐาน 16 ฉันพูดถึงการใช้การเข้ารหัสฐาน 64
rmaddy

@rmaddy ฉันหมายถึงการเข้ารหัส Base64 ในความคิดเห็นของฉันขอโทษของฉัน
Alexander

15

ลองสิ่งนี้:

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

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

2
ดูเหมือนว่าตอนนี้จะส่งคืนโทเค็นที่แตกต่างกัน
ChikabuZ


7

สวิฟต์ 3

วิธีที่ดีที่สุดและง่ายที่สุด

deviceToken.base64EncodedString()

3
วิธีนี้ง่ายที่สุด แต่โปรดระวังสิ่งที่เซิร์ฟเวอร์ของคุณใช้หากคุณกำลังส่งโทเค็นออก API จำนวนมากคาดหวังด้วยการเข้ารหัส Hex หรือ Base-16 ตัวอย่างเช่น Django Push Notifications
sww314

4

ข้อนี้ไม่ได้ระบุว่าเป็นคำตอบอย่างเป็นทางการ (เห็นในความคิดเห็น) แต่ในที่สุดฉันก็ทำเพื่อให้โทเค็นกลับมาเป็นลำดับ

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) ของเราสิ่งนี้กลายเป็นโซลูชันที่ "สะอาดที่สุด" ¯ \ _ (ツ) _ / ¯
race_carr

1
สิ่งนี้ใช้ไม่ได้ใน iOS 10 ตอนนี้คำอธิบายจะคืนค่าเป็น "32 ไบต์" เท่านั้น
edopelawi

@edopelawi คุณลืมใส่ที่as NSDataนั่น เมื่อคุณใส่เป็น NSData ไม่ใช่ Data จะส่งคืนค่าที่ถูกต้องแม้ใน 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
แม้ว่าบล็อกโค้ดนี้อาจตอบคำถามได้ แต่จะเป็นการดีที่สุดหากคุณสามารถให้คำอธิบายเล็กน้อยว่าเหตุใดจึงเป็นเช่นนั้น
Crispin

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

0

รับโทเค็นอุปกรณ์ด้วยรูปแบบที่เหมาะสม

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)
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.