关于iphone:如何将设备令牌(NSData)转换为NSString?

How can I convert my device token (NSData) into an NSString?

我正在实现推送通知。我想把我的APN令牌保存为字符串。

1
2
3
4
5
6
7
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
{
    NSString *tokenString = [NSString stringWithUTF8String:[newDeviceToken bytes]]; //[[NSString alloc]initWithData:newDeviceToken encoding:NSUTF8StringEncoding];
    NSLog(@"%@", tokenString);
    NSLog(@"%@", newDeviceToken);
}

第一行代码打印空值。第二个打印令牌。如何将新设备标记为nsstring?


如果有人正在寻找一种快速完成这项工作的方法:

1
2
3
4
5
6
7
8
9
10
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
    var tokenString =""

    for i in 0..<deviceToken.length {
        tokenString += String(format:"%02.2hhx", arguments: [tokenChars[i]])
    }

    print("tokenString: \(tokenString)")
}

编辑:用于Swift 3

swift 3引入了Data类型,具有值语义。要将deviceToken转换为字符串,可以执行以下操作:

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


有人帮了我,我只是路过而已

1
2
3
4
5
6
7
8
9
10
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {

    const unsigned *tokenBytes = [deviceToken bytes];
    NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                         ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                         ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                         ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];

    [[MyModel sharedModel] setApnsToken:hexToken];
}


你可以用这个

1
2
3
4
5
6
7
8
9
10
- (NSString *)stringWithDeviceToken:(NSData *)deviceToken {
    const char *data = [deviceToken bytes];
    NSMutableString *token = [NSMutableString string];

    for (NSUInteger i = 0; i < [deviceToken length]; i++) {
        [token appendFormat:@"%02.2hhX", data[i]];
    }

    return [token copy];
}


使用此:

1
2
3
4
5
6
NSString * deviceTokenString = [[[[deviceToken description]
                         stringByReplacingOccurrencesOfString: @"<" withString: @""]
                        stringByReplacingOccurrencesOfString: @">" withString: @""]
                       stringByReplacingOccurrencesOfString: @"" withString: @""];

NSLog(@"The generated device token string is : %@",deviceTokenString);


对于那些想要快速3和最简单方法的人

1
2
3
4
func extractTokenFromData(deviceToken:Data) -> String {
    let token = deviceToken.reduce("", {$0 + String(format:"%02X", $1)})
    return token.uppercased();
}


这是我的解决方案,它在我的应用程序中运行良好:

1
2
    NSString* newToken = [[[NSString stringWithFormat:@"%@",deviceToken]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@"" withString:@""];
  • stringWithFormatNSData转换为NSString
  • 修剪"< >"
  • 删除空格


我认为将devicetoken转换为十六进制字节字符串是没有意义的。为什么?您将把它发送到您的后端,在那里它将被转换回要推送到APN的字节。所以,使用nsdata的方法base64EncodedStringWithOptions,将它推到服务器上,然后使用反向base64解码的数据:)这非常简单:)

1
NSString *tokenString = [tokenData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];


这是一个简短的解决方案:

1
2
3
4
5
NSData *token = // ...
const uint64_t *tokenBytes = token.bytes;
NSString *hex = [NSString stringWithFormat:@"%016llx%016llx%016llx%016llx",
                 ntohll(tokenBytes[0]), ntohll(tokenBytes[1]),
                 ntohll(tokenBytes[2]), ntohll(tokenBytes[3])];

功能性swift版本

一班轮:

1
2
let hexString = UnsafeBufferPointer<UInt8>(start: UnsafePointer(data.bytes),
count: data.length).map { String(format:"%02x", $0) }.joinWithSeparator("")

以下是一个可重用的自文档扩展表单:

1
2
3
4
5
6
7
8
9
10
11
12
extension NSData {
    func base16EncodedString(uppercase uppercase: Bool = false) -> String {
        let buffer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes),
                                                count: self.length)
        let hexFormat = uppercase ?"X" :"x"
        let formatString ="%02\(hexFormat)"
        let bytesAsHexStrings = buffer.map {
            String(format: formatString, $0)
        }
        return bytesAsHexStrings.joinWithSeparator("")
    }
}

或者,用reduce("", combine: +)代替joinWithSeparator(""),让你的同龄人将其视为功能大师。

编辑:我将字符串($0,基数:16)更改为字符串(格式:"%02X",$0),因为一个数字需要填充零

(我还不知道如何将一个问题标记为另一个问题的副本,所以我再次发布了我的答案)


一条线解决方案怎么样?

目标C

1
NSString *token = [[data.description componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet]invertedSet]]componentsJoinedByString:@""];

迅捷

1
let token = data.description.componentsSeparatedByCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet).joinWithSeparator("")


Swift:

1
2
3
4
5
6
var characterSet: NSCharacterSet = NSCharacterSet( charactersInString:"<>" )
    var deviceTokenString: String = ( deviceToken.description as NSString )
    .stringByTrimmingCharactersInSet( characterSet )
    .stringByReplacingOccurrencesOfString("", withString:"" ) as String

println( deviceTokenString )

高票答卷中对%02.2hhx的解释:

  • %:介绍x转换说明符。
  • 02:转换值的最小宽度为2。如果转换值的字节数小于字段宽度,则应在左侧填充0
  • .2:给出x转换说明符要显示的最小位数。
  • hh:指定x转换说明符应用于有符号char或无符号char参数(参数将根据整数提升进行提升,但其值在打印前应转换为有符号char或无符号char)。
  • x:无符号参数转换为无符号十六进制格式,格式为"dddd";使用字母"abcdef"。精度规定了要显示的最小位数;如果要转换的值可以用较少的位数表示,则应使用前导零进行扩展。默认精度为1。明确精度为零的零转换结果不应为字符。

