Swift 3 - маркери пристрою тепер аналізуються як '32BYTES'


94

Я щойно оновився з Xcode 7 на 8 GM, і серед проблем сумісності Swift 3 я помітив, що мої маркери пристроїв перестали працювати. Зараз вони читають лише "32БАЙТИ".

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

Зворотна операція (жердина String -> Data) доступна тут: stackoverflow.com/a/46663290/5252428
Rok Gregoric

4
%02xце теж нормально.
jqgsninimo

1
@Rok, ти можеш пояснити свою відповідь? до якого нового формату був відформатований цей маркер?
simo

@simo - це перетворення з даних у шістнадцятковий рядок, яке ви можете передати веб-службі / API для можливості надсилати push-сповіщення.
Рок Грегоріч,

Хороший допис з гарним поясненням відмінностей між %02.2hhxі %02x nshipster.com/apns-device-tokens/#overturned-in-ios-13
Рок Грегоріч,

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"
андрей,

1
@andrei "hh" вказує форматору рядків обробляти введення як символ. Однак швидко, Дані - це колекція 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 Хто щось сказав про декодування Base64? Вся суть питання та відповідей полягає в кодуванні необроблених даних, а не декодуванні, у рядок. Єдина причина зробити щось із цього - перегляд вихідних даних. Конкретна схема кодування не має значення. Інша відповідь - використання кодування за базою 16. Я згадав про використання базового кодування 64.
rmaddy

@rmaddy Я мав на увазі кодування Base64 у своєму коментарі, свої вибачення.
Олександр

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) це
виявилось

1
Це не працює в iOS 10. Опис тепер повертає лише "32 байти".
edopelawi,

@edopelawi ви забули туди поставити as NSData. коли ви ставите як NSData not Дані повернуть правильне значення навіть на iOS 10
Якуб

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

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


}

4
Хоча цей блок коду може відповісти на запитання, найкраще, якщо ви зможете надати невелике пояснення, чому він це робить.
Кріспін,

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)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.