Corrado's Blog 2.0

Online thoughts of a technology funatic

Behaviors for Xamarin Forms v2.0

I’ve pushed version 2.0 of my behavior implementation for Xamarin Forms and moved it to a new location on GitHub: https://github.com/corradocavalli/Corcav.Behaviors

The reason for this is that, in order to prevent conflict with Xamarin API I’ve renamed the root namespace so upgrading to this version will break your code and I’m really sorry for this, but I’m sure it won’t take too long to fix it.

I’ve also removed old nuget package and replaced with this one : ’https://www.nuget.org/packages/Corcav.Behaviors/

Version 2.0 uses Xamarin Forms 1.3.4 and Unified API project as iOS demo.

Sorry for breaking your code, my fault using Xamarin as assembly name Sad smile (lesson learned), honestly didn’t expect such success, and I thank you for that.

Get device unique identifier in Xamarin Forms

Last week I introduced some ISV to the wonderful world of Xamarin and while discussing Xamarin Forms a few of them asked how to get an identifier that uniquely identifies a device.

I had the same issue in the past with a Windows Phone application so I know how retrieve it on this platform and I remember speaking with the guy that was working on the same app for iOS that he told me that Apple changed the policy so the API that was used in the past was no longer available and he had to find a workaround, more on this later.

The answer to the original question is quite easy from the architectural side: Just use a Dependency Service and you’re done, here are the steps:

Let’s create a IDevice interface in the common/shared project and let’s add a GetIdentifier method

public interface IDevice
 {
  string GetIdentifier();  
 }

Once done you can easily get device unique identifier within shared code using this snippet:

IDevice device = DependencyService.Get<IDevice>();
string deviceIdentifier = device.GetIdentifier();

Let’s now implement device specific code, starting from Windows Phone, add this class to Windows Phone project and add ID_CAP_IDENTITY_DEVICE capability.

[assembly: Xamarin.Forms.Dependency(typeof(WinPhoneDevice))]
namespace XFUniqueIdentifier.WinPhone
{
 public class WinPhoneDevice : IDevice
 {
  public string GetIdentifier()
  {
   byte[] myDeviceId = (byte[])Microsoft.Phone.Info.DeviceExtendedProperties.GetValue("DeviceUniqueId");
   return Convert.ToBase64String(myDeviceId);
  }
 }
}

Now add following class to Android project:

[assembly: Xamarin.Forms.Dependency(typeof(AndroidDevice))]
namespace XFUniqueIdentifier.Droid
{
 public class AndroidDevice : IDevice
 {
  public string GetIdentifier()
  {
   return Settings.Secure.GetString(Forms.Context.ContentResolver, Settings.Secure.AndroidId);
  }
 }
}

And now the hardest part: iOS developer used to get device identifier using Device UniqueIdentifier api but this has deprecated by Apple so an alternative has to be found.

After some investigations (also considered generating unique id at startup but this would fail if app is reinstalled) I found this post on Xamarin forums so kudos goes to the original author.

It’s now time to add a new class to iOS project with following code:

[assembly: Xamarin.Forms.Dependency(typeof(IOSDevice))]
namespace XFUniqueIdentifier.iOS
{
 using System.IO;
 using System.Runtime.InteropServices;

 public class IOSDevice : IDevice
 {
  [DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
  private static extern uint IOServiceGetMatchingService(uint masterPort, IntPtr matching);

  [DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
  private static extern IntPtr IOServiceMatching(string s);

  [DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
  private static extern IntPtr IORegistryEntryCreateCFProperty(uint entry, IntPtr key, IntPtr allocator, uint options);

  [DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
  private static extern int IOObjectRelease(uint o);

  public string GetIdentifier()
  {
   string serial = string.Empty;
   uint platformExpert = IOServiceGetMatchingService(0, IOServiceMatching("IOPlatformExpertDevice"));
   if (platformExpert != 0)
   {
    NSString key = (NSString) "IOPlatformSerialNumber";
    IntPtr serialNumber = IORegistryEntryCreateCFProperty(platformExpert, key.Handle, IntPtr.Zero, 0);
    if (serialNumber != IntPtr.Zero)
    {
     serial = NSString.FromHandle(serialNumber);
    }

    IOObjectRelease(platformExpert);
   }

   return serial;
  }  
}

And you’re done, have fun and make a good use of device unique id. Smile