By Tyler


2010-05-07 00:47:28 8 Comments

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

30 comments

@Kiran Maniya 2018-10-05 05:55:06

1.You can access android device id by gms service. see the given example below,

private DeviceInfoProvider mDeviceInfo = new DeviceInfoProvider(Context)
String mDeviceId = DeviceInfoProvider.getDeviceId(Context);
Log.d("DEVICE_ID" , mDeviceId);

2.Use the telephony manager, which provides a unique id(i.e. IMEI). See the example,

import android.telephony.TelephonyManager;
import android.content.Context;
// ...
TelephonyManager telephonyManager;
telephonyManager = (TelephonyManager) getSystemService(Context.
                TELEPHONY_SERVICE);
/*
* getDeviceId() returns the unique device ID.
* For example,the IMEI for GSM and the MEID or ESN for CDMA phones.
*/
String deviceId = telephonyManager.getDeviceId();
/*
* getSubscriberId() returns the unique subscriber ID,
*/
String subscriberId = telephonyManager.getSubscriberId();

This requires android.permission.READ_PHONE_STATE to your user which can be hard to justify following the type of application you have made.

  1. Devices without telephony services like tablets must report a unique device ID that is available via android.os.Build.SERIAL since Android 2.3 Gingerbread. Some phones having telephony services can also define a serial number. Like not all Android devices have a Serial Number, this solution is not reliable.

  2. On a device first boot, a random value is generated and stored. This value is available via Settings.Secure.ANDROID_ID. It’s a 64-bit number that should remain constant for the lifetime of a device. ANDROID_ID seems a good choice for a unique device identifier because it’s available for smartphones and tablets. To retrieve the value, you can use the following code,

    String androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);

However, the value may change if a factory reset is performed on the device. There is also a known bug with a popular handset from a manufacturer where every instance has the same ANDROID_ID. Clearly, the solution is not 100% reliable.

  1. Use UUID. As the requirement for most of the applications is to identify a particular installation and not a physical device, a good solution to get the unique id for a user if to use UUID class. The following solution has been presented by Reto Meier from Google in a Google I/O presentation,
SharedPreferences sharedPrefs = context.getSharedPreferences(
         PREF_UNIQUE_ID, Context.MODE_PRIVATE);
uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);

Update : The option 2 and 3 are no longer available after android 10 as the privacy updates by google. as option 2 and 3 requires critical permission.

@viper 2019-08-26 05:38:01

Which handset is the one where every instance has the same ANDROID_ID?

@Kiran Maniya 2019-08-26 06:37:34

please refer to the official docs developer.android.com/reference/android/provider/…

@Anubhav 2019-09-25 11:05:56

android.telephony.TelephonyManager.getDeviceId()

This will return whatever string uniquely identifies the device (IMEI on GSM, MEID for CDMA).

You'll need the following permission in your AndroidManifest.xml:

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

@Googlian 2019-10-23 07:22:30

It's deprecated

@Stephan J 2019-09-11 14:09:27

Yes , Every Android device have a unique serial numbers you can able to get it from below code. Build.SERIAL 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.

@Malwinder Singh 2019-07-24 07:34:34

If you add: 

Settings.Secure.getString(context.contentResolver,
    Settings.Secure.ANDROID_ID)

Android Lint will give you the following warning:

Using getString to get device identifiers is not recommended. Inspection info: Using these device identifiers is not recommended other than for high value fraud prevention and advanced telephony use-cases. For advertising use-cases, use AdvertisingIdClient$Info#getId and for analytics, use InstanceId#getId.

So, you should avoid using this.

As mentioned in Android Developer documentation :

1: Avoid using hardware identifiers.

In most use cases, you can avoid using hardware identifiers, such as SSAID (Android ID) and IMEI, without limiting required functionality.

2: 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.

3: Use an Instance ID 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 Instance ID or GUID should be sufficient.

4: 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.

@Vitaly Zinchenko 2019-08-03 12:41:31

To get a user id you can use Google Play Licensing Library.

To download this library open SDK Manager => SDK Tools. The path to downloaded library files is:

path_to_android_sdk_on_your_pc/extras/google/market_licensing/library

Include the library in your project (you can simply copy its files).

Next you need some implementation of Policy interface (you can simply use one of two files from the library: ServerManagedPolicy or StrictPolicy).

User id will be provided for you inside processServerResponse() function:

public void processServerResponse(int response, ResponseData rawData) {
    if(rawData != null) {
        String userId = rawData.userId
        // use/save the value
    }
    // ...
}

Next you need to construct the LicenseChecker with a policy and call checkAccess() function. Use MainActivity.java as an example of how to do it. MainActivity.java is located inside this folder:

path_to_android_sdk_on_your_pc/extras/google/market_licensing/sample/src/com/example/android/market/licensing

Don't forget to add CHECK_LICENSE permission to your AndroidManifest.xml.

More about Licensing Library: https://developer.android.com/google/play/licensing

@Raj 2019-06-11 16:55:41

Here is a simple answer to get AAID, tested working properly June 2019

 AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
        @Override
        protected String doInBackground(Void... params) {
            String token = null;
            Info adInfo = null;
            try {
                adInfo = AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext());
            } catch (IOException e) {
                // ...
            } catch ( GooglePlayServicesRepairableException e) {
                // ...
            } catch (GooglePlayServicesNotAvailableException e) {
                // ...
            }
            String android_id = adInfo.getId();
            Log.d("DEVICE_ID",android_id);

            return android_id;
        }

        @Override
        protected void onPostExecute(String token) {
            Log.i(TAG, "DEVICE_ID Access token retrieved:" + token);
        }

    };
    task.execute();

read full answer in detail here:

@Waheed Nazir 2019-05-03 22:09:36

To understand the available Unique Ids in Android devices. Use this official guide.

Best practices for unique identifiers:

IMEI, Mac Addresses, Instance Id, GUIDs, SSAID, Advertising Id, Safety Net API to verify devices.

https://developer.android.com/training/articles/user-data-ids

@Jens Vesti 2019-01-31 15:27:51

In order to include Android 9 I have only one idea that could still work that (probably) doesn't violate any terms, requires permissions, and works across installations and apps.

Fingerprinting involving a server should be able to identify a device uniquely. The combination of hardware information + installed apps and the installation times should do the trick. First installation times do not change unless an app is uninstalled and installed again. But this would have to be done for all apps on device in order to not be able to identify the device (ie. after a factory reset).

This is how I would go about it:

  1. Extract hardware information, application package names and first installation times.

This is how you extract all applications from Android (no permissions needed):

final PackageManager pm = application.getPackageManager();
List<ApplicationInfo> packages = 
pm.getInstalledApplications(PackageManager.GET_META_DATA);

