Categories
android uniqueidentifier

Is there a unique Android device ID?

2994

Do Android devices have a unique ID, and if so, what is a simple way to access it using Java?

2

2178

Settings.Secure#ANDROID_ID returns the Android ID as an unique for each user 64-bit hex string.

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID);

Also read Best practices for unique identifiers: https://developer.android.com/training/articles/user-data-ids

18

1180

UPDATE: As of recent versions of Android, many of the issues with ANDROID_ID have been resolved, and I believe this approach is no longer necessary. Please take a look at Anthony’s answer.

Full disclosure: my app used the below approach originally but no longer uses this approach, and we now use the approach outlined in the Android Developer Blog entry that emmby’s answer links to (namely, generating and saving a UUID#randomUUID()).


There are many answers to this question, most of which will only work “some” of the time, and unfortunately, that’s not good enough.

Based on my tests of devices (all phones, at least one of which is not activated):

  1. All devices tested returned a value for TelephonyManager.getDeviceId()
  2. All GSM devices (all tested with a SIM) returned a value for TelephonyManager.getSimSerialNumber()
  3. All CDMA devices returned null for getSimSerialNumber() (as expected)
  4. All devices with a Google account added returned a value for ANDROID_ID
  5. All CDMA devices returned the same value (or derivation of the same value) for both ANDROID_ID and TelephonyManager.getDeviceId()as long as a Google account has been added during setup.
  6. I did not yet have a chance to test GSM devices with no SIM, a GSM device with no Google account added, or any of the devices in airplane mode.

So if you want something unique to the device itself, TM.getDeviceId() should be sufficient. Obviously, some users are more paranoid than others, so it might be useful to hash 1 or more of these identifiers, so that the string is still virtually unique to the device, but does not explicitly identify the user’s actual device. For example, using String.hashCode(), combined with a UUID:

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);

