我正在实施推送通知。我想将我的APNS令牌保存为字符串。
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
{
NSString *tokenString = [NSString stringWithUTF8String:[newDeviceToken bytes]]; //[[NSString alloc]initWithData:newDeviceToken encoding:NSUTF8StringEncoding];
NSLog(@"%@", tokenString);
NSLog(@"%@", newDeviceToken);
}
第一行代码打印为null。第二个打印令牌。如何将newDeviceToken作为NSString?
用这个 :
NSString * deviceTokenString = [[[[deviceToken description]
stringByReplacingOccurrencesOfString: @"<" withString: @""]
stringByReplacingOccurrencesOfString: @">" withString: @""]
stringByReplacingOccurrencesOfString: @" " withString: @""];
NSLog(@"The generated device token string is : %@",deviceTokenString);
一个班轮:
let hexString = UnsafeBufferPointer<UInt8>(start: UnsafePointer(data.bytes),
count: data.length).map { String(format: "%02x", $0) }.joinWithSeparator("")
这是一个可重用且自我记录的扩展形式:
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),因为填充零所需的一位数字
(我还不知道如何将问题标记为this other one的副本,所以我刚刚发布了我的答案)
对于Swift:
var characterSet: NSCharacterSet = NSCharacterSet( charactersInString: "<>" )
var deviceTokenString: String = ( deviceToken.description as NSString )
.stringByTrimmingCharactersInSet( characterSet )
.stringByReplacingOccurrencesOfString( " ", withString: "" ) as String
println( deviceTokenString )
在堆上扔我的答案。避免使用字符串解析;文档无法保证NSData.description将始终以这种方式工作。
Swift 3实施:
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()
}
}
我试图用格式"%02.2hhx"
和"%02x"
测试两种不同的方法
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:
deviceToken.reduce("", {$0 + String(format: "%02x", $1)})
高票%02.2hhx
中answer的解释:
%
:介绍x
转换说明符。02
:转换值的最小宽度为2.如果转换后的值的字节数少于字段宽度,则应在左侧填充0
。.2
:给出x
转换说明符的最小位数。hh
:指定x
转换说明符适用于signed char或unsigned char参数(该参数将根据整数提升进行提升,但其值应在打印前转换为signed char或unsigned char)。x
:无符号参数应转换为“dddd”样式的无符号十六进制格式;使用字母“abcdef”。精度指定要显示的最小位数;如果转换的值可以用较少的数字表示,则应使用前导零进行扩展。默认精度为1.使用显式精度零转换零的结果不应为字符。有关更多详细信息,请参阅IEEE printf specification。
基于上面的解释,我认为最好将%02.2hhx
改为%02x
或%.2x
。
对于Swift 5,以下方法都是可行的:
deviceToken.map({String(format: "%02x", $0)}).joined()
deviceToken.map({String(format: "%.2x", $0)}).joined()
deviceToken.reduce("", {$0 + String(format: "%02x", $1)})
deviceToken.reduce("", {$0 + String(format: "%.2x", $1)})
测试如下:
let deviceToken = (0..<32).reduce(Data(), {$0 + [$1]})
print(deviceToken.reduce("", {$0 + String(format: "%.2x", $1)}))
// Print content:
// 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
迅速:
let tokenString = deviceToken.description.stringByReplacingOccurrencesOfString("[ <>]", withString: "", options: .RegularExpressionSearch, range: nil)
迅速
// 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)")
}
这是你在Xamarin.iOS中的表现
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
}
-(NSString *)deviceTokenWithData:(NSData *)data
{
NSString *deviceToken = [[data description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
deviceToken = [deviceToken stringByReplacingOccurrencesOfString:@" " withString:@""];
return deviceToken;
}
NSString *tokenString = [[newDeviceToken description] stringByReplacingOccurrencesOfString:@"[<> ]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [[newDeviceToken description] length])];
如果有人想在Swift中这样做:
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引入了Data
类型,具有值语义。要将deviceToken
转换为String,您可以执行以下操作:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
print(token)
}
斯威夫特3:
如果有人正在寻找一种在Swift 3中获取设备令牌的方法。请使用以下修改后的代码段。
let characterSet: CharacterSet = CharacterSet( charactersIn: "<>" )
let deviceTokenString: String = (deviceToken.description as NSString)
.trimmingCharacters(in: characterSet as CharacterSet)
.replacingOccurrences(of: " ", with: "")
.uppercased()
print(deviceTokenString)
使用优秀的类别!
// .h文件
@interface NSData (DeviceToken)
- (NSString *)stringDeviceToken;
@end
// .m文件
#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;
}
@结束
// AppDelegate.m
#import "NSData+DeviceToken.h"
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token = deviceToken.stringDeviceToken;
}
工作良好!
var token: String = ""
for i in 0..<deviceToken.count {
token += String(format: "%02.2hhx", deviceToken[i] as CVarArg)
}
print(token)
尝试这个,除非数据以空值终止。
NSString* newStr = [[NSString alloc] initWithData:newDeviceToken
encoding:NSUTF8StringEncoding];
NSString *tokenstring = [[NSString alloc] initWithData:token encoding:NSUTF8StringEncoding];
有人用这帮我。我只是路过
- (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];
}
你可以用它
- (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];
}
对于那些想要在Swift 3和最简单的方法
func extractTokenFromData(deviceToken:Data) -> String {
let token = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
return token.uppercased();
}
这是我的解决方案,它在我的应用程序中运行良好:
NSString* newToken = [[[NSString stringWithFormat:@"%@",deviceToken]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""];
NSData
将NSString
转换为stringWithFormat
我认为将deviceToken转换为十六进制字节字符串是没有意义的。为什么?您将它发送到您的后端,在那里它将被转换回字节以推送到APNS。所以,使用NSData的方法base64EncodedStringWithOptions
,将其推送到服务器,然后使用反向base64decoded数据:)这是如此容易:)
NSString *tokenString = [tokenData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
这是一个稍微简短的解决方案:
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])];
一线解决方案怎么样?
目标C.
NSString *token = [[data.description componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet]invertedSet]]componentsJoinedByString:@""];
迅速
let token = data.description.componentsSeparatedByCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet).joinWithSeparator("")