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 2016

回答:


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

逆演算(16進文字列->データ)は、こちらから入手できます:stackoverflow.com/a/46663290/5252428
RokGregoričOct

4
%02x大丈夫です。
jqgsninimo 2017年

1
@ロク、あなたの答えを説明してくれませんか?トークンがフォーマットされた新しいフォーマットは何ですか?
シモ

@simoは、データから16進文字列への変換で、プッシュ通知を送信できるようにWebサービス/ APIに渡すことができます。
RokGregorič19年


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 2017

29

これが、ベース16でエンコードされた16進文字列を取得するためのSwift 3拡張機能です。

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

「%02x」形式も機能することに気づきました。私はまた、「HH」は何をするか理解できない
アンドレイ

1
@andrei "hh"は、文字列フォーマッタに入力を文字として扱うように指示します。ただし、迅速に言えば、DataはUInt8のコレクションなので、必要ありません
wyu

27

デバイストークンは文字列ではなく、UTF-8でエンコードされた文字列でもありません。データです。これは32バイトの不透明なデータです。

不透明なデータを文字列に変換する唯一の有効な方法は、それをエンコードすることです-通常、base64エンコードを使用します。

Swift 3 / iOS 10では、Data base64EncodedString(options:)メソッドを使用するだけです。


ここでの違いは、新しいデータ型です。deviceTokenをNSDataに変換しようとしたところ、以前と同じようにデバイストークンが出力されます。NSDataなしでこれに対処する方法の例はありますか?これはハッキリと感じますが、彼らが私たちに期待することよりも簡単です。
user1537360 2016

3
私は私が言ったことを支持します。NSDataまたはData、それは問題ではありません。データのバイトは文字列ではありません。ドキュメントは、それが不透明なデータのセットであることを明確に述べています。コードが機能していたという事実は幸運です。それは常にそれを処理するための誤った方法でした。データをbase64エンコードして、データを文字列に変換するだけです。それは今も以前も適切な解決策です。
rmaddy 2016

Amazon SNSなどのサービスを使用する場合、Base64デコードは機能しません。データを@satheeshwaranなどの16進文字に変換するソリューションは、SDKが変更される前の文字列に似たデバイストークン文字列を生成します。
アレクサンダー

@Alexander誰がBase64デコードについて何か言ったのですか?質問と回答の要点は、デコードではなく生データを文字列にエンコードすることです。これを行う唯一の理由は、生データを表示することです。特定のコード化スキームは無関係です。もう1つの答えは、base 16エンコーディングを使用することです。Base 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

8

これを試して

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

7

スウィフト3

最善かつ最も簡単な方法。

deviceToken.base64EncodedString()

3
これが最も簡単ですが、トークンを渡す場合は、サーバーが何を使用しているかに注意してください。多くのAPIは、HexエンコードまたはBase-16で期待しています。たとえば、Djangoプッシュ通知。
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(パイソン)の目的のために、これは"きれいな"ソリューション¯\ _(ツ)_ /¯ことになった
race_carr

1
これはiOS 10では機能しません。説明は「32バイト」のみを返すようになりました。
edopelawi

@edopelawiあなたがas NSDataそこに置くのを忘れた。iOS 10でもNSDataではなくNSDataとして配置すると、正しい値が返されます
Jakub

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

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


}

4
このコードブロックが質問に答える可能性がありますが、なぜそうなるのかについて少し説明を提供できれば最適です。
クリスピン2017年

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.