final String tmDevice, tmSerial, 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(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

might result in something like: 00000000-54b3-e7c7-0000-000046bffd97

It works well enough for me.

As Richard mentions below, don’t forget that you need permission to read the TelephonyManager properties, so add this to your manifest:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

import libraries

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;

14

  • 161

    Telephony-based ID won’t be there on tablet devices, neh?

    Jun 23, 2010 at 14:27

  • 24

    Hence why I said most won’t work all the time 🙂 I’ve yet to see any answer to this question that is reliable for all devices, all device types, and all hardware configurations. That’s why this question is here to begin with. It’s pretty clear that there is no end-all-be-all solution to this. Individual device manufacturers may have device serial numbers, but those are not exposed for us to use, and it is not a requirement. Thus we’re left with what is available to us.

    – Joe

    Jun 29, 2010 at 19:40

  • 33

    The code sample works great. Remember to add <uses-permission android:name="android.permission.READ_PHONE_STATE" /> to the manifest file. If storing in a database, the returned string is 36 characters long.

    – Richard

    Feb 27, 2011 at 22:28

  • 12

    Be aware there are huge limitations with this solution: android-developers.blogspot.com/2011/03/…

    – emmby

    Apr 7, 2011 at 20:09

  • 21

    @softarn: I believe what you’re referring to is the Android Developer Blog that emmby already linked to, which explains what you are trying to say, so perhaps you should have simply upvoted his comment instead. Either way, as emmby mentions in his answer, there are still problems even with the blog info. The question asks for a unique DEVICE identifier (not installation identifier), so I disagree with your statement. The blog is making an assumption that what you want is not necessarily to track the device, whereas the question asks for just that. I agree with the blog otherwise.

    – Joe

    Jul 22, 2011 at 0:45


463

#Last Updated: 6/2/15


After reading every Stack Overflow post about creating a unique ID, the Google developer blog, and Android documentation, I feel as if the ‘Pseudo ID’ is the best possible option.

Main Issue: Hardware vs Software

Hardware

  • Users can change their hardware, Android tablet, or phone, so unique IDs based on hardware are not good ideas for TRACKING USERS
  • For TRACKING HARDWARE, this is a great idea

Software

  • Users can wipe/change their ROM if they are rooted
  • You can track users across platforms (iOS, Android, Windows, and Web)
  • The best want to TRACK AN INDIVIDUAL USER with their consent is to simply have them login (make this seamless using OAuth)

#Overall breakdown with Android

###- Guarantee uniqueness (include rooted devices) for API >= 9/10 (99.5% of Android devices)
###- No extra permissions

Psuedo code:

if API >= 9/10: (99.5% of devices)

return unique ID containing serial id (rooted devices may be different)

else

return the unique ID of build information (may overlap data - API < 9)

Thanks to @stansult for posting all of our options (in this Stack Overflow question).

##List of options – reasons why/ why not to use them:

  • User Email – Software

  • User could change email – HIGHLY unlikely

  • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> or

  • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> (How to get the Android device’s primary e-mail address)

  • User Phone Number – Software

  • Users could change phone numbers – HIGHLY unlikely

  • <uses-permission android:name="android.permission.READ_PHONE_STATE" />

  • IMEI – Hardware (only phones, needs android.permission.READ_PHONE_STATE)

  • Most users hate the fact that it says “Phone Calls” in the permission. Some users give bad ratings because they believe you are simply stealing their personal information when all you really want to do is track device installs. It is obvious that you are collecting data.

  • <uses-permission android:name="android.permission.READ_PHONE_STATE" />

  • Android ID – Hardware (can be null, can change upon factory reset, can be altered on a rooted device)

  • Since it can be ‘null’, we can check for ‘null’ and change its value, but this means it will no longer be unique.

  • If you have a user with a factory reset device, the value may have changed or altered on the rooted device so there may be duplicates entries if you are tracking user installs.

  • WLAN MAC Address – Hardware (needs android.permission.ACCESS_WIFI_STATE)

  • This could be the second-best option, but you are still collecting and storing a unique identifier that comes directly from a user. This is obvious that you are collecting data.

  • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>

  • Bluetooth MAC Address – Hardware (devices with Bluetooth, needs android.permission.BLUETOOTH)

  • Most applications on the market do not use Bluetooth, and so if your application doesn’t use Bluetooth and you are including this, the user could become suspicious.

  • <uses-permission android:name="android.permission.BLUETOOTH "/>

  • Pseudo-Unique ID – Software (for all Android devices)

  • Very possible, may contain collisions – See my method posted below!

  • This allows you to have an ‘almost unique’ ID from the user without taking anything that is private. You can create your own anonymous ID from device information.


I know there isn’t any ‘perfect’ way of getting a unique ID without using permissions; however, sometimes we only really need to track the device installation. When it comes to creating a unique ID, we can create a ‘pseudo unique id’ based solely on information that the Android API gives us without using extra permissions. This way, we can show the user respect and try to offer a good user experience as well.

With a pseudo-unique id, you really only run into the fact that there may be duplicates based on the fact that there are similar devices. You can tweak the combined method to make it more unique; however, some developers need to track device installs and this will do the trick or performance based on similar devices.

##API >= 9:

If their Android device is API 9 or over, this is guaranteed to be unique because of the ‘Build.SERIAL’ field.

REMEMBER, you are technically only missing out on around 0.5% of users who have API < 9. So you can focus on the rest: This is 99.5% of the users!

##API < 9:

If the user’s Android device is lower than API 9; hopefully, they have not done a factory reset and their ‘Secure.ANDROID_ID’ will be preserved or not ‘null’. (see http://developer.android.com/about/dashboards/index.html)

##If all else fails:

If all else fails, if the user does have lower than API 9 (lower than Gingerbread), has reset their device, or ‘Secure.ANDROID_ID’ returns ‘null’, then simply the ID returned will be solely based on their Android device information. This is where the collisions can happen.

Changes:

  • Removed ‘Android.SECURE_ID’ because factory resets could cause the value to change
  • Edited the code to change on API
  • Changed the Pseudo

Please take a look at the method below:

/**
 * Return pseudo unique ID
 * @return ID
 */
public static String getUniquePsuedoID() {
    // If all else fails, if the user does have lower than API 9 (lower
    // than Gingerbread), has reset their device or 'Secure.ANDROID_ID'
    // returns 'null', then simply the ID returned will be solely based
    // off their Android device information. This is where the collisions
    // can happen.
    // Thanks http://www.pocketmagic.net/?p=1662!
    // Try not to use DISPLAY, HOST or ID - these items could change.
    // If there are collisions, there will be overlapping data
    String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);

    // Thanks to @Roman SL!
    // https://stackoverflow.com/a/4789483/950427
    // Only devices with API >= 9 have android.os.Build.SERIAL
    // http://developer.android.com/reference/android/os/Build.html#SERIAL
    // If a user upgrades software or roots their device, there will be a duplicate entry
    String serial = null;
    try {
        serial = android.os.Build.class.getField("SERIAL").get(null).toString();

        // Go ahead and return the serial for api => 9
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    } catch (Exception exception) {
        // String needs to be initialized
        serial = "serial"; // some value
    }

    // Thanks @Joe!
    // https://stackoverflow.com/a/2853253/950427
    // Finally, combine the values we have found by using the UUID class to create a unique identifier
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}

#New (for apps with ads AND Google Play Services):

From the Google Play Developer’s console:

Beginning August 1st, 2014, the Google Play Developer Program Policy
requires all-new app uploads and updates to use the advertising ID in
lieu of any other persistent identifiers for any advertising purposes.
Learn more

Implementation:

Permission:

<uses-permission android:name="android.permission.INTERNET" />

Code:

import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
import com.google.android.gms.common.GooglePlayServicesAvailabilityException;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import java.io.IOException;
...

// Do not call this function from the main thread. Otherwise, 
// an IllegalStateException will be thrown.
public void getIdThread() {

  Info adInfo = null;
  try {
    adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);

  } catch (IOException exception) {
    // Unrecoverable error connecting to Google Play services (e.g.,
    // the old version of the service doesn't support getting AdvertisingId).
 
  } catch (GooglePlayServicesAvailabilityException exception) {
    // Encountered a recoverable error connecting to Google Play services. 

  } catch (GooglePlayServicesNotAvailableException exception) {
    // Google Play services is not available entirely.
  }
  final String id = adInfo.getId();
  final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
}

