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.
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'm currently working on an application where the code uses the device IMEI number as a variable to store something in the DB. We need to see what device the reading originated from.
ie:
String IMEI = telephonyManager.getDeviceId();
However, I'm not sure how this will behave on phones without network access, such as a wifi only tablet. Will is return a unique value? Will it return null?
I know there are alternatives to using IMEI, and I don't need any explanation on what alternative values I can use. I only need to know what will happen when I call this on a phone with no network access. Please do not provide suggestions on alternative IDs or anything other than what I have asked. I appreciate you taking the time to read this question.
Thanks,
-Mark
You get null.
Just ran into this on an app I wrote 3 years ago, and only just converted to tablet format. I had forgotten we were using IMEI (against the advice you and I both received ;-) ) and we started sending a whole bunch of null device IDs to the server.
Sadly it took a whole lot of network logs before I tracked it down to that little hack.
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).
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.
Android provides the following method to determine the network operator:
http://developer.android.com/reference/android/telephony/TelephonyManager.html#getNetworkOperatorName()
However even the documentation specifically says:
Returns the alphabetic name of current registered operator.
Availability: Only when user is registered to a network. Result may be unreliable on CDMA networks (use getPhoneType() to determine if on a CDMA network).
The problem is that we need a reliable way to detect the carrier so we can identify the traffic source. Has anyone had a similar problem and if so, what is the best solution?
My phone is on Verizon Wireless. On a daily basis, I drive through areas where my phone is roaming and/or has poor reception. Using scripting layer for android, I will log the results of calling getOperatorName() once every ten minutes over the next week.
There is another method that might work in the android.telephony.cdma api. The documentation there is missing the reliability disclaimer. You would only get a Network ID instead of a name. Unfortunately, this requires API level 5 instead of 1 if that matters to you.
Logging the results of the getOperatorName() method yielded nothing special. When I had no service it consistently returned null and when I had service it consistently returned "Verizon Wireless." I'm sure that's not very helpful.
Edit: Addition and correction.
Added - Explanation of link
Corrected - API level 5 not 17
Edit 2: Test results
I am currently looking for a solution for this problem as well. According to this thread one could use CdmaCellLocation.getNetworkId and CdmaCellLocation.getSystemId. Since there are no CDMA networks in Germany, I am unable to check if this works...
You think maybe this was one precurser to Google pulling cdma support? Play within the frameworks or find you another playground is what I hear Google saying. Well that and the fact that carrier apps burned into roms have at times left gaping holes in security.
As to a possible answer to your question... from where are you able to pull info? APN settings might tell you or an assert to a known carrier line in build.prop could pull the info I might need for example. (I do the hobby roms). Then again if you physically inspect a phone, the carrier is usually branded ;) From what vantage are you pulling the info?
Rob