for (ApplicationInfo packageInfo : packages) {
    try {
        Log.d(TAG, "Installed package :" + packageInfo.packageName);
        Log.d(TAG, "Installed :" + pm.getPackageInfo(packageInfo.packageName, 0).firstInstallTime);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
}
  1. You may want to make a hash of the each package name and installation timestamp combination, before sending it to the server, as it may or may not be any of your business what the user has installed on the device.
  2. Some apps (a lot actually) are system apps. These are likely to have the same installation timestamp, matching the latest system update after a factory reset. Because they have the same installation timestamp they are cannot be installed by the user, and can be filtered out.
  3. Send the info to the server and let it look for nearest match amongst previously stored info. You need to make a threshold when comparing with previously stored device info as apps are installed and uninstalled. But my guess is that this threshold can be very low, as any package name and first time installation timestamp combination alone will be pretty unique for a device, and apps are not that frequently installed and uninstalled. Having multiple apps just increases the probability of being unique.
  4. Return the generated unique id for the match, or generate a unique id, store with device info and return this new id.

NB: This is a non-tested and non-proved method! I am confident it will work, but I am also pretty sure that if this catches on, they will close it down one way or another.

@Martin Zikmund 2019-01-21 07:13:54

For completeness, here is how you can get the Id in Xamarin.Android and C#:

var id = Settings.Secure.GetString(ContentResolver, Settings.Secure.AndroidId);

Or if you are not within an Activity:

var id = Settings.Secure.GetString(context.ContentResolver, Settings.Secure.AndroidId);

Where context is the passed in context.

@Jared Burrows 2013-07-12 23:58:49

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 off of 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 off their Android device information. This is where the collisions can happen.

Changes:

  • Removed 'Android.SECURE_ID' because of 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/

@LuckyMe 2013-07-13 10:16:16

But wouldn't the Build class change upon OS update? Especially if the API got updated? If so, how do you guarantee this is unique? (Speaking about the method you wrote)

@Jared Burrows 2013-07-13 17:39:19

I am still tweaking and going over the classes as well as testing right now; however, I made sure not to include Build.DISPLAY, Build.HOST or Build.ID, which would definitely change on an OTA update. But, like I said API => 9 is practically guaranteed. We should only fall back on the Android.SECURE_ID and/or Build class.

@Marin 2014-02-05 19:13:07

I think there is an error in your code getting the serial number - it just returns the field name not its value - here is how to retrieve the value from the field: android.os.Build.class.getField("SERIAL").get(null).toString‌​();

@Jared Burrows 2014-02-05 21:02:12

@Marin Have you printed this out in the log?

@Marin 2014-02-06 00:48:29

Yes, this is how I found the error - the log showed the field name and its java type but not the actual value

@Jared Burrows 2014-02-06 04:15:31

@Marin The reason I ask is because you can edit the post, yourself. But I'll make the change, thanks!

@Kenji 2014-04-26 11:16:23

I wanna know that what is the range of Android_ID. is it have specific pattern? thanks

@SE apologise to Monica Cellio 2014-04-29 17:06:44

Build.SERIAL is a hardware serial number, as per the Android documentation. However, some API 9 phones like my Galaxy Ace, when queried for this number return "unknown"

@Micky 2014-07-28 14:44:26

"the advertising ID completely replace existing usage of other identifiers for ads purposes" => so this means you can still use ANDROID_ID for uses other than ads?

@Jared Burrows 2014-07-28 19:29:36

@NannuoLei Currently I am not using this.

@Jared Burrows 2014-07-28 19:30:35

@Kim I am considering moving to the Advertising ID

@Jamshid 2014-12-18 06:53:18

@JaredBurrows you said that: "If a user upgrades software". So which software my software or os upgrade?

@Jared Burrows 2014-12-18 15:51:00

@Jamshid IF the user upgrades the software on the device, it may not have the Android ID anymore or duplicated IDs.

@Jamshid 2015-01-08 10:18:01

@JaredBurrows your UniquePsuedoID not changed after my sofware update(in genymotion emulator), it's OK, but i'll ask you, what do you think, if Android os update, will UniquePsuedoID change?

@Jared Burrows 2015-01-08 15:06:48

@Jamshid Software update in the Genymotion emulator? You mean installing a new version, then reinstalling your app? What do you mean? I posted this question with links to the Android documentation that mentioned the Android ID changing on updates.

@Jamshid 2015-01-08 15:22:02

@JaredBurrows i update with play google, at first i install 0.0.6, then update to 0.0.7 in galaxy s4 geny motion device. so id not changed. maybe we should check real device?

@Jared Burrows 2015-01-08 15:42:14

@Jamshid Sounds good. I am not sure, I have not tested out the ID's.

@hojjat reyhane 2015-03-17 16:36:19

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.

@Jared Burrows 2015-03-17 17:35:58

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.

@Durai Amuthan.H 2015-04-29 17:24:17

@JaredBurrows - Can you plz take a look at this stackoverflow.com/q/27233518/730807 Thanks

@Jared Burrows 2015-04-29 17:29:54

@Duraiamuthan.H What about it? Isn't that just a duplicate of this question?

@Durai Amuthan.H 2015-04-29 17:41:16

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

@Jared Burrows 2015-05-06 14:08:05

@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.

@Den Rimus 2015-06-18 12:58:19

I never met an answer to "Will Build.SERIAL retain after major OS update or not?" This article here blog.djodjo.org/?p=664 shows that it will remain the same, while this post above states that it might change...

@Jared Burrows 2015-06-22 15:08:16

@JPM no problem. I try to keep this updated!

@Sayed Abolfazl Fatemi 2016-08-30 12:08:26

Salam. I think if using sum of getBytes() of each items (like Build.BOARD) against of length() of them it's better to make unique result. Because length of items can be same in other devices.

@shoe 2016-11-25 19:52:36

why does getUniquePsuedoID() use android.os.Build.class.getField("SERIAL").get(null).toString‌​() instead of simply Build.SERIAL?

@EpicPandaForce 2017-04-13 08:50:13

@shoe because the method didn't exist before API 9, and this solution is API < 9 compatible. However, Android O will bind reading Build.SERIAL to a permission, so Build.SERIAL will be deprecated. :|

@Nikolay Kulachenko 2018-07-10 09:16:41

Build.SERIAL is deprecated for 25+ sdk (N_MR1) and always returns "unknown". So PsuedoId is not unique anymore. Have a nice day :)

@elsennov 2018-08-13 04:44:55

Then use Build.getSerial() (android-developers.googleblog.com/2017/04/…). Have a nice day too :)

@Lenn Dolling 2011-03-24 19:55:18

I think this is sure fire way of building a skeleton for a unique ID... check it out.

Pseudo-Unique ID, that works on all Android devices Some devices don't have a phone (eg. Tablets) or for some reason, you don't want to include the READ_PHONE_STATE permission. You can still read details like ROM Version, Manufacturer name, CPU type, and other hardware details, that will be well suited if you want to use the ID for a serial key check, or other general purposes. The ID computed in this way won't be unique: it is possible to find two devices with the same ID (based on the same hardware and ROM image) but the changes in real-world applications are negligible. For this purpose you can use the Build class:

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