Source/Docs:

http://developer.android.com/google/play-services/id.html
http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html

##Important:

It is intended that the advertising ID completely replace existing
usage of other identifiers for ads purposes (such as the use of ANDROID_ID
in Settings.Secure) when Google Play Services is available. Cases
where Google Play Services is unavailable are indicated by a
GooglePlayServicesNotAvailableException being thrown by
getAdvertisingIdInfo().

##Warning, users can reset:

http://en.kioskea.net/faq/34732-android-reset-your-advertising-id

I have tried to reference every link that I took information from. If you are missing and need to be included, please comment!

Google Player Services InstanceID

https://developers.google.com/instance-id/

5

  • 7

    i used your method in my app for sending comments. i have bad news. unfortunately PsuedoID isn’t unique completely. my server recorded more than 100 for 5 ID and more than 30 for almost 30 ID. the most repeated IDs are ‘ffffffff-fc8f-6093-ffff-ffffd8’ (159 record) and ‘ffffffff-fe99-b334-ffff-ffffef’ (154 time). also based on time and comments it’s obvious there are different peoples. the total records until now is 10,000. please let me know why this happened. tanks.

    Mar 17, 2015 at 16:36

  • 3

    I wrote this 1.5+ years ago. I am not sure why it is not unique for you. You can try the advertising ID. If not, you can come up with your own solution.

    Mar 17, 2015 at 17:35

  • 3

    sorta..I’d really appreciate if you go through the question and give your thoughts on this

    Apr 29, 2015 at 17:41

  • 1

    @user1587329 Thank you. I am trying to keep this up to date for everyone. This question is tricky when it comes to hardware vs software and cross platform.

    May 6, 2015 at 14:08

  • why so hard to get the unique id with a simple without collision anyway? just use Pseudo-Unique ID – Software + date (hhmmss) it’s no collision. the longer the combination the higher difficulties rate applied.

    – gumuruh

    Apr 25 at 3:41