Getting unique device ID

Hi all,

Just having a little tinker with xamarin and loving it. I was wondering, what is considered the best way to get a unique device ID which will be consistent across Android + iOS and which return same result even if device has it's firmware flashed etc. I was thinking the IMEI would do but that doesn't' seem possible for iOS anymore? I'd even need something that runs on iPod/iPad etc so guess IMEI not best option anwyay. A mix of MAC address perhaps? Is there a best-practice way of doing this which will be consistent?

Many thanks

Posts

  • CarlJonesCarlJones GBMember ✭✭

    Thanks for that, I'll take a look, I was toying with generating a unique ID based on mac address, storing that server-side and then when they load the up I'll be able to check if they're running from same device based on if it's already got the mac perhaps. Perhaps I'm just over-complicating matters and should just stick to your advice and store it in the security record, need to find a way of doing that with android though.

    Thank you

  • ahmedkhan25ahmedkhan25 USMember

    You can try open udid project as well: https://github.com/ylechelle/OpenUDID#readme

  • NicWiseNicWise NZMember, Insider, Beta mod

    @_belial what happens if the user gets a new device?

    eg, I can walk into an apple store with a somewhat broken device, and walk out with a new one.

    Is that something you need to deal with?

  • LuisValdezLuisValdez USMember

    @_belial... Here's a possible solution.

    var telephonyDeviceID = string.Empty;
    var telephonySIMSerialNumber = string.Empty;
    TelephonyManager telephonyManager = (TelephonyManager)activity.ApplicationContext.GetSystemService(Context.TelephonyService);
    if (telephonyManager != null)
    {
      if(!string.IsNullOrEmpty(telephonyManager.DeviceId))
        telephonyDeviceID = telephonyManager.DeviceId;
      if(!string.IsNullOrEmpty(telephonyManager.SimSerialNumber))
        telephonySIMSerialNumber = telephonyManager.SimSerialNumber;
    }
    var androidID = Android.Provider.Settings.Secure.GetString(activity.ApplicationContext.ContentResolver, Android.Provider.Settings.Secure.AndroidId);
    var deviceUuid = new UUID(androidID.GetHashCode(), ((long)telephonyDeviceID.GetHashCode() << 32) | telephonySIMSerialNumber.GetHashCode());
    var deviceID = deviceUuid.ToString();
    

    Work for me... for now... :D

  • CheesebaronCheesebaron DKInsider, University mod

    I use this for my MvvmCross applications: https://github.com/Cheesebaron/Cheesebaron.MvxPlugins/tree/master/AppId

    It contains methods to obtain a device ID for Android, iOS and WindowsPhone. However, Android in some cases produces a non-unique device ID. Hence simply generating a Guid is much safer and unique.

  • ignaciomachinignaciomachin USMember ✭✭

    Hi,

    In iOS the UniqueIdentifier cannot be used anymore, your app will be rejected.
    If you are pre 7.0 you could use the MAC address, unfortunately that does not work anymore in 7.0

    You should be using UIDevice.IdentifierForVendor , this is a unique ID per developer per device.
    Take a look at Apple doc if you need more details.

  • LuigiSaggeseLuigiSaggese ITDeveloper Group Leader ✭✭

    @Cheesebaron could you provide an example of AppIdGenerator use?

  • CheesebaronCheesebaron DKInsider, University mod

    Just call the method and store the result. There isn't much to it.

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    @Cheesebaron, I looked at your code for the AppId plugin and I like it. But I do have a question. What are the purposes for the Prefix, Suffix, and PhoneID when they are appended to create the final AppId? It seems a GUID would be unique enough. Does the extra info buy you anything?

    Thanks!

  • CheesebaronCheesebaron DKInsider, University mod

    They are there for a custom use case I have where I want to know the type of phone on the web service side, which I use those for. They are there just to allow for some flexibility. You are right though, GUID is enough for most cases.

  • KanthKanth INMember ✭✭

    @mrskensington Thanks for code it's really very helpful ,I only have one question for you ,Do Apple accepts if I implement the same in my app?

  • mrskensingtonmrskensington USMember, Beta ✭✭

    @Kanth said:
    @mrskensington Thanks for code it's really very helpful ,I only have one question for you ,Do Apple accepts if I implement the same in my app?

    We've had a number of applications pass through Apple's AppStore review process that contain this code with no issues raised (at least nothing to do with this code :tongue:)

  • DAVIDBUCKLEYDAVIDBUCKLEY GBMember

    One question I have I am using touch id so i no i have it stored in my keychain but what is my best way to link it to my users data. Their I am a bit lost like.

  • BengiBesceliBengiBesceli USMember ✭✭

    What is the using library of TelephonyManager ?

  • KanthKanth INMember ✭✭

    @mrskensington Recently my app review failed in the Apple store and when I check it in the Debug mode I got the SecKeyChain.Add -34018 error when I try to add the key to SecKeyChain. Can you please suggest any solution or reason behind the error.

  • IPSIPS USMember

    Mobile IME Number Read a Variable Xamarin Forms Pls Help
    Me

  • yanivmaymonyanivmaymon ILMember

    this worked for me

    Android.Telephony.TelephonyManager manager = (Android.Telephony.TelephonyManager)this.ApplicationContext.GetSystemService(Context.TelephonyService);
    string deviceIde = manager.DeviceId;

  • rio_riyario_riya INMember ✭✭

    @mrskensington said:
    What I've done with iOS devices is generate a GUID and store it as a password security record against my application. Something like...

    public override string UniqueID {
    get {
    var query = new SecRecord(SecKind.GenericPassword);
    query.Service = NSBundle.MainBundle.BundleIdentifier;
    query.Account = "UniqueID";

    NSData uniqueId = SecKeyChain.QueryAsData(query);
    if(uniqueId == null) {
    query.ValueData = NSData.FromString(System.Guid.NewGuid().ToString());
    var err = SecKeyChain.Add (query);
    if (err != SecStatusCode.Success && err != SecStatusCode.DuplicateItem)
    throw new Exception("Cannot store Unique ID");

    return query.ValueData.ToString();
    }
    else {
    return uniqueId.ToString();
    }
    }
    }

    From what I've read this will stay even if the user uninstall's your application and re-installs it. Obviously if they factory reset the device it'll be gone.

    Unfortunately I haven't implemented the android version yet so I can't provide you code for that. But I'm sure something similar is possible.

    Wow, thanks for the code bro. It helps me.

  • SrikanthNuvvulaSrikanthNuvvula USMember ✭✭

    Hi @mrskensington,
    I've used the above code but sometimes i am getting the exception "Cannot store Unique ID". Can you tell me how to overcome it and what scenarios it would come

  • RobinSchroeder.8683RobinSchroeder.8683 USMember ✭✭
    edited January 2018

    @mrskensington said:
    What I've done with iOS devices is generate a GUID and store it as a password security record against my application. Something like...

    public override string UniqueID {
    get {
    var query = new SecRecord(SecKind.GenericPassword);
    query.Service = NSBundle.MainBundle.BundleIdentifier;
    query.Account = "UniqueID";

    NSData uniqueId = SecKeyChain.QueryAsData(query);
    if(uniqueId == null) {
    query.ValueData = NSData.FromString(System.Guid.NewGuid().ToString());
    var err = SecKeyChain.Add (query);
    if (err != SecStatusCode.Success && err != SecStatusCode.DuplicateItem)
    throw new Exception("Cannot store Unique ID");

    return query.ValueData.ToString();
    }
    else {
    return uniqueId.ToString();
    }
    }
    }

    From what I've read this will stay even if the user uninstall's your application and re-installs it. Obviously if they factory reset the device it'll be gone.

    This has worked really well for me for a month or two, through updates, but just recently failed.
    After reading this about SecRecord()...

        //     When you create a SecRecord you need to specify the kind of record that you will
        //     be matching using one of the SecKind values, and you must set also:
        //     One or more attributes to match (AccessGroup, Accessible, Account, ApplicationLabel,
        //     ApplicationTag, AuthenticationType, CanDecrypt, CanDerive, CanEncrypt, CanSign,
        //     CanUnwrap, CanVerify, CanWrap, CertificateEncoding, CertificateType, Comment,
        //     CreationDate, Creator, CreatorType, Description, EffectiveKeySize, Generic, Invisible,
        //     IsNegative, IsPermanent, Issuer, KeyClass, KeySizeInBits, KeyType, Label, ModificationDate,
        //     Path, Port, Protocol, PublicKeyHash, SecurityDomain, SerialNumber, Server, Service,
        //     Subject, SubjectKeyID) Optional search attributes, used to determine how the
        //     search is performed. You do this by setting any of the Match properties in the
        //     class (MatchCaseInsensitive, MatchEmailAddressIfPresent, MatchIssuers, MatchItemList,
        //     MatchPolicy, MatchSubjectContains, MatchTrustedOnly, MatchValidOnDate)
        //     Once the class is constructed, you can pass this to the Query, Add, Remove or
        //     Update methods on the SecKeyChain class.
        //     Internally this is setting the kSecClass key to one of the kSec* values as specifed
        //     by the SecKind. On MacOS X the only supported value is InternetPassword, while
        //     iOS offers a wider range of options.
    

    I am wondering if it should be:

    public override string UniqueID {
            get {
                    var query = new SecRecord(SecKind.GenericPassword);
                  query.IsPermanent = true;  //ADD THIS
                    query.Service = NSBundle.MainBundle.BundleIdentifier;
                    query.Account = "UniqueID";
    

    Thoughts?

  • RonaldPetersRonaldPeters USMember
    edited March 2018

    @RobinSchroeder.8683
    I think the problem is that iOS no longer saves keychain items across app uninstalls. I would post the link, but this system is not letting me do it. Go to forums dot developer dot apple dot com and go to thread 72271

  • SreeeeSreeee INMember ✭✭✭✭✭

    For android the below solution worked for me:

    In PCL create an interface IDevice

    IDevice.cs
    
    namespace projectname
    {
        public interface IDevice
        {
           string GetIdentifier();
        }
    }   
    

    In android project create a class AndroidDevice
    AndroidDevice.cs

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

    Capture the unique id of a device in PCL using the following code, where deviceIdentifier is the unique id.

    IDevice device = DependencyService.Get<IDevice>();
        string deviceIdentifier = "";
        if (device != null)
        {
           deviceIdentifier = device.GetIdentifier();
         }
         Debug.WriteLine("deviceIdentifier:>>" + deviceIdentifier);
    

    I found this solution from here. Also please refer the StackOverflow thread related to this.

    Ios part is not working as per the blog. But @mrskensington answer working for me in ios part.

Sign In or Register to comment.