Most of the Build members are strings, what we're doing here is to take their length and transform it via modulo in a digit. We have 13 such digits and we are adding two more in front (35) to have the same size ID as the IMEI (15 digits). There are other possibilities here are well, just have a look at these strings. Returns something like 355715565309247. No special permission is required, making this approach very convenient.


(Extra info: The technique given above was copied from an article on Pocket Magic.)

@Steve Pomeroy 2011-04-12 16:28:04

Interesting solution. It sounds like this is a situation where you really should be just hashing all that data concatenated instead of trying to come up with your own "hash" function. There are many instances where you'd get collisions even if there is substantial data that is different for each value. My recommendation: use a hash function and then transform the binary results into decimal and truncate it as needed. To do it right, though you should really use a UUID or full hash string.

@Lenn Dolling 2011-05-15 00:09:57

I found that the Build.CPU_ABI and Build.MANUFACTURER are not present in all versions.. I was getting harsh build errors when running against <2.2 :)

@Steve Haley 2011-05-16 12:07:44

You should give credit to your sources... This has been lifted straight out of the following article: pocketmagic.net/?p=1662

@Lenn Dolling 2011-05-16 16:22:21

ohh for sure... I meant too.. thanks for doing what I forgot too. whoo hoo. we got some teamwork.

@Seva Alekseyev 2011-05-26 20:21:30

This ID is open to collisions like you don't know what. It's practically guaranteed to be the same on identical devices from the same carrier.

@jjmontes 2011-09-19 20:20:57

As said by Steve and Seva, this seems a really bad strategy, as the hash function proposed loos very weak. Don't use.

@David Given 2012-01-25 12:25:54

This may also change if the device gets upgraded.

@Victor Ronin 2012-07-26 17:26:51

I don't think it's good idea to use this solution. As I understand all Build fields will be the same for all phones produced together.

@Carl 2012-12-23 05:40:07

Per David Given's comment, this seems like a serious concern. A careful inventory should be made of the Build attributes to determine which ones are unlikely to change as a result of an over-the-air update. For example, Build.DISPLAY above, per the Javadoc, is "A build ID string meant for displaying to the user," so wouldn't that be likely to change when an update occurs? I still think that this approach could add useful distinguishing attributes in combination with other information from the device, but only if such OTA-changeable attributes can be carefully culled.

@Carl 2012-12-23 05:48:08

Likewise, Build.HOST is defined as "A string that uniquely identifies the host the build was BUILT on, in human readable format." It seems entirely possible that different BUILD machines could be used to create the build for an OTA update.

@Sinan Dizdarević 2015-03-04 16:53:23

Very, very bad solution. Tested on two Nexus 5... Return same numbers.

@Ege Kuzubasioglu 2017-12-28 08:36:43

Not recommended as deviceId can be used as tracking in 3rd party hands, but this is another way.

@SuppressLint("HardwareIds")
private String getDeviceID() {
    deviceId = Settings.Secure.getString(getApplicationContext().getContentResolver(),
                    Settings.Secure.ANDROID_ID);
    return deviceId;
}

@Jeff Padgett 2018-06-22 07:12:25

Android is making some changes on: Settings.Secure.ANDROID_ID; On Android 8.0 (API level 26) and higher versions of the platform, a 64-bit number (expressed as a hexadecimal string), unique to each combination of app-signing key, user, and device. This means Settings.Secure.ANDROID_ID now returns IDs that are unique to the app/device combination, which makes things safer for the user.

@Shivam Agrawal 2017-12-14 15:02:04

Serial Number is a unique device ID available via android.os.Build.SERIAL.

public static String getSerial() {
    String serial = "";
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        serial = Build.getSerial();
    }else{ 
        serial = Build.SERIAL;    
    }
    return serial;
}

Make sure you have READ_PHONE_STATE permission before calling getSerial().

NOTE:- It is Not available with Devices without telephony (like wifi only tablets).

@Ted Hopp 2017-12-14 20:42:24

Note that the docs say that this will return the hardware serial number "if available", suggesting that Build.SERIAL (or Build.getSerial()) is not always available. More info is available in the blog post Changes to Device Identifiers in Android O. Also worth a read: Best Practices for Unique Identifiers.

@Joe 2010-05-17 22:12:20

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 libs

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

@Seva Alekseyev 2010-06-23 14:27:54

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

@Joe 2010-06-29 19:40:29

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.

@liori 2011-01-31 20:12:16

Will you update your answer after more testing? It would be quite interesting.

@Richard 2011-02-27 22:28:48

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.

@Joe 2011-03-02 16:21:27

Yes, good call Richard. Updated my answer.

@Paresh Mayani 2011-04-06 06:51:28

@Joe Its awesome, but how do we get Unique Device id while developing application for Android Tablet kind of device? Please help me to find out.

@emmby 2011-04-07 20:09:14

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

@MusiGenesis 2011-04-21 16:19:41

FYI, TelephonyManager.getDeviceId() returns a valid unique ID on my Xoom, so this appears to work for tablets as well.

@Ross Hambrick 2011-05-06 20:56:30

Is that a WIFI only XOOM? (I guess I could test this on mine)

@softarn 2011-07-17 17:18:54

This answer is outdated and should not be used. Don't track devices, track installations!

@Joe 2011-07-22 00:45:57

@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.

@Daniel Novak 2011-08-04 07:10:22

I think there is one serious flaw in this method. This depends on SIM card information, users sometimes switch to Airplane mode = no SIM connected. You need to have a fallback mechanism in this scenario, probably to take the Android ID.

@Joe 2011-08-22 13:44:38

@Daniel Novak: fair point. For my case, it wasn't relevant because the id is used in API communication, so Airplane mode = no app :) We also designed it this way so that, e.g., if the user swaps SIM cards, we intentionally wanted the "device id" to be different. Obviously that won't be the case for everyone, so thanks for pointing it out.

@Mathias 2011-12-19 21:54:04

I'm a bit surprised that noone's brought this one up yet, but the code example can be really unfortunate in some circumstances - it will return a different ID depending on whether the phone is, for example, in flight mode or not, since the simSerialNumber will be null if the device gsm network is switched off. If you have an app that relies on a unique id, but only needs internet, not necessarily network, it might be best to ensure that the code always returns the same ID regardless of the current phone's network status.

@Joe 2011-12-22 17:09:47

@Mathias: Actually, the comment just before yours from Daniel Novak on Aug 4 does bring up that exact point :) And I responded to it as well.

@Mathias 2012-01-30 15:43:53

@Joe, geez :) Its pretty obvious, i must have forgotten to show all comments.... sorry.

@Eduardo 2012-03-30 13:19:53

@Joe: What means that variable tmPhone? It is not being used, so I am wondering. Thanks.

@Joe 2012-04-10 18:55:33

@Eduardo: in the initial code that we used, we were also hashing the phone number (getLine1Number()), but that doesn't always work, and didn't really help anyway, so we removed it. It's just a leftover variable, good catch. :) I'll remove it from the example.