有关详细信息,请参阅IEEE printf规范。

基于以上的解释,我认为最好把%02.2hhx改为%02x%.2x

对于Swift 5,以下方法都是可行的:

1
deviceToken.map({String(format:"%02x", $0)}).joined()
1
deviceToken.map({String(format:"%.2x", $0)}).joined()
1
deviceToken.reduce("", {$0 + String(format:"%02x", $1)})
1
deviceToken.reduce("", {$0 + String(format:"%.2x", $1)})

试验如下:

1
2
3
4
let deviceToken = (0..<32).reduce(Data(), {$0 + [$1]})
print(deviceToken.reduce("", {$0 + String(format:"%.2x", $1)}))
// Print content:
// 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f

我试过用格式"%02.2hhx""%02x"测试两种不同的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    var i :Int = 0
    var j: Int = 0
    let e: Int = Int(1e4)
    let time = NSDate.timeIntervalSinceReferenceDate
    while i < e {
        _ =  deviceToken.map { String(format:"%02x", $0) }.joined()
        i += 1
    }
    let time2 = NSDate.timeIntervalSinceReferenceDate
    let delta = time2-time
    print(delta)

    let time3 = NSDate.timeIntervalSinceReferenceDate
    while j < e {
        _ =  deviceToken.reduce("", {$0 + String(format:"%02x", $1)})
        j += 1
    }
    let time4 = NSDate.timeIntervalSinceReferenceDate
    let delta2 = time4-time3
    print(delta2)

其结果是,最快的是"%02x",平均2.0比2.6(对于精简版:

1
deviceToken.reduce("", {$0 + String(format:"%02x", $1)})

把我的答案扔到一叠纸上。避免使用字符串分析;文档不保证nsdata.description总是这样工作。

Swift 3实施:

1
2
3
4
5
6
7
8
9
10
extension Data {
    func hexString() -> String {
        var bytesPointer: UnsafeBufferPointer<UInt8> = UnsafeBufferPointer(start: nil, count: 0)
        self.withUnsafeBytes { (bytes) in
            bytesPointer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(bytes), count:self.count)
        }
        let hexBytes = bytesPointer.map { return String(format:"%02hhx", $0) }
        return hexBytes.joined()
    }
}


Swift:

1
let tokenString = deviceToken.description.stringByReplacingOccurrencesOfString("[ <>]", withString:"", options: .RegularExpressionSearch, range: nil)

以下是在xamarin.ios中的操作方法

1
2
3
4
5
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    var tokenStringBase64 = deviceToken.GetBase64EncodedString(NSDataBase64EncodingOptions.None);
    //now you can store it for later use in local storage
}

迅捷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    // make sure that we have token for the devie on the App
    func application(application: UIApplication
        , didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {

            var tokenStr = deviceToken.description
            tokenStr = tokenStr.stringByReplacingOccurrencesOfString("<", withString:"", options: [], range: nil)
            tokenStr = tokenStr.stringByReplacingOccurrencesOfString(">", withString:"", options: [], range: nil)
            tokenStr = tokenStr.stringByReplacingOccurrencesOfString("", withString:"", options: [], range: nil)



            print("my token is: \(tokenStr)")

    }

1
2
3
4
5
6
-(NSString *)deviceTokenWithData:(NSData *)data
{
    NSString *deviceToken = [[data description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    deviceToken = [deviceToken stringByReplacingOccurrencesOfString:@"" withString:@""];
    return deviceToken;
}

斯威夫特3:

如果有人想在Swift 3中获取设备令牌。使用下面修改的代码段。

1
2
3
4
5
6
7
8
    let characterSet: CharacterSet = CharacterSet( charactersIn:"<>" )

    let deviceTokenString: String = (deviceToken.description as NSString)
        .trimmingCharacters(in: characterSet as CharacterSet)
        .replacingOccurrences(of:"", with:"")
        .uppercased()

    print(deviceTokenString)


1
NSString *tokenString = [[newDeviceToken description] stringByReplacingOccurrencesOfString:@"[<> ]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [[newDeviceToken description] length])];


使用优秀的类别!

//h文件

1
2
3
4
5
@interface NSData (DeviceToken)

- (NSString *)stringDeviceToken;

@end

//m文件

1
2
3
4
5
6
7
8
9
10
11
12
#import"NSData+DeviceToken.h"

@implementation NSData (DeviceToken)

- (NSString *)stringDeviceToken {
    const unsigned *deviceTokenBytes = [deviceToken bytes];
    NSString *deviceToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                     ntohl(deviceTokenBytes[0]), ntohl(deviceTokenBytes[1]), ntohl(deviceTokenBytes[2]),
                     ntohl(deviceTokenBytes[3]), ntohl(deviceTokenBytes[4]), ntohl(deviceTokenBytes[5]),
                     ntohl(deviceTokenBytes[6]), ntohl(deviceTokenBytes[7])];
    return deviceToken;
}

@结束

//应用委托.m

1
2
3
4
5
6
#import"NSData+DeviceToken.h"

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSString *token = deviceToken.stringDeviceToken;
}

工作很好!


1
2
3
4
5
6
var token: String =""
for i in 0..<deviceToken.count {
    token += String(format:"%02.2hhx", deviceToken[i] as CVarArg)
}

print(token)


请尝试此操作,除非数据以NULL结尾。

NSString* newStr = [[NSString alloc] initWithData:newDeviceToken
encoding:NSUTF8StringEncoding];


1
NSString *tokenstring = [[NSString alloc] initWithData:token encoding:NSUTF8StringEncoding];