I want some unique ID of the Android device. I've tried it with the following code
String ts = Context.TELEPHONY_SERVICE;
TelephonyManager telephonyManager = (TelephonyManager) this.getSystemService(ts);
However I know that this works only for phones.
What if my app is running on some notebook, netbook or other type of device? How do I get an unique ID in that case?
There are three types of identifier on android phone.
IMEI
IMSI
String ts = Context.TELEPHONY_SERVICE;
TelephonyManager mTelephonyMgr = (TelephonyManager) getSystemService(ts);
String imsi = mTelephonyMgr.getSubscriberId();
String imei = mTelephonyMgr.getDeviceId();
Android ID
It is a 64-bit hex string which is generated on the device's first boot.
Generally it won't be changed unless is factory reset.
Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Sorry to bump an old thread but this problem gives me headache, I found a good article for someone to read, and this really helps me a lot.
Sometimes it is required during Android application development to get the unique id of the Android based smartphone device. This is necessary in cases when the user wants to track the unique device installations of the application.
This is also useful in cases where the Android developer wants to send Push messages to only few specific devices. So over here it becomes necessary to have a UDID for every device.
In Android there are many alternatives to UDID of the device. Some of the methods to get the UDID in android application are listed below with its advantages and disadvantages and any necessary permissions for getting the device ID.
The IMEI: (International Mobile Equipment Identity)
The Android ID
The WLAN MAC Address string
The Bluetooth Address string
1) IMEI: (International Mobile Equipment Identity)
The IMEI Number is a very good and primary source to get the device ID. It is unique for each and every device and is dependent on the device Hardware. So it is also unique for each and every device and it is permanent till the lifetime of the device.
The code snippet to get the Device IMEI is as below,
TelephonyManager TelephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String m_deviceId = TelephonyMgr.getDeviceId();
For this your application will require the permission “android.permission.READ_PHONE_STATE” given in the manifest file.
Advantages of using IMEI as Device ID:
The IMEI is unique for each and every device.
It remains unique for the device even if the application is re-installed or if the device is rooted or factory reset.
Disadvantages of using IMEI as Device ID:
IMEI is dependent on the Simcard slot of the device, so it is not possible to get the IMEI for the devices that do not use Simcard.
In Dual sim devices, we get 2 different IMEIs for the same device as it has 2 slots for simcard.
2) The Android ID
The Android_ID is a unique 64 bit number that is generated and stored when the device is first booted. The Android_ID is wiped out when the device is Factory reset and new one gets generated.
The code to get the Android_ID is shown below,
String m_androidId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Advantages of using Android_ID as Device ID:
It is unique identifier for all type of devices (smart phones and tablets).
No need of any permission.
It will remain unique in all the devices and it works on phones without Simcard slot.
Disadvantages of using Android_ID as Device ID:
If Android OS version is upgraded by the user then this may get changed.
The ID gets changed if device is rooted or factory reset is done on the device.
Also there is a known problem with a Chinese manufacturer of android device that some devices have same Android_ID.
3) The WLAN MAC Address string
We can get the Unique ID for android phones using the WLAN MAC address also. The MAC address is unique for all devices and it works for all kinds of devices.
The code snippet to get the WLAN MAC address for a device is as shown below,
WifiManager m_wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
String m_wlanMacAdd = m_wm.getConnectionInfo().getMacAddress();
Your application will require the permission “android.permission.ACCESS_WIFI_STATE” given in the manifest file.
Advantages of using WLAN MAC address as Device ID:
It is unique identifier for all type of devices (smart phones and tablets).
It remains unique if the application is reinstalled.
Disadvantages of using WLAN MAC address as Device ID:
If device doesn’t have wifi hardware then you get null MAC address, but generally it is seen that most of the Android devices have wifi hardware and there are hardly few devices in the market with no wifi hardware.
4) The Bluetooth Address string
We can get the Unique ID for android phones using the Bluetooth device also. The Bluetooth device address is unique for each device having Bluetooth hardware.
The code snippet to get the Bluetooth device address is as given below,
BluetoothAdapter m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_bluetoothAdd = m_BluetoothAdapter.getAddress();
To get the above code, your application needs the permission “android.permission.BLUETOOTH” given in the manifest file.
Advantages of using Bluetooth device address as Device ID:
It is unique identifier for all type of devices (smart phones and tablets).
There is generally a single Bluetooth hardware in all devices and it doesn’t gets changed.
Disadvantages of using Bluetooth device address as Device ID:
If device hasn’t bluetooth hardware then you get null.
As per me these are few of the best possible ways to get the Unique Device ID for Android smartphone device and their pros and cons of using it. Now it is upto you to decide which method to use based on the Android application development requirements.
If there are any other methods to get UDID and that covers up the disadvantages of above methods, then I would love to explore those in my Android application. Pl. share those in comment box and also if any suggestions or queries.
Here's the article
Secure.getString(getContentResolver(), Secure.ANDROID_ID);
This will not work for all the devices.
Some of the android devices has a problem Some devices returns null when we try to get the Device ID.The only way to solve this issue is to make a pseudodeviceID which should be generated by ourself.This function will generation a unique device ID for you.You can make changes to this function as you needed.Me too struggled a lot for solving this issue.
public String getDeviceID() {
/*String Return_DeviceID = USERNAME_and_PASSWORD.getString(DeviceID_key,"Guest");
return Return_DeviceID;*/
TelephonyManager TelephonyMgr = (TelephonyManager) getApplicationContext().getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
String m_szImei = TelephonyMgr.getDeviceId(); // Requires
// READ_PHONE_STATE
// 2 compute DEVICE ID
String m_szDevIDShort = "35"
+ // we make this look like a valid IMEI
Build.BOARD.length() % 10 + Build.BRAND.length() % 10
+ Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10
+ Build.DISPLAY.length() % 10 + Build.HOST.length() % 10
+ Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10
+ Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10
+ Build.TAGS.length() % 10 + Build.TYPE.length() % 10
+ Build.USER.length() % 10; // 13 digits
// 3 android ID - unreliable
String m_szAndroidID = Secure.getString(getContentResolver(),Secure.ANDROID_ID);
// 4 wifi manager, read MAC address - requires
// android.permission.ACCESS_WIFI_STATE or comes as null
WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
String m_szWLANMAC = wm.getConnectionInfo().getMacAddress();
// 5 Bluetooth MAC address android.permission.BLUETOOTH required
BluetoothAdapter m_BluetoothAdapter = null; // Local Bluetooth adapter
m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_szBTMAC = m_BluetoothAdapter.getAddress();
System.out.println("m_szBTMAC "+m_szBTMAC);
// 6 SUM THE IDs
String m_szLongID = m_szImei + m_szDevIDShort + m_szAndroidID+ m_szWLANMAC + m_szBTMAC;
System.out.println("m_szLongID "+m_szLongID);
MessageDigest m = null;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
m.update(m_szLongID.getBytes(), 0, m_szLongID.length());
byte p_md5Data[] = m.digest();
String m_szUniqueID = new String();
for (int i = 0; i < p_md5Data.length; i++) {
int b = (0xFF & p_md5Data[i]);
// if it is a single digit, make sure it have 0 in front (proper
// padding)
if (b <= 0xF)
m_szUniqueID += "0";
// add number to string
m_szUniqueID += Integer.toHexString(b);
}
m_szUniqueID = m_szUniqueID.toUpperCase();
Log.i("-------------DeviceID------------", m_szUniqueID);
Log.d("DeviceIdCheck", "DeviceId that generated MPreferenceActivity:"+m_szUniqueID);
return m_szUniqueID;
}
Look at the constant
ANDROID_ID in android.provider.Secure.Settings to see if that helps.
I am adding a few useful links from official docs;
Best Practices for Unique Identifiers
Changes to Device Identifiers in Android O
For detailed instructions on how to get a Unique Identifier for each Android device your application is installed from, see this official Android Developers Blog posting:
http://android-developers.blogspot.com/2011/03/identifying-app-installations.html
It seems the best way is for you to generate one your self upon installation and subsequently read it when the application is re-launched.
I personally find this acceptable but not ideal. No one identifier provided by Android works in all instances as most are dependent on the phone's radio states (wifi on/off, cellular on/off, bluetooth on/off). The others like Settings.Secure.ANDROID_ID must be implemented by the manufacturer and are not guaranteed to be unique.
The following is an example of writing data to an INSTALLATION file that would be stored along with any other data the application saves locally.
public class Installation {
private static String sID = null;
private static final String INSTALLATION = "INSTALLATION";
public synchronized static String id(Context context) {
if (sID == null) {
File installation = new File(context.getFilesDir(), INSTALLATION);
try {
if (!installation.exists())
writeInstallationFile(installation);
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return sID;
}
private static String readInstallationFile(File installation) throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
private static void writeInstallationFile(File installation) throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id = UUID.randomUUID().toString();
out.write(id.getBytes());
out.close();
}
}
Use a MAC address:
A Media Access Control address (MAC
address) is a unique identifier
assigned to network interfaces
Any device connected to a network is guaranteed to have a MAC address, and you can find it on the Android by going to Settings > About Phone > Status.
You should be able to get the bluetooth Mac address using the Bluetooth API.
You can try this:
String deviceId = Secure.getString(this.getContentResolver(),
Secure.ANDROID_ID);
Settings.Secure#ANDROID_ID returns the Android ID as an unique 64-bit hex string.
import android.provider.Settings.Secure;
private String android_id = Secure.getString(getContext().getContentResolver(),
Secure.ANDROID_ID);
final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
final String tmDevice, tmSerial, tmPhone, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
UUID deviceUuid = new UUID(androidId.hashCode(), ((<span id="IL_AD3" class="IL_AD">long</span>)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();
You can get MAC address if network-device (Bluetooth etc.) is enabled in the system (turned on). But device may have Bluetooth, WiFi, etc. or nothing.
You may write your own unique ID generator (with 20 numbers or symbols randomly for example)
TextView textAndroidId = (TextView)findViewById(R.id.androidid);
String AndroidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
textAndroidId.setText("My ID is: " + AndroidId);
Since new restrictions have been applied to the MAC address and other telephony-related API's and one can only access those hardware-related Unique identifiers if they are part of the system app and has the required privileges.
from docs:
When working with Android identifiers, follow these best practices:
Avoid using hardware identifiers. In most use cases, you can avoid using hardware identifiers, such as SSAID (Android ID), without limiting required functionality.
Android 10 (API level 29) adds restrictions for non-resettable identifiers, which include both IMEI and serial number. Your app must be a device or profile owner app, have special carrier permissions, or have the READ_PRIVILEGED_PHONE_STATE privileged permission in order to access these identifiers.
Only use an Advertising ID for user profiling or ads use cases. When using an Advertising ID, always respect users' selections regarding ad tracking. Also, ensure that the identifier cannot be connected to personally identifiable information (PII), and avoid bridging Advertising ID resets.
Use a Firebase installation ID (FID) or a privately stored GUID whenever possible for all other use cases, except for payment fraud prevention and telephony. For the vast majority of non-ads use cases, an FID or GUID should be sufficient.
Use APIs that are appropriate for your use case to minimize privacy risk. Use the DRM API for high-value content protection and the SafetyNet APIs for abuse protection. The SafetyNet APIs are the easiest way to determine whether a device is genuine without incurring privacy risk.
The remaining sections of this guide elaborate on these rules in the context of developing Android apps.
The best case is we use the FID or GUID to identify the uniqueness of the app per installation, here is how you can do it.
fun getDeviceId(): String {
return FirebaseInstallations.getInstance().id.result ?: UUID.randomUUID().toString()
}
You can check permission and can evaluate the value it will give you the device id:
private static final int REQUEST_READ_PHONE_STATE = 1;
int permissionCheck = ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.READ_PHONE_STATE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_READ_PHONE_STATE);
} else {
TelephonyManager tManager = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
System.out.print(uid);
}
Output: 358240051111110
Related
I am using GoogleFit HistoryAPI for get step data from user. It's working well.
However, in my case, I want to distinguish data between from different devices (using same account) because I don't want user using same account for 2 or more devices (it is a game base on step so I don't want user play on 1 device and have achievement on many devices).
I found that Device from DataSource#getDevice, Device#getLocalDevice can help me distinguish data between from different devices. Below is info from official docs:
To get information about the device for a data source, use the DataSource.getDevice method. The device information is useful to distinguish from similar sensors on different devices, show the device information from a sensor to the user, or process data differently depending on the device. For example, you may be interested in reading data specifically from the a sensor on a wearable device but not from the same type of sensor on the phone.
To get a Device instance for the device that is running your activity, use the Device.getLocalDevice static method. This is useful when you want to check if a data source is on the same device that your app is running on.
So,
// My idea is comparing the uid of local device and uid of device in datasource
// if it is same => step come from THIS device
// if not => step come from OTHER device
private void dumpDataSet(DataSet dataSet) {
for (DataPoint dp : dataSet.getDataPoints()) {
Log.i(Constant.TAG, "Origin type uid: " + dp.getOriginalDataSource().getDevice().getUid());
Log.i(Constant.TAG, "Local device uid: " + Device.getLocalDevice(getApplicationContext()).getUid());
...
}
}
However, the logcat result for datasource from only 1 DEVICE is
Origin type uid: 9ff67c48
Local device uid: f2b01c49ecd9c389
// Only the model, manufacturer is same (but I can not use 2 fields because user can use 2 devices with same model, manufacturer)
You can see that the uid from datasource is different to local device uid, so I can not distinguish data.
Is there any way to distinguish data between from different devices? Any help or suggestion would be great appreciated.
DEMO project
From what I get, I think you a looking ro stable ID for each Device. There are few ways of using ID, on which you can relay.
public static String getSerial() {
final String serial;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
serial = Build.getSerial();
} else {
serial = Build.SERIAL;
}
return serial;
}
As another eample, it's common to use IMEI, to relay on Unique ID, from Telephony Manager.
public static String getDeviceImei(Context ctx) {
TelephonyManager telephonyManager = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
return telephonyManager.getDeviceId();
}
And last, but maybe most correct way, I suggest to use Secure ID. Which provides stable background, of using this value. From the Doc On devices that have multiple users, each user appears as a completely separate device, so the ANDROID_ID value is unique to each user. Settings.Secure#ANDROID_ID
import android.provider.Settings.Secure;
private String android_id = Secure.getString(getContext().getContentResolver(),
Secure.ANDROID_ID);
I'm developing an app in which I'm gonna need the unique ID of a device.
This post: Is there a unique Android device ID? first leads me to consider using ANDROID_ID. But I need a reliable solution for both tablets and phones, with or without any google account/software on it, like in China where most of its services are blocked. I'm therefore looking for an other solution.
Important: for security reasons, this id must be safe from any change. Of course when the device is rooted or when someone really want to mess with the app, it's impossible, but at least for the average users. Also, the Mac address and the TelephonyManager.getDeviceId() are not reliable.
As I'm targeting both phones and tablets, with or without Google, is it a way to get a unique device Id unmodifiable for each device?
I am sorry that I flagged this question before fully understanding it. Like #Johann said considering rooted users into the equation will make it a lot more difficult to identify the device.
Using the assumption that your application uses webservice, user must connect to internet in some way i.e. either by data plan(users with sim card) or by wifi.
So combining id's from both the hardware and generating a unique hashcode of the resulting string, you should be able to uniquely identify the device(in theory i.e). But I haven't tested this code, so check if works for you.
final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
final String tmDevice, tmSerial, androidId, wifi;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi = ""+ manager.getConnectionInfo().getMacAddress();
String unique_id = makeSHA1Hash(tmDevice + tmSerial + androidId + wifi);
makeSHA1Hash
public String makeSHA1Hash(String input)
throws NoSuchAlgorithmException, UnsupportedEncodingException
{
MessageDigest md = MessageDigest.getInstance("SHA1");
md.reset();
byte[] buffer = input.getBytes("UTF-8");
md.update(buffer);
byte[] digest = md.digest();
String hexStr = "";
for (int i = 0; i < digest.length; i++) {
hexStr += Integer.toString( ( digest[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return hexStr;
}
Hope it helps you...
You can use the wifi mac address:
private String getWifiMacAddress() {
WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();
return info.getMacAddress();
}
you can use the device imei number.
You want to call-
android.telephony.TelephonyManager.getDeviceId().
You'll need the following permission in your AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
I think it would be good to identify devices by using Mac address o Wi-Fi module. It's quite unique even on cheap chinese devices.
Take a look at WifiInfo class:
http://developer.android.com/reference/android/net/wifi/WifiInfo.html
Should works fine for device identification.
After the device is rooted, the IMEI numbers and the MAC/WiFi address can be modified. Moreover, from Android Marshmallow, the user may revoke the permission for WiFi/MAC address and Bluetooth address. If you try to retrieve those values, you will be presented with a simple dummy ID, which remains common across all Marshmallow devices.Check this link
You can use the Android unique serial number it is generated when the device is booted for the first time and remains same for the lifetime.
Settings.Secure.getString(getContext().getContentResolver(), Settings.Secure.ANDROID_ID)
I need to register user devices on server with an unique identifier that be a constant value and doesn't change in the future.
I can't find a good solution to get unique id from all devices (with/without simcard).
Secure.ANDROID_ID: Secure.ANDROID_ID is not unique and can be null or change on factory reset.
String m_androidId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
IMEI: IMEI is dependent on the Simcard slot of the device, so it is not possible to get the IMEI for the devices that do not use Simcard.
TelephonyManager tManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String uuid = tManager.getDeviceId();
WLAN MAC Address: If device doesn’t have wifi hardware then it returns null MAC address. and user can change the device mac address.
WifiManager m_wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
String m_wlanMacAdd = m_wm.getConnectionInfo().getMacAddress();
Bluetooth Address string:If device hasn’t bluetooth hardware then it returns null.
BluetoothAdapter m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_bluetoothAdd = m_BluetoothAdapter.getAddress();
Instance id: instance_id will change when user uninstalls and reinstalls app. and it's not a constant value.
Do you have any idea to get a unique id from all Android devices (with/without simcard, Bluetooth, ...) that really be unique, cannot be null and doesn't change after uninstall/reinstall app?
I found that Secure.ANDROID_ID is the best choice. This is a 64-bit quantity that is generated and stored when the device first boots. But it resets on device factory reset.
there are some reports that shows some devices has same Secure.ANDROID_ID on all instances.
we can add extra items (like sim serial, GCM instance id or ...) to the Secure.ANDROID_ID and generate new unique fingerprint.
Mutiple users can be setup on Android device and Secure.ANDROID_ID is different for every user on same Android device. So using Secure.ANDROID_ID means single devices will be registered as a different device for each user setup on the device.
Secure.ANDROID_ID is your only friend. However it has some problems (empty results) on older (<2.3) devices. All other ID's do not work on all type of devices.
Please also read Is there a unique Android device ID?
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.
My app (S Educate) requires me to get the DeviceId (for Analytics/Recommendations) and hence I added the permission, READ_PHONE_STATE and although the documentation is harmless, when the user installs, the app permissions window shows, "Phone Calls - Monitor, record, and process phone calls" which obviously prevents user from installing and users have informed that they are not installing simply because of this permission.
Screenshot (click for larger variant)
Here are my options:
I state clearly in my app description that I require this permission to get DeviceId and not to monitor/record phone calls and hope the users believe me and install the app
I find an alternate way to get DeviceId - which to my knowledge is not available without using the above mentioned permission
Please advise how do I get around this permission issue.
Please use an app-generated UUID. This will allow you to distinguish one app installation from another, without violating user privacy.
There are different ways you can retrieve Unique device id in Android.
IMEI (for this, You will need to add READ_PHONE_STATE Permission in Manifest)
Pseudo Unique ID (no need to add READ_PHONE_STATE permission)
Android ID
MAC Address
Check out the details below.
http://www.pocketmagic.net/2011/02/android-unique-device-id/#.UsMCatIW2vE
From Android Developers Blog
In the past, when every Android device was a phone, things were simpler: TelephonyManager.getDeviceId() is required to return (depending on the network technology) the IMEI, MEID, or ESN of the phone, which is unique to that piece of hardware.
Mac Address
It may be possible to retrieve a Mac address from a device’s WiFi or
Bluetooth hardware. We do not recommend using this as a unique
identifier. To start with, not all devices have WiFi. Also, if the
WiFi is not turned on, the hardware may not report the Mac address.
Serial Number
Since Android 2.3 (“Gingerbread”) this is available via
android.os.Build.SERIAL. Devices without telephony are required to
report a unique device ID here; some phones may do so also.
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.
Solution is given on android blog. Use Installation.id(context).
public class Installation {
private static String sID = null;
private static final String INSTALLATION = "INSTALLATION";
public synchronized static String id(Context context) {
if (sID == null) {
File installation = new File(context.getFilesDir(), INSTALLATION);
try {
if (!installation.exists())
writeInstallationFile(installation);
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return sID;
}
private static String readInstallationFile(File installation) throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
private static void writeInstallationFile(File installation) throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id = UUID.randomUUID().toString();
out.write(id.getBytes());
out.close();
}
}