@Eng.Fouad 2013-05-24 16:33:07

I wouldn't use getSimSerialNumber() since the user can easily change his SIM card.

@Joe 2013-05-29 19:53:28

@Eng.Fouad: in my implementation, we wanted it to be treated as a new device if the SIM card was changed (e.g., we would save login credentials by device id, so if you changed your SIM, the app would "forget" your previously saved credentials, for security reasons). If you don't want that behavior, you are right it should be omitted.

@Pratik Butani 2014-12-26 06:33:41

getDeviceId() changed on SIM card Change. Why?

@Joe 2014-12-29 18:50:09

@ツFellinLovewithAndroidツ See the 2 comments directly above yours, as well as the comment from Aug 4 2011 and response Aug 22 2011. This behavior is intended for this approach. If you do not want that behavior, simply replace the getSimSerialNumber() contributor with something else (or omit it by substituting 0 in its place.

@Behrouz.M 2015-06-18 09:35:05

I have used this code for 6 month. It does not generate a unique ID. I do not recommend all of you to use this code. Currently I am using the code from this post: stackoverflow.com/a/17625641/365229

@angryITguy 2015-06-29 04:06:30

I have found from my own implementation, that I am getting duplicate ID's registered when I record installations on my server. Amazing how Google have botched this for developers and have done so for a long time. A "roll your own" approach seems to be the best solution => android-developers.blogspot.com.au/2011/03/…

@lavuy 2015-07-30 06:48:26

I would strongly recommend you don't use this code. It has several critical bugs: Firstly, both telephony and Android ID aren't guaranteed to exist, and if both don't exist your devices will be mapped according to their model alone. Secondly, and more important, when you use the Android ID's hash code you turn a 64bit string representation of a number to a 32 bit number, and thus you lose a lot of the uniqueness.

@wit221 2016-08-14 20:44:34

The Developer Blog entry writes the uuid to a separate file. Why not simply check if the uuid exists, and if not, then generate one and save it in shared preferences? This will also track an installation, since shared preferences are wiped when an app is deleted. Also, I disagree that devs should use installation id instead of device ids. There are countless situations in which specifically the latter one is the one needed.

@Prashanth Debbadwar 2017-02-15 06:37:31

I was using the imei. If users use this play.google.com/store/apps/… then we will get wrong imei.

@Hossein Shahdoost 2017-06-18 09:11:07

Though it creates a unique id per device, This method has a huge flaw, By changing either the Sim or Google account the device Id also changes.

@Amir Ziarati 2017-10-23 06:41:47

tm.getDeviceId() was deprecated in api 26. wouldnt that be a problem ?

@Joe 2017-11-30 21:13:00

@AmirZiarati please see the UPDATE section at the top.

@Naga 2019-02-22 08:13:09

If all devices with Google account will return unique I'd then most likely ANDROID_ID would work as there are lean chances an Android device without Google account

@Ajay Chauhan 2019-10-01 08:46:57

wont working for Android 10

@Cheok Yan Cheng 2017-11-07 19:00:18

I have came across this question several years ago, and have learn to implement a generalized solution based on various answers.

I have used the generalized solution for several years, in a real-world product. It serves me quite well so far. Here's the code snippet, based on various provided answers.

Note, getEmail will return null most of the time, as we didn't ask for permission explicitly.

private static UniqueId getUniqueId() {
    MyApplication app = MyApplication.instance();

    // Our prefered method of obtaining unique id in the following order.
    // (1) Advertising id
    // (2) Email
    // (2) ANDROID_ID
    // (3) Instance ID - new id value, when reinstall the app.

    ////////////////////////////////////////////////////////////////////////////////////////////
    // ADVERTISING ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    AdvertisingIdClient.Info adInfo = null;
    try {
        adInfo = AdvertisingIdClient.getAdvertisingIdInfo(app);
    } catch (IOException e) {
        Log.e(TAG, "", e);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e(TAG, "", e);
    } catch (GooglePlayServicesRepairableException e) {
        Log.e(TAG, "", e);
    }

    if (adInfo != null) {
        String aid = adInfo.getId();
        if (!Utils.isNullOrEmpty(aid)) {
            return UniqueId.newInstance(aid, UniqueId.Type.aid);
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // EMAIL
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String email = Utils.getEmail();
    if (!Utils.isNullOrEmpty(email)) {
        return UniqueId.newInstance(email, UniqueId.Type.eid);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // ANDROID ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String sid = Settings.Secure.getString(app.getContentResolver(), Settings.Secure.ANDROID_ID);
    if (!Utils.isNullOrEmpty(sid)) {
        return UniqueId.newInstance(sid, UniqueId.Type.sid);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // INSTANCE ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String iid = com.google.android.gms.iid.InstanceID.getInstance(MyApplication.instance()).getId();
    if (!Utils.isNullOrEmpty(iid)) {
        return UniqueId.newInstance(iid, UniqueId.Type.iid);
    }

    return null;
}

public final class UniqueId implements Parcelable {
    public enum Type implements Parcelable {
        aid,
        sid,
        iid,
        eid;

        ////////////////////////////////////////////////////////////////////////////
        // Handling Parcelable nicely.

        public static final Parcelable.Creator<Type> CREATOR = new Parcelable.Creator<Type>() {
            public Type createFromParcel(Parcel in) {
                return Type.valueOf(in.readString());
            }

            public Type[] newArray(int size) {
                return new Type[size];
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeString(this.name());
        }

        // Handling Parcelable nicely.
        ////////////////////////////////////////////////////////////////////////////
    }

    public static boolean isValid(UniqueId uniqueId) {
        if (uniqueId == null) {
            return false;
        }
        return uniqueId.isValid();
    }

    private boolean isValid() {
        return !org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) && type != null;
    }

    private UniqueId(String id, Type type) {
        if (org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) || type == null) {
            throw new java.lang.IllegalArgumentException();
        }
        this.id = id;
        this.type = type;
    }

    public static UniqueId newInstance(String id, Type type) {
        return new UniqueId(id, type);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + id.hashCode();
        result = 31 * result + type.hashCode();
        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }

        if (!(o instanceof UniqueId)) {
            return false;
        }

        UniqueId uniqueId = (UniqueId)o;
        return this.id.equals(uniqueId.id) && this.type == uniqueId.type;
    }

    @Override
    public String toString() {
        return type + ":" + id;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Handling Parcelable nicely.

    public static final Parcelable.Creator<UniqueId> CREATOR = new Parcelable.Creator<UniqueId>() {
        public UniqueId createFromParcel(Parcel in) {
            return new UniqueId(in);
        }

        public UniqueId[] newArray(int size) {
            return new UniqueId[size];
        }
    };

    private UniqueId(Parcel in) {
        this.id = in.readString();
        this.type = in.readParcelable(Type.class.getClassLoader());
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeString(this.id);
        parcel.writeParcelable(this.type, 0);
    }

    // Handling Parcelable nicely.
    ////////////////////////////////////////////////////////////////////////////

    public final String id;
    public final Type type;
}

public static String getEmail() {
    Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
    AccountManager accountManager = AccountManager.get(MyApplication.instance());
    Account[] accounts = accountManager.getAccountsByType("com.google");
    for (Account account : accounts) {
        if (emailPattern.matcher(account.name).matches()) {
            String possibleEmail = account.name;
            return possibleEmail;
        }
    }

    accounts = accountManager.getAccounts();
    for (Account account : accounts) {
        if (emailPattern.matcher(account.name).matches()) {
            String possibleEmail = account.name;
            return possibleEmail;
        }
    }

    return null;
} 

@emmby 2011-04-11 19:06:50

As Dave Webb mentions, the Android Developer Blog has an article that covers this. Their preferred solution is to track app installs rather than devices, and that will work well for most use cases. The blog post will show you the necessary code to make that work, and I recommend you check it out.

However, the blog post goes on to discuss solutions if you need a device identifier rather than an app installation identifier. I spoke with someone at Google to get some additional clarification on a few items in the event that you need to do so. Here's what I discovered about device identifiers that's NOT mentioned in the aforementioned blog post:

  • ANDROID_ID is the preferred device identifier. ANDROID_ID is perfectly reliable on versions of Android <=2.1 or >=2.3. Only 2.2 has the problems mentioned in the post.
  • Several devices by several manufacturers are affected by the ANDROID_ID bug in 2.2.
  • As far as I've been able to determine, all affected devices have the same ANDROID_ID, which is 9774d56d682e549c. Which is also the same device id reported by the emulator, btw.
  • Google believes that OEMs have patched the issue for many or most of their devices, but I was able to verify that as of the beginning of April 2011, at least, it's still quite easy to find devices that have the broken ANDROID_ID.

Based on Google's recommendations, I implemented a class that will generate a unique UUID for each device, using ANDROID_ID as the seed where appropriate, falling back on TelephonyManager.getDeviceId() as necessary, and if that fails, resorting to a randomly generated unique UUID that is persisted across app restarts (but not app re-installations).

Note that for devices that have to fallback on the device ID, the unique ID WILL persist across factory resets. This is something to be aware of. If you need to ensure that a factory reset will reset your unique ID, you may want to consider falling back directly to the random UUID instead of the device ID.

Again, this code is for a device ID, not an app installation ID. For most situations, an app installation ID is probably what you're looking for. But if you do need a device ID, then the following code will probably work for you.

import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;

import java.io.UnsupportedEncodingException;
import java.util.UUID;

public class DeviceUuidFactory {

    protected static final String PREFS_FILE = "device_id.xml";
    protected static final String PREFS_DEVICE_ID = "device_id";
    protected volatile static UUID uuid;

    public DeviceUuidFactory(Context context) {
        if (uuid == null) {
            synchronized (DeviceUuidFactory.class) {
                if (uuid == null) {
                    final SharedPreferences prefs = context
                            .getSharedPreferences(PREFS_FILE, 0);
                    final String id = prefs.getString(PREFS_DEVICE_ID, null);
                    if (id != null) {
                        // Use the ids previously computed and stored in the
                        // prefs file
                        uuid = UUID.fromString(id);
                    } else {
                        final String androidId = Secure.getString(
                            context.getContentResolver(), Secure.ANDROID_ID);
                        // Use the Android ID unless it's broken, in which case
                        // fallback on deviceId,
                        // unless it's not available, then fallback on a random
                        // number which we store to a prefs file
                        try {
                            if (!"9774d56d682e549c".equals(androidId)) {
                                uuid = UUID.nameUUIDFromBytes(androidId
                                        .getBytes("utf8"));
                            } else {
                                final String deviceId = (
                                    (TelephonyManager) context
                                    .getSystemService(Context.TELEPHONY_SERVICE))
                                    .getDeviceId();
                                uuid = deviceId != null ? UUID
                                    .nameUUIDFromBytes(deviceId
                                            .getBytes("utf8")) : UUID
                                    .randomUUID();
                            }
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }
                        // Write the value out to the prefs file
                        prefs.edit()
                                .putString(PREFS_DEVICE_ID, uuid.toString())
                                .commit();
                    }
                }
            }
        }
    }

    /**
     * Returns a unique UUID for the current android device. As with all UUIDs,
     * this unique ID is "very highly likely" to be unique across all Android
     * devices. Much more so than ANDROID_ID is.
     * 
     * The UUID is generated by using ANDROID_ID as the base key if appropriate,
     * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
     * be incorrect, and finally falling back on a random UUID that's persisted
     * to SharedPreferences if getDeviceID() does not return a usable value.
     * 
     * In some rare circumstances, this ID may change. In particular, if the
     * device is factory reset a new device ID may be generated. In addition, if
     * a user upgrades their phone from certain buggy implementations of Android
     * 2.2 to a newer, non-buggy version of Android, the device ID may change.
     * Or, if a user uninstalls your app on a device that has neither a proper
     * Android ID nor a Device ID, this ID may change on reinstallation.
     * 
     * Note that if the code falls back on using TelephonyManager.getDeviceId(),
     * the resulting ID will NOT change after a factory reset. Something to be
     * aware of.
     * 
     * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
     * directly.
     * 
     * @see http://code.google.com/p/android/issues/detail?id=10603
     * 
     * @return a UUID that may be used to uniquely identify your device for most
     *         purposes.
     */
    public UUID getDeviceUuid() {
        return uuid;
    }
}

@Steve Pomeroy 2011-04-11 20:10:05

Shouldn't you be hashing the various IDs so that they're all the same size? Additionally, you should be hashing the device ID in order to not accidentally expose private information.

@Steve Pomeroy 2011-04-11 20:12:15

Also, a device whose configuration causes the Device ID to be used will tie the ID to the device, not necessarily the user. That ID will survive factory resetting, which could be potentially bad. Maybe the Device ID could be hashed with something that reports the time of the last factory reset?

@emmby 2011-04-11 21:53:08

Good points, Steve. I updated the code to always return a UUID. This ensure that a) the generated IDs are always the same size, and b) the android and device IDs are hashed before being returned to avoid accidentally exposing personal information. I also updated the description to note that device ID will persist across factory resets and that this may not be desirable for some users.

@Tim Bray 2011-04-12 04:58:02

I believe you are incorrect; the preferred solution is to track installations, not device identifiers. Your code is substantially longer and more complex than that in the blog post and it's not obvious to me that it adds any value.

@emmby 2011-04-12 12:25:57

Good point, I updated the commentary to strongly suggest users use app installation ids rather than device ids. However, I think this solution is still valuable for people who do need a device rather than installation ID.

@Samuel 2011-05-19 08:12:49

ANDROID_ID can change on factory reset, so it cannot identify devices as well

@David Given 2012-01-25 12:35:27

...and, of course, if ANDROID_ID is not available and wireless is turned off you won't get a device ID.

@Alexis 2012-06-18 13:34:17

I encountered this "9774d56d682e549c" ANDROID_ID on devices with versions 2.2, 2.2.1, 2.2.2, 2.3.3, 2.3.4, 2.3.6

@Marek Sebera 2013-01-17 18:30:00

@jafar on the same device or multiple ones?

@Alexis 2013-01-17 18:35:34

multiple. It's a well-known bug of android 2.2/2.3

@Tony Chan 2013-06-05 00:38:14

Since this method stores and first tries to retrieve the UUID from a SharedPreference file, I think it's prudent to point out that if the user is rooted they can alter the device_id.xml file to provide any id they want. What do you think @emmby ? That said I like the fallbacks you use. I'm also considering using android.os.Build.SERIAL as a fallback for tablets before using the final random number fallback.

@Mr_and_Mrs_D 2013-09-18 12:46:34

As I note on your same answer here there is no guarantee you will get the same generated UUID across processes - the SharedPrefs copy is local !

@Ton 2015-07-13 18:23:49

Hello. It is been a long time since this answer. Is still valid? How long should I have the String variables in my database to keep the generated id? Thanks

@Arslan Anwar 2016-01-15 11:04:43

Did you just day an random number? :O what about when we uninstall the app install it again?

@IHC_Applroid 2016-01-31 04:10:30

is it still valid now for android 6.0.1?

@bnnoor 2019-08-29 06:15:20

permission denied on android 8 and 9 and after . this working only older version of Android

@Jeffy 2017-09-07 14:31:22

String SERIAL_NUMER = Build.SERIAL;

Returns SERIAL NUMBER as a string which unique in each device.

@Ninja 2019-04-02 13:42:26

@Anthony Forloney 2010-05-07 00:49:47

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); 

@Seva Alekseyev 2010-06-23 14:21:59

It's known to be null sometimes, it's documented as "can change upon factory reset". Use at your own risk, and it can be easily changed on a rooted phone.

@user604363 2011-02-05 17:06:05

I think we need to be careful about using ANDROID_ID in hash in first answer about because it may not be set when app is first run, may be set later, or may even change in theory, hence unique ID may change

@emmby 2011-04-07 20:10:26

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

@Girish Patel 2011-09-30 07:18:24

this ANDROID_ID is Only for Android Tab if you can run in phone then you will get null if you will run in Tab then you can get Unique ID.-Girish

@Felipe 2012-02-14 20:55:01

Before decide what is the best solution for you, have a look on the answer stackoverflow.com/a/2853253/450148 - that answer can be improved a bit as well.

@Andrew Wyld 2012-04-02 09:44:00

Just a quick question: the Kindle app registered my phone as three separate devices, one corresponding to each build from Eclair to Froyo. Does this mean updating Android to a later version resets this identifier?

@Zenexer 2012-05-07 05:43:04

Note also that in the context of an Activity or such, "getContext()" can be replaced with "this"--or nothing at all.

@Tom 2012-12-15 19:36:42

ANDROID_ID no longer uniquely identifies a device (as of 4.2): stackoverflow.com/a/13465373/150016

@CanCeylan 2013-12-16 16:08:16

Will we be able to send push notifications via this ID ? Or we also need to get sth like registration_id (stackoverflow.com/questions/13742720/…)

@Dori 2014-03-06 09:23:32

It seems this can also change if a user clears Play Services cached data. androidpolice.com/2013/11/20/… hints to "Doing this changes the primary ID by which Google knows your device. As far as the servers are concerned, the device was basically factory reset." which im assuming is the ANDROID_ID - I cant replicate this in testing however - worth being aware of anyhow...

@macio.Jun 2014-03-31 21:35:24

On nexus 7 if you create another user, then this answer returns a different device id.

@Pratik Butani 2014-04-25 04:59:29

@jiahao 2014-06-01 13:58:01

As Google blog states, Android_ID is not a good option. "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." android-developers.blogspot.com.es/2011/03/…

@Sayed Abolfazl Fatemi 2014-07-09 09:20:52

Salaam. look at @Joe answer http://stackoverflow.com/a/2853253/1676736

@Jorgesys 2015-02-06 14:58:15

Here is a better answer; stackoverflow.com/questions/3802644/…

@Tom 2015-06-19 21:42:17

Things are quite different with ARC (Android on Chrome): a fresh android ID is generated for every installation. See here: stackoverflow.com/questions/29656101/…

@Song 2016-02-25 19:51:20

This solution returns null when the app is installed under managed profile in Android for work.

@Anix PasBesoin 2016-03-14 16:49:49

Do you know how can I obtain the same ID outputted by "Secure.getString(getContext().getContentResolver(),Secure.A‌​NDROID_ID); "directly from my phone? (For the IMEI i would just call: *#06#)

@Atul 2016-05-04 04:57:57

Note that using ANDROID_ID may get you banned from Play Store if you're using that for tracking purposes - it's forbidden by ToS. Google Play Services Advertiser ID is the replacement.

@Nilesh Panchal 2017-04-03 07:02:59

But it can be changed using factory reset or Rooted Phone

@Iman Marashi 2017-04-05 21:05:44

Using getString to get device identifiers is not recommended. WHY?

@EpicPandaForce 2017-04-12 08:26:06

@hmac 2018-05-17 10:31:47

from above link: "In O, Android ID (Settings.Secure.ANDROID_ID or SSAID) has a different value for each app and each user on the device." - just to confirm, if the same google account user is using the same app on two different devices, the Android ID will be different right?

@OzzyTheGiant 2018-09-11 15:31:42

Also, I heard of a bug where some old Motorola Droid phones all displayed the same ANDROID_ID, so it may not be reliable

@Naga 2019-02-22 08:26:47

I have been using Android ID in my app to uniquely identify users coz this I felt is more easy than with routine registration with email id, and so far I have not found any issues with this solution, neither any of our subscribers complain so far, and we know the fallback option will not be so devastating if it happens again it all depends on the kinda app , unless the app needs tight security I think ANDROID ID maynot be a concern

@Aaron Ullal 2019-06-13 09:49:52

@Naga do you know how to lookup the device id from the phone (and not programmatically) ?

@Malwinder Singh 2019-07-24 07:28:01

Android Lint is saying "Using getString to get device identifiers is not recommended. Inspection info:Using these device identifiers is not recommended other than for high value fraud prevention and advanced telephony use-cases. For advertising use-cases, use AdvertisingIdClient$Info#getId and for analytics, use InstanceId#getId.

@Naga 2019-09-03 12:27:33

@AaronUllal sorry little late, no I dont think so, About Phone under the settings has got things like android version, imei, etc, in one of the android phones i checked, maybe this is not so relevant to users than for the Apps

@Zin Win Htet 2017-06-19 15:25:06

Normally, I use device unique id for my apps. But sometime I use IMEI. Both are unique numbers.

to get IMEI (international mobile equipment identifier)

public String getIMEI(Activity activity) {
    TelephonyManager telephonyManager = (TelephonyManager) activity
            .getSystemService(Context.TELEPHONY_SERVICE);
    return telephonyManager.getDeviceId();
}

to get device unique id

public String getDeviceUniqueID(Activity activity){
    String device_unique_id = Secure.getString(activity.getContentResolver(),
            Secure.ANDROID_ID);
    return device_unique_id;
}

@Seva Alekseyev 2010-06-23 14:27:22

Also you might consider the Wi-Fi adapter's MAC address. Retrieved thusly:

WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE);
return wm.getConnectionInfo().getMacAddress();

Requires permission android.permission.ACCESS_WIFI_STATE in the manifest.

Reported to be available even when Wi-Fi is not connected. If Joe from the answer above gives this one a try on his many devices, that'd be nice.

On some devices, it's not available when Wi-Fi is turned off.

NOTE: From Android 6.x, it returns consistent fake mac address: 02:00:00:00:00:00

@ohhorob 2010-11-01 04:41:54

This required android.permission.ACCESS_WIFI_STATE

@Axarydax 2010-12-22 10:28:34

what about wifi-less devices?

@Seva Alekseyev 2010-12-22 14:23:52

They exist? I'd rather envision a telephony-less device (AKA tablet)...

@Jack 2011-08-29 21:27:12

I know this question is old - but this is a great idea. I used the BT mac ID in my app, but only because it requires BT to function. Show me an Android device that's worth developing for that does NOT have WiFi.

@chrisdowney 2012-05-21 23:38:21

I think you'll find that it's unavailable when WiFi is off, on pretty much all android devices. Turning WiFi off removes the device at kernel level.

@Ahmed 2013-01-02 21:45:43

if WIFI is on ? Will it ALWAYS return a valid MAC address ? or still likely to return null or empty ??

@Seva Alekseyev 2013-01-02 22:03:32

2Ahmed: I saw your question. ALWAYS is such a strong word...

@Sanandrea 2013-07-09 21:25:49

Anyway on rooted phones the MAC address can be spoofed

@ocodo 2013-09-04 09:53:14

@Sanandrea - let's face it, on a rooted device EVERYTHING can be spoofed.

@Kartheek s 2014-05-06 07:22:50

is it device unique. when will be change of this number can be expected

@jiahao 2014-06-01 13:55:12

As stated the google blog, MAC is not a good option. "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." android-developers.blogspot.com.es/2011/03/…

@breez 2015-12-22 12:37:39

Accessing WiFi MAC address has been blocked on Android M: stackoverflow.com/questions/31329733/…

@sarika kate 2016-03-30 06:00:36

Most notably, Local WiFi and Bluetooth MAC addresses are no longer available.The getMacAddress() method of aWifiInfo object and the BluetoothAdapter.getDefaultAdapter().getAddress() method will both return02:00:00:00:00:00 from now on

@Alberto M 2016-05-31 11:03:15

some devices can have no wi-fi (personally experienced)

@Behrouz.M 2016-07-10 09:14:47

From Android 6.x it returns consistent fake mac address: 02:00:00:00:00:00

@bugraoral 2017-04-11 08:51:27

Just a heads up for everyone reading looking for more up to date info. With Android O there are some changes to how the system manages these ids.

https://android-developers.googleblog.com/2017/04/changes-to-device-identifiers-in.html

tl;dr Serial will require PHONE permission and Android ID will change for different apps, based on their package name and signature.

And also Google has put together a nice document which provides suggestions about when to use the hardware and software ids.

https://developer.android.com/training/articles/user-data-ids.html

@ᴛʜᴇᴘᴀᴛᴇʟ 2017-03-08 14:01:34

There are 30+ answers here and some are same and some are unique. This answer is based on few of those answers. One of them being @Lenn Dolling's answer.

It combines 3 IDs and creates a 32-digit hex string. It has worked very well for me.

3 IDs are:
Pseudo-ID - It is generated based on physical device specifications
ANDROID_ID - Settings.Secure.ANDROID_ID
Bluetooth Address - Bluetooth adapter address

It will return something like this: 551F27C060712A72730B0A0F734064B1

Note: You can always add more IDs to the longId string. For example, Serial #. wifi adapter address. IMEI. This way you are making it more unique per device.

@SuppressWarnings("deprecation")
@SuppressLint("HardwareIds")
public static String generateDeviceIdentifier(Context context) {

        String pseudoId = "35" +
                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;

        String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        String btId = "";

        if (bluetoothAdapter != null) {
            btId = bluetoothAdapter.getAddress();
        }

        String longId = pseudoId + androidId + btId;

        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(longId.getBytes(), 0, longId.length());

            // get md5 bytes
            byte md5Bytes[] = messageDigest.digest();

            // creating a hex string
            String identifier = "";

            for (byte md5Byte : md5Bytes) {
                int b = (0xFF & md5Byte);

                // if it is a single digit, make sure it have 0 in front (proper padding)
                if (b <= 0xF) {
                    identifier += "0";
                }

                // add number to string
                identifier += Integer.toHexString(b);
            }

            // hex string to uppercase
            identifier = identifier.toUpperCase();
            return identifier;
        } catch (Exception e) {
            Log.e("TAG", e.toString());
        }
        return "";
}

