![]() |
Source: Device ID |
Despite the fact that I couldn't write anything in the last couple of months due to heavy workload with asshole of teams I decided to write again since I have faced pretty interesting issues over the months. One of that is a Salesforce related issue in Android (Another pretty good story that i'm not suppose to tell *wink*) where I have to come up with a solution which doesn't impact the live version, and during the approach I had to come up with a way where I have to create a unique identifier to identify each device. So in here I'll briefly explain the things I found during that journey.
What are our options?
If we ask this from most of the developers they might reply saying that we can use Android ID (AKA Android Hardware ID) for this and that's fine, I thought the same thing in the very beginning but I was wrong. So in here I'll explain what are our options, What is the key, what are the pros and cons (The usual shit in most of my posts) and how we can implement them. (If it is recommended to implement) So here are the list of options that I found,
- Secure Android ID (Android Hardware ID)
- Unique Telephony Number (IMEI, MEID, ESN, IMSI)
- MAC Address
- GUID
- Pseudo Unique ID
So let's take one by one...
Secure Android ID (Android Hardware ID)
This is a 64-bit number that randomly generated and stored in the very initial boot up of the device and which is available almost in every device. People say it is reliable on Android versions ≤ 2.1 and ≥ 2.3. So seems this is a good option right? NO! you're wrong, this value might change in a factory reset of the device and there's a known bug in one of the handset where it returns the same value for every model. So this is not 100% reliable. And according to the latest Android documentation they have mentioned to NOT to use Android ID (SSAID) as a identifier. But if you're still interested you can get the android ID as follows,
Unique Telephony Number (IMEI, MEID, ESN, IMSI)
If you’re targeting devices with telephony services (not WiFi only devices) this can be a solution for you. You just have to execute the code and BAM! You got the unique ID and it can be IMEI, EMID, ESN or IMSI. So for those who don't know what are those,
- IMEI (International Mobile Equipment Identity) - The unique number which identifies the GSM, WCDMA mobile phones and some satellite phones
- MEID (Mobile Equipment IDentifier) - a globally unique number identifying a physical piece of mobile station equipment. This is the replacement of ESN
- ESN (Electronic Serial Number) - the unique number to identify CDMA mobile phones
- IMSI (International Mobile Subscriber Identity) - The unique ID which comes with all the GSM and UMTS network mobile phone users.
So this unique ID survives even in a factory reset, But the only issue is justifying the permission android.permission.READ_PHONE_STATE which requires for getting the unique ID. As you can see it gives a permission dialog which scares the shit out of the user so we have to justify the use of the permission in order to user to accept it.
And then again we might have to plan an alternative route if in case user denies the permission dialog which end up giving a null as the unique ID. (You can always create a wizard and tell user to enter it or to accept the permission to proceed) And if you have planned all scenarios perfectly here’s the code for generating the IMEI or the device specific unique ID.
MAC Address
MAC Address
I’m pretty sure everyone knows that MAC or Media Access Control address is a unique identifier assigned to network interface controllers and we can get MAC addresses from the WiFi and as well as from Bluetooth but make sure that you don’t use this anymore and here’s why,
1- If you’re retrieving WiFi’s MAC make sure that user’s WiFi is turned on, otherwise this won’t give the MAC
2- In Android v6.0 MarshMallow: they have removed programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs. So now those methods return a constant value of 02:00:00:00:00:00 for every device
GUID
GUID (globally unique ID) in google UUID (universally unique identifier) in Apple *wink*, basically the same concept but different names, If you have developed/developing iOS you know that this is what we get when we need to get a unique ID from iOS. (And we store this in keychain) This is also known as instance ID since this is recommended to use to identify a particular installation (particular instance) but NOT a physical device. (Because we can't replicate the behavior of a keychain in Android with the file managers)
Pseudo Unique ID
Then comes this fella, IMO this is the best way to identify a physical device. (At least in my situation where my target audience is api >= 15) Basically we get use of Android’s Build class and get unique details related to that particular device and create a GUID with the hash code of the entire string that we generated. But keep that in mind that there’s a slight possibility that we might get the same ID for 2 devices where it returns the exact same information for the multiple devices. But once an Android developer of Facebook told me,
Since in here we have append more stuff into it which makes it even harder for a bug to give the same ID for more than 1 device. You’ll get a more clearer idea once you look into the code below.
And I have found out that lot of developers saying that serial might change in an OS update and I was wondering how the hell would that happen since serial is a hardware ID and how does that get impacted from a software update. And after days of researching I found out the below line of code in a CyanogenMod custom ROM which gives some sense to me.
So according to that yes, it can get changed by a OS update. (Only by a custom ROM which defines the extraction of the serial) But not because of the change in the device serial but from the way it assigning as a variable. (In a situation where ROM developer decided to change the variable)
Finally, I have seen in the documentation under "Resettability and persistence" that they have mentioned about FDR-persistent which will survive a factory reset as well but unfortunately I couldn't figure out how to implement that. So if you do please let me know as well because that'll solve everything...
And I have found out that lot of developers saying that serial might change in an OS update and I was wondering how the hell would that happen since serial is a hardware ID and how does that get impacted from a software update. And after days of researching I found out the below line of code in a CyanogenMod custom ROM which gives some sense to me.
57| sprintf(buf, "ro.serialno=%s", serial);
Conclusion
So to sum up there's no perfect solution in Android to get a unique ID. And the use of unique ID will change depends on the requirement, so before you lock an approach I suggest that you do your POCs, researches well because let's face it, bug related to this won't be pretty.Finally, I have seen in the documentation under "Resettability and persistence" that they have mentioned about FDR-persistent which will survive a factory reset as well but unfortunately I couldn't figure out how to implement that. So if you do please let me know as well because that'll solve everything...
This doesn't work for the "Pseudo Unique ID" stated as the best solution.
ReplyDeleteIf you have 2 identical phones, you get the same string (result of new UUID(generatedID.hashCode(), serial.hashCode()).toString();)
All properties of the Build class in your example return the exact same value on 2 identical phones.
Have you tested this? Because I have and it worked for identical devices for me.
Delete"If you have 2 identical phones, you get the same string" > your are right! Unfortunately it doesn't work for identical hardware.
ReplyDeleteWe are still looking for a workable solution, but...