33

I am receiving iPhone device token in the form of NSData object. When I tested my notifications script function, I have only copied that object from log and the notifications went fine. However when I try now to automatically do it, I am sending the device token as ASCII encoded string in the form of variable

self.deviceToken = [[NSString alloc] initWithData:webDeviceToken encoding:NSASCIIStringEncoding];

The string that I am getting has some funky characters and looks similar to this "å-0¾fZÿ÷ʺÎUQüRáqEªfÔk«"

When server side script sends the notification to that token, I am not receiving anything.

Do I need to decode something and how?

Regardz

Venk
  • 5,949
  • 9
  • 41
  • 52
Mladen
  • 25,578
  • 11
  • 39
  • 48
  • I found another solution here, looks more future-proof then the "description" method. http://stackoverflow.com/questions/1959600/how-to-use-objective-c-to-send-device-token-for-push-notifications-and-other-use – 廖維平 Mar 19 '13 at 09:07
  • This's weird, I think this NSData* shouldn't be special kind object, so I tried using NSUTF8StringEncoding and get a different result. It's unimagable for me to convert NSData to NSString with **description** method! Some apple documendation related? – Itachi Jul 21 '15 at 09:17

6 Answers6

107

Ok, I found a solution. If anyone has the same problem, forget about ASCII encoding, just make the string with the following lines:

NSString *deviceToken = [[webDeviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
deviceToken = [deviceToken stringByReplacingOccurrencesOfString:@" " withString:@""];
Mladen
  • 25,578
  • 11
  • 39
  • 48
  • 8
    Please stop upvoting this answer, this uses the token .description - which is just that, a description. It is meant to be read by a human for debugging purposes or display. The "<" and ">" are not part of the token, they are just for display formatting. Apple could change it to "[" or "-" or whatever in the future if they wanted. Use one of the answers that converts the data to a hex string instead. – Michael Peterson May 25 '16 at 03:37
43

If anyone is looking for a way to do this in 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)")
}

Edit: For Swift 3

Swift 3 introduces the Data type, with value semantics. To convert the deviceToken to a String, you can do as follows:

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

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

    print(token)
}
Oscar Swanros
  • 19,767
  • 5
  • 32
  • 48
Sascha
  • 5,903
  • 3
  • 24
  • 20
  • 1
    Its surprising that there's no easy way in swift to get the appropriately decoded string data from the NSData device token object. But this is example fro @sascha is the first thing I have come across that actually works! Thank you. – Shiprack Feb 21 '15 at 14:35
  • 1
    Now move it to NSData extension and call it `hexadecimalStringDescription()` – Eimantas Nov 13 '15 at 09:09
5

I found this solution better as iOS can change the usage of description in future versions, so using description property on data can be unreliable in future. We can directly use this by creating hex Token from the data token bytes.

 - (void)application:(UIApplication *)app 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];

}

We can also store the device token in our NSUserdefaults and use it later to send it out to our server.

megha
  • 473
  • 5
  • 18
2

I don't think it's a good solution, as you have to reconstruct the string before sending the notifications to Apple servers. Use Base64 encoding for transmitting the strings or something similar.

  • Sent string works from server side without any reconstructions or modifications – Mladen Oct 19 '09 at 09:31
  • But as far as I see, you are removing and trimming characters ... Did you try sending notification by using that token and it worked? How come? – M. Broncano Oct 19 '09 at 09:51
0

Another way of converting device token into hexa decimal string

NSUInteger capacity = [deviceToken length] * 2;
NSMutableString *stringBuffer = [NSMutableString stringWithCapacity:capacity];
const unsigned char *dataBuffer = [deviceToken bytes];
NSInteger i;
for (i=0; i<[deviceToken length]; ++i) {
    [stringBuffer appendFormat:@"%02X", (NSUInteger)dataBuffer[i]];
}
NSLog(@"token string buffer is %@",stringBuffer);
aparna
  • 353
  • 2
  • 3
  • 13
0

For Swift 3 :

var tokenString: String = ""
    for i in 0..<deviceToken.count {
        tokenString += String(format: "%02.2hhx", deviceToken[i] as CVarArg)
    }

    print(tokenString)

Other Method

Create Data extension for getting hexstring

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

And call this extension in

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let tokenString = deviceToken.hexString()
    print("token: \(tokenString)")
}
Andrei Konstantinov
  • 6,971
  • 4
  • 41
  • 57
Adarsh G J
  • 2,684
  • 1
  • 24
  • 25
  • Don't rely on .description, the format you get from that is undocumented and could technically change. deviceToken.description should only be used for debugging purposes. Use one of the answers that converts the bytes to a hex string instead. – Michael Peterson May 25 '16 at 03:33
  • 2
    agreed. Dont use this. When using PKPushCredentials, description now returns "32 bytes" – Tony Oct 03 '16 at 19:06