@Mousa Alfhaily 2017-04-11 07:08:32

Adding the UUID to the longId and store it in a file, will make it the most unique identifier : String uuid = UUID.randomUUID().toString();

@Mousa Alfhaily 2017-04-11 07:17:53

If all else fails, if the user does have lower than API 9 (lower than Gingerbread), has reset their phone or 'Secure.ANDROID_ID'. if returns 'null', then simply the ID returned will be solely based off their Android device information. This is where the collisions can happen. Try not to use DISPLAY, HOST or ID - these items could change. If there are collisions, there will be overlapping data. The source : gist.github.com/pedja1/fe69e8a80ed505500caa

@Ninja 2019-04-03 06:06:46

If we try to get Unique number by this line of code can we say that is It Unique Id and it will never conflict with any other device ?

@ᴛʜᴇᴘᴀᴛᴇʟ 2019-04-03 12:38:35

@Ninja Since BLE mac address is unique, yes the ID generated will always be unique. However, if you really want to be sure, I would suggest to add a UUID to the longId. Change that one line like this: String longId = pseudoId + androidId + btId + UUID.randomUUID().toString(); This guarantees that generated ID will be unique.

@Ninja 2019-04-05 05:32:32

@ᴛʜᴇᴘᴀᴛᴇʟ Thanks you so much for this huge help. Actually my app very sensitive data so i need to sure about it that's why i am just confirming this things.

