Как преобразовать токен устройства (NSData) в NSString?
Я внедряю push-уведомления. Я бы хотел сохранить токен APNS как строку.
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
{
NSString *tokenString = [NSString stringWithUTF8String:[newDeviceToken bytes]]; //[[NSString alloc]initWithData:newDeviceToken encoding:NSUTF8StringEncoding];
NSLog(@"%@", tokenString);
NSLog(@"%@", newDeviceToken);
}
Первая строка кода печатает нуль. второй печатает токен. Как я могу получить свой newDeviceToken как NSString?
Ответы
Ответ 1
используйте это:
NSString * deviceTokenString = [[[[deviceToken description]
stringByReplacingOccurrencesOfString: @"<" withString: @""]
stringByReplacingOccurrencesOfString: @">" withString: @""]
stringByReplacingOccurrencesOfString: @" " withString: @""];
NSLog(@"The generated device token string is : %@",deviceTokenString);
Ответ 2
Если кто-то ищет способ сделать это в 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
Swift 3 вводит тип Data
со значениями семантики. Чтобы преобразовать deviceToken
в строку, вы можете сделать следующее:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
print(token)
}
Ответ 3
Кто-то помог мне с этим. Я просто прохожу
- (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];
}
Ответ 4
Вы можете использовать этот
- (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];
}
Ответ 5
Для тех, кто хочет в Swift 3 и наиболее удобном методе
func extractTokenFromData(deviceToken:Data) -> String {
let token = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
return token.uppercased();
}
Ответ 6
Это мое решение, и оно хорошо работает в моем приложении:
NSString* newToken = [[[NSString stringWithFormat:@"%@",deviceToken]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""];
- конвертировать
NSData
в NSString
с помощью stringWithFormat
- нарисуйте "< > "
- удалить пробелы
Ответ 7
Я думаю, что преобразование deviceToken в шестнадцатеричную байтовую строку не имеет смысла. Зачем? Вы отправите его на свой сервер, где он будет преобразован обратно в байты, которые будут перенесены в APNS. Итак, используйте NSDatastrong > метод base64EncodedStringWithOptions
, нажмите его на сервер, а затем используйте обратные данные с базовым 64-разрядным кодом:) Это намного проще:)
NSString *tokenString = [tokenData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
Ответ 8
Объяснение %02.2hhx
в ответе высокого голосования:
%
: вводит спецификатор преобразования x
.
02
: минимальная ширина преобразованного значения равна 2. Если преобразованное значение имеет меньше байтов, чем ширина поля, оно должно быть дополнено 0
слева.
.2
: отображает минимальное количество цифр для спецификатора преобразования x
.
hh
: указывает, что спецификатор преобразования x
применяется к аргументу char со знаком или без знака (аргумент будет повышен в соответствии с целочисленными акциями, но его значение должно быть преобразовано в char со знаком или без знака перед печатью).
x
: Аргумент без знака должен быть преобразован в шестнадцатеричный формат без знака в стиле "dddd"; буквы "abcdef" используются. Точность определяет минимальное количество отображаемых цифр; если конвертируемое значение может быть представлено меньшим количеством цифр, оно должно быть расширено начальными нулями. Точность по умолчанию равна 1. Результатом преобразования нуля с явной точностью нуля не должно быть символов.
Для получения дополнительной информации см. спецификацию printf IEEE.
Исходя из приведенного выше объяснения, я думаю, что лучше изменить %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
Ответ 9
Это немного более короткое решение:
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])];
Ответ 10
Функциональная версия Swift
Один вкладыш:
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("")
для просмотра в качестве функционального мастера вашими сверстниками.
Изменить: я изменил String ($ 0, radix: 16) на String (формат: "% 02x", $0), потому что для одного номера цифр необходимо иметь нулевой пробел
(Я еще не знаю, как отметить вопрос как дубликат этого другого, поэтому я только что отправил свой ответ снова)
Ответ 11
Бросив мой ответ на кучу. Избегайте использования синтаксического анализа строк; Это не гарантирует документы, что 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()
}
}
Ответ 12
В iOS 13 description
сломается, так что используйте это
let deviceTokenString = deviceToken.map { String(format: "%02x", $0) }.joined()
Для ясности давайте разберем это и объясним каждую часть:
Метод map работает с каждым элементом последовательности. Поскольку Data - это последовательность байтов в Swift, переданное закрытие оценивается для каждого байта в deviceToken.
Инициализатор String (format :) вычисляет каждый байт данных (представленный анонимным параметром $ 0), используя спецификатор формата% 02x, чтобы получить заполненное нулями 2-значное шестнадцатеричное представление байта /8-разрядного целого числа.
После сбора каждого байтового представления, созданного методом map, join() объединяет каждый элемент в одну строку.
P.S не использует описание, дает разные строки в iOS 12 и iOS 13 и небезопасно согласно будущей области видимости. Разработчики не должны были полагаться на определенный формат для описания объектов.
// iOS 12
(deviceToken as NSData).description // "<965b251c 6cb1926d e3cb366f dfb16ddd e6b9086a 8a3cac9e 5f857679 376eab7C>"
// iOS 13
(deviceToken as NSData).description // "{length = 32, bytes = 0x965b251c 6cb1926d e3cb366f dfb16ddd ... 5f857679 376eab7c }"
Для получения дополнительной информации прочитайте это.
Ответ 13
Как насчет решения одной строки?
Цель C
NSString *token = [[data.description componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet]invertedSet]]componentsJoinedByString:@""];
Свифта
let token = data.description.componentsSeparatedByCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet).joinWithSeparator("")
Ответ 14
Я попытался протестировать два разных метода с помощью формата "%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)})
Ответ 15
Использование updateAccumulationResult более эффективно, чем различные другие подходы, найденные здесь, поэтому здесь самый быстрый способ для строкового преобразования ваших байтов Data
:
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.reduce(into: "") { $0 += String(format: "%.2x", $1) }
print(token)
}
Ответ 16
Для Swift:
var characterSet: NSCharacterSet = NSCharacterSet( charactersInString: "<>" )
var deviceTokenString: String = ( deviceToken.description as NSString )
.stringByTrimmingCharactersInSet( characterSet )
.stringByReplacingOccurrencesOfString( " ", withString: "" ) as String
println( deviceTokenString )
Ответ 17
Swift
// 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)")
}
Ответ 18
Вот как вы это делаете в 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
}
Ответ 19
-(NSString *)deviceTokenWithData:(NSData *)data
{
NSString *deviceToken = [[data description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
deviceToken = [deviceToken stringByReplacingOccurrencesOfString:@" " withString:@""];
return deviceToken;
}
Ответ 20
NSString *tokenString = [[newDeviceToken description] stringByReplacingOccurrencesOfString:@"[<> ]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [[newDeviceToken description] length])];
Ответ 21
Swift:
let tokenString = deviceToken.description.stringByReplacingOccurrencesOfString("[ <>]", withString: "", options: .RegularExpressionSearch, range: nil)
Ответ 22
Swift 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)
Ответ 23
введите описание изображения здесь. Чтобы преобразовать NSData в NSString в Swift 4.2, вы можете использовать код ниже, посмотрите на изображение ниже
Ответ 24
Используйте отличную категорию!
//.h файл
@interface NSData (DeviceToken)
- (NSString *)stringDeviceToken;
@end
//.m file
#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;
}
@end
//AppDelegate.m
#import "NSData+DeviceToken.h"
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token = deviceToken.stringDeviceToken;
}
Прекрасно работает!
Ответ 25
Решение @kulss, опубликованное здесь, хотя и лишено элегантности, но обладает простотой, больше не работает в iOS 13, так как description
будет работать по-другому для NSData. Вы все еще можете использовать debugDescription
, хотя.
NSString * deviceTokenString = [[[[deviceToken debugDescription]
stringByReplacingOccurrencesOfString: @"<" withString: @""]
stringByReplacingOccurrencesOfString: @">" withString: @""]
stringByReplacingOccurrencesOfString: @" " withString: @""];
Ответ 26
var token: String = ""
for i in 0..<deviceToken.count {
token += String(format: "%02.2hhx", deviceToken[i] as CVarArg)
}
print(token)
Ответ 27
Попробуйте выполнить это, если данные не завершены нулями.
NSString* newStr = [[NSString alloc] initWithData:newDeviceToken
encoding:NSUTF8StringEncoding];
Ответ 28
NSString *tokenstring = [[NSString alloc] initWithData:token encoding:NSUTF8StringEncoding];