Correctly capture iOS 13 Device Token in Xamarin

Cross posted on dev.to

Capturing the Device Tokens is necessary for push notification to work. A Device Token is nothing but an ID that uniquely identifies a combination of a device and an app. So if we have 2 apps running on the same device, they will have different Device Tokens. Likewise, if the same app runs on 2 different devices, they will also have different Device Tokens. This is obvious because Apple Push Notification service (APNs) must know where to correctly push the notifications to.

To receive the Device Token, an app must register with APNs. I copied the following code from honestly-I-do-not-remember-where and paste in the AppDelegate class:

It worked great. I never bothered to question why or how.

Then comes trouble. iOS 13 arrived. Customers who updated their devices to iOS 13 no longer receive push notifications.

My boss informed me. Then I found this post on App forum and from NSHipster. It then makes all senses to me because the following line is returned by the toString() method in Xamarin C# NSData (equivalently, in Swift, that’s the description field of the native Objective-C/ Swift NSData structure):

<124686a5 556a72ca d808f572 00c323b9 3eff9285 92445590 3225757d b83997ba>

So after we call Replace with the regex pattern[^0-9a-zA-Z] as in line

DeviceToken = Regex.Replace(deviceToken.ToString(), "[^0-9a-zA-Z]+", "");

We end up with the Device Token (if you count, that’s 32 bytes)

124686a5556a72cad808f57200c323b93eff9285924455903225757db83997ba

The trouble is: in iOS 13, the description field of the NSData structure now contains something like

{length = 32, bytes = 0xd3d997af 967d1f43 b405374a 13394d2f 28f10282 14af515f }

Important: The elliptic (…) in the line above is NOT from my abbreviation. It is the ACTUAL string returned by APNs.

So obviously if we call Replace with the regex pattern[^0-9a-zA-Z] as above, we end up with a wrong Device Token:

length32bytes0xd3d997af967d1f43b405374a13394d2f28f1028214af515f

It got the junk length32bytes0x in the beginning, and it’s no longer 32 bytes in length.

The NSHipster article shows the fix in Swift:

A nice one-line in Swift. We can do equally well in C#:

Now let’s break this down:

  1. First we have to grab all the bytes in the device token by calling the ToArray() method on it.
  2. Once we have the bytes which is an array of bytes or,byte[], we call the LINQ Select which applies an inner function that takes each byte and returns a zero-padded 2 digit Hex string. C# can do this nicely using the format specifier x2. The LINQ Select function returns an IEnumerable<string>, so it’s easy to call ToArray() to get an array of string orstring[].
  3. Now just call Join() method on an array of string and we end up with a concatenated string.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store