@Baskaran Veerabathiran 2016-10-03 11:02:10

Android device mac id also a unique id, it won't change suppose if we format the device itself so using the following code to get mac id

WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();
String address = info.getMacAddress();

Also do not forget to add the appropriate permissions into your AndroidManifest.xml

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

@Ted Hopp 2016-10-05 00:32:14

Unfortunately, this won't work if there is no current WiFi connection. From the docs (emphasis added): "Return dynamic information about the current Wi-Fi connection, if any is active."

@user6796473 2017-07-03 16:33:35

Also by granting root access on device, one can spoof mac address

@mumu123 2016-06-07 03:35:16

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.

@Sergii 2017-01-27 11:22:56

this answer is a copypaste from the old google blog android-developers.googleblog.com/2011/03/…. So the bug is already resolved?

@Asaf Pinhassi 2013-04-15 13:01:21

I use the following code to get the IMEI or use Secure.ANDROID_ID as an alternative, when the device doesn't have phone capabilities:

String identifier = null;
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE));
if (tm != null)
      identifier = tm.getDeviceId();
if (identifier == null || identifier .length() == 0)
      identifier = Secure.getString(activity.getContentResolver(),Secure.ANDROID_ID);

@Ilan.b 2015-09-01 12:32:39

For hardware recognition of a specific Android device you could check the MAC Addresses.

