I am developing an android application that targets Android 4.0 (API 14) and above.
I am looking for a serial number that is unique per device and that persists for ever (dies with the device, does not change after factory resets).
I have found lots of results on the web concerning unique identifiers for android devices, but very little on the android.os.Build.SERIAL number.
So far, I eliminated the use of the ANDROID_ID because it might change after factory resets. I also eliminated the use of the IMEI because the android device might be non-phone. I cannot use the wifi or bluetooth MAC ADDRESS because the device might not have such hardware and/or such mac addresses might not be readable if the hardware is not enabled (based on what I found on the web).
I believe I might go for the android device serial number.
It is easily accessible using android.os.Build.SERIAL (since it is added in API level 9 and does not need any additional permission).
My questions are :
Taking into consideration that my application targets Android 4.0 (API 14) and above, is the android.os.Build.SERIAL number for the android devices unique for each device ?
Currently, documentation of android.os.Build.SERIAL indicates : A hardware serial number, if available. Alphanumeric only, case-insensitive.
Does this mean that the serial number might not be available ?
What could be another alternative that meets the conditions mentioned above ?
Taking into consideration that my application targets Android 4.0 (API 14) and above, is the android.os.Build.SERIAL number for the android devices unique for each device ?
According to this useful article in the Android Developers blog, android.os.Build.SERIAL should be unique if it is available.
From the article:
Devices without telephony are required to report a unique device ID here; some phones may do so also.
Does this mean that the serial number might not be available ?
Correct, it may not be available. Notice that they say "Devices without telephony are required...", so only devices without "telephony" (like wifi only tablets) are required to supply a SERIAL number, although some phones still do (like the Nexus 4).
Documentation is definitely lacking on this topic, but from the wording it's possible that only "devices without telephony" are required to submit a unique ID, while phones that do submit one might not be unique.
What could be another alternative that meets the conditions mentioned above ?
For your situation I think your best bet is to first check for a deviceId (IMEI, or what not) and if deviceId doesn't exist then you fallback to using android.os.Build.SERIAL (since this is probably a tablet) like so:
public static String getDeviceId(Context context) {
final String deviceId = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
if (deviceId != null) {
return deviceId;
} else {
return android.os.Build.SERIAL;
}
}
Keep in mind to use deviceId you need the permission android.permission.READ_PHONE_STATE.
So since your app's minSDK is 14, you can safely use the field android.os.Build.SERIAL. And if we assume that devices without telephony truly do always provide unique ids in SERIAL then I think this would be a safe bet on always getting a unique device id (bar any bugs of course).
I personally use Secure.ANDROID_ID & Build.SERIAL to identify a phone:
androidId = Settings.Secure.getString(this.getContentResolver(),
Settings.Secure.ANDROID_ID) + Build.SERIAL;
They may have the same ANDROID_ID, they may not have a SERIAL. But the chance of both is low.
You appear to have summarized the situation pretty well.
The serial number is intended to be unique for each device, but (this being Android) there are of course bugs that create exceptions, e.g.
https://code.google.com/p/android/issues/detail?id=35193
As you point out, the docs suggest that this is intended to be a hardware serial number, but the way it is worded suggests that you shouldn't count on that. And don't mistake that for the device's actual serial number, i.e. the serial number printed on the back or on the box. As well, I believe it is much less widely used than android_id, so there could well be issues that are not reported.
I've seen it widely reported that the android_id is based on the serial number, but I believe that is not true - I recently observed that, on a tablet with the new multi-user capability, each user account gets its own android_id but the serial number is the same for both.
AFAIK 'another alternative' does not exist: your list is complete. The serial number is the closest thing to what you are after unless you are prepared to depend on wifi or bluetooth permissions.
I usually get unique id's by doing an SHA1 hash of some unique string (company name usually) + imei (if no imei, mac address [wifi, bluetooth, etc]). This gives me unique id's that look the same, tend to be unique per device (not perfect if the MAC is changed/faked though).
Related
Objective:
I am looking for a way to find out a unique_id for android device.
Background:
I will use the Id in login request payload and as my app is license based service app the Id should not change under normal circumstances.
Existing Approaches:
In iOS there are some unique id solutions for iOS such as CFUUID or identifierForVendor coupled with Keychain,Advertising Identifier etc.. that can do this job upto the expectation.
But in Android all the options that I know seems to have hole in it.
IMEI:
TelephonyManager TelephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String m_deviceId = TelephonyMgr.getDeviceId();
Drawbacks
It is sim card dependent so
If there is no sim card then we're doomed
If there is dual sim then we're dommed
Android_ID:
String m_androidId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Drawbacks
If OS version is upgraded then it may change
If device is rooted it gets changed
No guarantee that the device_id is unique there are some reports some manufacturers are having duplicate device_id
The WLAN MAC Address
WifiManager m_wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
String m_wlanMacAdd = m_wm.getConnectionInfo().getMacAddress();
Drawbacks
If there is no wifi hardware then we're doomed
In some new devices If wifi is off then we're doomed.
Bluetooth Address:
BluetoothAdapter m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_bluetoothAdd = m_BluetoothAdapter.getAddress();
Drawbacks:
if there is no bluetooth hardware we're doomed.
In future in some new devices we mightn't able to read it if its off.
Possible solutions:
There are two approaches that I think to solve this problem
We generate a random id by hashing timestamp with unique ids that I have mentioned and store it so next time during login we’ll check if the the stored value of key is null if its so then we’ll generate and store it else we’ll use the value of the key.
If there is something equivalent to keychain of iOS then we’re good with this approach.
Find a global identifier something like advertisingIdentifier of iOS which is same for all the apps in the device.
Any help is appreciated !
I have chosen to use Android_ID since It's not dependent on any hardware.
Build.SERIAL also dependent on availability of telephony that is in wifi only devices this Build.SERIAL won't work.
I have explained how other approaches are dependent upon the hardware availability in the question itself.
There is no such ID available on Android. You can generate your own, for example a random UUID and connect it to the user's account. This is what Kindle, Audible and other applications do to identify devices in a non-privacy-intrusive way.
Consider Google Analytics Mobile if you want to "track your users", http://www.google.com/analytics/mobile/
If you want to get closer to tracking a device you can combine the IDs above together in a hash-function. Bluetooth + wifi + android serial, and if any of them are null, you put a 0 in the hash, e.g. if there is no wifi mac addr. As you point out, you aren't guaranteed the id won't change. Unless the user is running a custom ROM, I would expect this computed ID to stay constant, though.
I think, you could use device serial ID (hardware serial number, not android id). You could seen it in device settings. In your code, you could get it by Build.SERIAL.
I know, that android.Build.SERIAL is generated at first device boot, but I can't locate where and when exactly. I'm building AOSP Jelly Bean, Android tablet, nosdcard.
2nd question: is this serial number really unique for all Android devices?
According to this thread, it clearly says that it's unique, but added since API 9 and may be not present on all devices.
If you're writing your app for a specific device's model, you could direclty check if it has an IMEI. Otherwise, as you said, I recommend you to write a custom ID generator module. You will be sure that your ID will be unique and available for all devices.
IMEI represents the serial number of the device. It's sure it's unique. Two different devices can't have the same serial number.
To get the serial number of the device you just have to call :
String serial = Build.SERIAL;
It exists another approach. You can get the id by calling Secure.ANDROID_ID.
A 64-bit number (as a hex string) that is randomly generated on the
device's first boot and should remain constant for the lifetime of the
device. (The value may change if a factory reset is performed on the
device.)
private final String ANDROID_ID = Secure.getString(getContext().getContentResolver(),
Secure.ANDROID_ID);
Take care because it says that the value MAY change if a factory reset is performed.
I would like to use a unique id for android device that works for phone and Tablet.
(IMEI doesn't work with no SIM card device and sometime MAC Address return null)
I'm not sure is android.os.Build.SERIAL unique or not.
Does anyone know about this?
Thanks,
Regards.
Yes, but note that it was only added in API level 9, and it may not be present on all devices. To get a unique ID on earlier platforms, you'll need to read something like the MAC address or IMEI.
Generally, try reading all the possible IDs, and use whichever are available. See this article for guidance.
You can use Build serial and android ID to make your own unique id.
String serial = Build.SERIAL;
String android_id =Secure.getString(context.getContentResolver(),
Secure.ANDROID_ID);
String myKey=serial +android_id ;
Serial was only exposed in API:9. but you can get it in older versions using reflection. However the docs mention "if available" so I guess don't rely on it.
String deviceSerial = (String) Build.class.getField("SERIAL").get(
null);
I think for unique Id you should used android Id.
following is code to get Android Id.
String android_id = Secure.getString(this.getContentResolver(),
Secure.ANDROID_ID);
Log.d("Android","Android ID : "+android_id);
If it is there, then it is expected to be unique. But there is no guarantee that this property is set. Also it is API 9. Unfortunately there's no easy way to uniquely identify the device. Some properties like said SERIAL can be present, others like ANDROID_ID as NOT unique, some other like MAC depends on presence of WIFI or its state (if wifi module is off, the you may not be able to read its MAC). Some like IMEI cannot be read even device got phone module. So the best approach is to gather as much data as you can, and try to build something you could most likely consider unique device ID
What about a combination of MAC, IMEI and SERIAL ?
You just have to deal with the fact that they all could be non existant esp. on older phones without SIM.
I just find it odd that MAC would return null. This should not be possible imho, as it makes no sense that a mobile device has no MAC.
There are 2 MAC addresses possible but they can be non accessible in some cases.
Right now my algorithm based only on IMEI. And here is the problem: some devices doesn't have radio module, so they also doesn't have IMEI
I need unique parameters ( CPU ID, flash ID, MAC etc) to generate ID without using IMEI.
And how to get them with Java. Preferably without Root
Thank you
Use Build.SERIAL to get the unique serial number of an android device. This will return a string value. In emulator this code may return the string "unknown". But try it with a device. It really works... :)
String id=Build.SERIAL;
ANDROID_ID
More specifically, Settings.Secure.ANDROID_ID. This is a 64-bit quantity that is generated and stored when the device first boots. It is reset when the device is wiped.
ANDROID_ID seems a good choice for a unique device identifier. There are downsides: First, it is not 100% reliable on releases of Android prior to 2.2 (“Froyo”). Also, there has been at least one widely-observed bug in a popular handset from a major manufacturer, where every instance has the same ANDROID_ID.
This could help you
You may use android.os.Build.getSerial() instead of android.os.Build.SERIAL
android.os.Build.SERIAL --> This field was deprecated in API level O. Use getSerial() instead.
Source:
https://developer.android.com/reference/android/os/Build.html
You can use the Setting.secure which is inbuilt to get the device id. this device ID is fixed till you reset the factory setting.
Settings.Secure.getString(getContentResolver(),Settings.Secure.ANDROID_ID);
This is the unique Id of your device which is stable till you reset to the factory setting.
below code can help you to get your device id
String ts = Context.TELEPHONY_SERVICE;
TelephonyManager mTelephonyMgr = (TelephonyManager) getSystemService(ts);
String imsi = mTelephonyMgr.getSubscriberId();
String imei = mTelephonyMgr.getDeviceId();
I'm implementing an way to unique identify the device.
The architect send me the following specs:
devices with Wifi + 3G: IMEI Code
devices Wifi only - MacAddress
Both needs also the Manufacturer + Model for complete the id.
My questions are:
How do I get the IMEI from the device?
How can I get the Manufacturer and Model from the device? (I see theres some constants on Build class for it, but don't know where to use them)
Theres devices with 3G only?
How can I know if the device is wifi only, wifi+3g or 3g only if exists?
Also, suggestions for unique identifiers are available.
PS: I'm already able to get the MacAddres through WifiManager.
You can use the TelephonyManager getDeviceID method. This should return IMEI or MEID. For build information you can see android.os.Build and android.os.Build.VERSION. Also, if its about uniquely identifying your application installs, you may want to go through (and/or show your architect) the developer blog post on Identifying App Installations
How to get IMEI can be found in this question: How to get the device's IMEI/ESN programmatically in android?;
MANUFACTURER and MODEL can be retrieved from android.os.BUILD class.
Theoretically, yes, there might be devices without Wi-Fi but with 3G. But I haven't seen any.
If getSystemService(WIFI_SERVICE) returns null, then there is no Wi-Fi.
android.telephony.TelephonyManager.getDeviceId() gets you 'the IMEI for GSM and the MEID or ESN for CDMA phones'.
Build.MODEL is a static field, so you can just use it like that, so long as you've imported android.os.Build first.
Quite possibly.
You could try calling Context.getSystemService(Context.WIFI_SERVICE) and seeing if it's null, although I suppose it's possible that the service might still exist even if there's no wifi (in such a case, I would expect checking the wifi to return DISABLED.)
These questions have plagued Android developers for a while, see Is there a unique Android device ID?
The Android development team has tried to address these concerns directly in their blog here: http://android-developers.blogspot.com/2011/03/identifying-app-installations.html
In answer to your last question: just test for null when querying for SIM/MAC/Whatever and then act accordingly. It's been reported that there are cases where MAC will return null; see my first link.