Is there a unique Android device ID?

Android设备是否有唯一的ID,如果有,使用Java访问它的简单方法是什么?


Settings.Secure#ANDROID_ID将Android ID作为每个用户的64位十六进制字符串的唯一返回值。

import android.provider.Settings.Secure;

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

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

  • All devices tested returned a value for TelephonyManager.getDeviceId()
  • All GSM devices (all tested with a SIM) returned a value for TelephonyManager.getSimSerialNumber()
  • All CDMA devices returned null for getSimSerialNumber() (as expected)
  • All devices with a Google account added returned a value for ANDROID_ID
  • 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.
  • 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;
    

    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

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

  • User's 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 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 you own unanimous 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 do is 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 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/

    链接地址: http://www.djcxy.com/p/618.html

    上一篇: 将具有默认值的列添加到SQL Server中的现有表

    下一篇: 是否有唯一的Android设备ID?