you can do it that way:

in AndroidManifest.xml

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

now in your code:

List<NetworkInterface> interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces());

for (NetworkInterface interface : interfacesList) {
   // This will give you the interface MAC ADDRESS
   interface.getHardwareAddress();
}

In every Android device their is at least a "wlan0" Interface witch is the WI-FI chip. This code works even when WI-FI is not turned on.

P.S. Their are a bunch of other Interfaces you will get from the list containing MACS But this can change between phones.

@Tom 2015-06-19 22:22:28

Google Instance ID

Released at I/O 2015; on Android requires play services 7.5.

https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-implementation

InstanceID iid = InstanceID.getInstance( context );   // Google docs are wrong - this requires context
String id = iid.getId();  // blocking call

It seems that Google intends for this ID to be used to identify installations across Android, Chrome, and iOS.

It identifies an installation rather then a device, but then again, ANDROID_ID (which is the accepted answer) now no longer identifies devices either. With the ARC runtime a new ANDROID_ID is generated for every installation (details here), just like this new instance ID. Also, I think that identifying installations (not devices) is what most of us are actually looking for.

The advantages of instance ID

It appears to me that Google intends for it to be used for this purpose (identifying your installations), it is cross-platform, and can be used for a number of other purposes (see the links above).

If you use GCM, then you will eventually need to use this instance ID because you need it in order to get the GCM token (which replaces the old GCM registration ID).

The disadvantages/issues

In the current implementation (GPS 7.5) the instance ID is retrieved from a server when your app requests it. This means that the call above is a blocking call - in my unscientific testing it takes 1-3 seconds if the device is online, and 0.5 - 1.0 seconds if off-line (presumably this is how long it waits before giving up and generating a random ID). This was tested in North America on Nexus 5 with Android 5.1.1 and GPS 7.5.

If you use the ID for the purposes they intend - eg. app authentication, app identification, GCM - I think this 1-3 seconds could be a nuisance (depending on your app, of course).

@idanakav 2015-07-08 16:13:31

another significant downside of instanceID is that a new instanceID will be generated for you if the user clears the data of the app.

@Tom 2015-07-08 20:11:53

Interesting, but I don't think it really changes the potential use-cases: instance ID, like android_id, is not suited to identifying a device. So your server will see user clearing data as like user uninstalling and re-installing your app - which is not unreasonable.

@Jorgesys 2014-01-13 00:30:48

The unique device ID of an Android OS device as String, using TelephonyManager and ANDROID_ID, is obtained by:

String deviceId;
final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephony.getDeviceId() != null) {
    deviceId = mTelephony.getDeviceId();
}
else {
    deviceId = Secure.getString(
                   getApplicationContext().getContentResolver(),
                   Secure.ANDROID_ID);
}

But I strongly recommend a method suggested by Google, see Identifying App Installations.

@Android 2013-02-27 10:03:18

Add Below code in class file:

final TelephonyManager tm = (TelephonyManager) getBaseContext()
            .getSystemService(SplashActivity.TELEPHONY_SERVICE);
    final String tmDevice, tmSerial, androidId;
    tmDevice = "" + tm.getDeviceId();
    Log.v("DeviceIMEI", "" + tmDevice);
    tmSerial = "" + tm.getSimSerialNumber();
    Log.v("GSM devices Serial Number[simcard] ", "" + tmSerial);
    androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(),
            android.provider.Settings.Secure.ANDROID_ID);
    Log.v("androidId CDMA devices", "" + androidId);
    UUID deviceUuid = new UUID(androidId.hashCode(),
            ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
    String deviceId = deviceUuid.toString();
    Log.v("deviceIdUUID universally unique identifier", "" + deviceId);
    String deviceModelName = android.os.Build.MODEL;
    Log.v("Model Name", "" + deviceModelName);
    String deviceUSER = android.os.Build.USER;
    Log.v("Name USER", "" + deviceUSER);
    String devicePRODUCT = android.os.Build.PRODUCT;
    Log.v("PRODUCT", "" + devicePRODUCT);
    String deviceHARDWARE = android.os.Build.HARDWARE;
    Log.v("HARDWARE", "" + deviceHARDWARE);
    String deviceBRAND = android.os.Build.BRAND;
    Log.v("BRAND", "" + deviceBRAND);
    String myVersion = android.os.Build.VERSION.RELEASE;
    Log.v("VERSION.RELEASE", "" + myVersion);
    int sdkVersion = android.os.Build.VERSION.SDK_INT;
    Log.v("VERSION.SDK_INT", "" + sdkVersion);

Add in AndroidManifest.xml:

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

@Jorgesys 2015-02-06 15:00:25

TelephonyManger.getDeviceId() Returns the unique device ID, for example, the IMEI for GSM and the MEID or ESN for CDMA phones.

final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);            
String myAndroidDeviceId = mTelephony.getDeviceId(); 

But i recommend to use:

Settings.Secure.ANDROID_ID that returns the Android ID as an unique 64-bit hex string.

    String   myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

Sometimes TelephonyManger.getDeviceId() will return null, so to assure an unique id you will use this method:

public String getUniqueID(){    
    String myAndroidDeviceId = "";
    TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    if (mTelephony.getDeviceId() != null){
        myAndroidDeviceId = mTelephony.getDeviceId(); 
    }else{
         myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
    }
    return myAndroidDeviceId;
}

@Holger Jakobs 2016-03-13 16:16:34

I recently discovered that a client's device of type SM-G928F / Galaxy S6 edge+ delivers only 15 instead of 16 hex digits for the Android ID.

Related Questions

Sponsored Content

25 Answered Questions

[SOLVED] Is there a way to run Python on Android?

51 Answered Questions

[SOLVED] Stop EditText from gaining focus at Activity startup

97 Answered Questions

33 Answered Questions

30 Answered Questions

28 Answered Questions

[SOLVED] What is 'Context' on Android?

31 Answered Questions

[SOLVED] Activity restart on rotation Android

77 Answered Questions

11 Answered Questions

[SOLVED] Proper use cases for Android UserManager.isUserAGoat()?

8 Answered Questions

[SOLVED] Android error: Failed to install *.apk on device *: timeout

Sponsored Content