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


当前回答

这个示例演示了如何在Android中获取和存储设备ID,但我使用的是Kotlin。

      val textView: TextView = findViewById(R.id.textView)
      val uniqueId: String = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
      textView.text = "Device ID: $uniqueId"

其他回答

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

import android.provider.Settings.Secure;

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

另请阅读唯一标识符的最佳实践:https://developer.android.com/training/articles/user-data-ids

更新:在最近的Android版本中,Android_ID的许多问题已经得到解决,我相信这种方法不再是必要的。请看一下安东尼的回答。

完整披露:我的应用程序最初使用了以下方法,但现在不再使用这种方法,我们现在使用了emmby的答案链接所指向的Android开发者博客条目中概述的方法(即,生成并保存UUID#randomUUID())。


这个问题有很多答案,其中大多数只在“某些”时间有效,不幸的是,这还不够好。

根据我对设备的测试(所有手机,至少有一部未激活):

所有测试的设备都返回了TelephonyManager.getDeviceId()的值所有GSM设备(均使用SIM进行测试)都返回了TelephonyManager.getSimSerialNumber()的值对于getSimSerialNumber(),所有CDMA设备均返回null(如预期)添加了Google帐户的所有设备都返回了ANDROID_ID的值所有CDMA设备都为ANDROID_ID和TelephonyManager.getDeviceId()返回相同的值(或相同值的派生)——只要在安装过程中添加了Google帐户。我还没有机会测试没有SIM卡的GSM设备,没有添加谷歌账户的GSM设备或任何处于飞行模式的设备。

因此,如果您想要设备本身独有的东西,TM.getDeviceId()就足够了。显然,有些用户比其他用户更偏执,因此对这些标识符中的一个或多个进行散列可能会很有用,这样该字符串对于设备来说实际上仍然是唯一的,但不会明确标识用户的实际设备。例如,使用String.hashCode()并结合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();

可能会导致类似的结果:00000000-54b3-e7c7-0000-000046bffd97

这对我来说足够好了。

正如Richard在下面提到的那样,不要忘记您需要权限才能读取TelephonyManager财产,因此请将此添加到您的清单中:

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

导入库

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

正如DaveWebb提到的,Android开发者博客有一篇文章介绍了这一点。他们的首选解决方案是跟踪应用程序安装而不是设备,这对于大多数使用情况都很有效。博客文章将向您展示实现这一功能所需的代码,我建议您查看一下。

然而,如果您需要设备标识符而不是应用程序安装标识符,博客文章将继续讨论解决方案。我与谷歌的某位人士进行了交谈,以获得一些额外的澄清,以防您需要这样做。以下是我发现的有关设备标识符的信息,这些信息在上述博客文章中没有提及:

ANDROID_ID是首选设备标识符。ANDROID_ID在ANDROID<=2.1或>=2.3版本上非常可靠。只有2.2存在帖子中提到的问题。多个制造商的多个设备受到2.2中ANDROID_ID错误的影响。据我所知,所有受影响的设备都具有相同的ANDROID_ID,即9774d56d682e549c。顺便说一下,这也是模拟器报告的相同设备id。谷歌相信,原始设备制造商已经为他们的许多或大部分设备修补了这个问题,但我能够证实,至少在2011年4月初,找到ANDROID_ID损坏的设备仍然很容易。

根据谷歌的建议,我实现了一个类,该类将为每个设备生成一个唯一的UUID,在适当的情况下使用ANDROID_ID作为种子,必要时返回TelephonyManager.getDeviceId(),如果失败,则使用随机生成的唯一UUID,该UUID将在应用程序重新启动(但不是应用程序重新安装)期间保持。

请注意,对于必须在设备ID上回退的设备,唯一ID将在出厂重置期间保持。这是需要注意的。如果您需要确保出厂重置将重置您的唯一ID,您可能需要考虑直接返回到随机UUID而不是设备ID。

同样,此代码用于设备ID,而不是应用安装ID。对于大多数情况,应用安装ID可能是您要查找的。但是,如果您确实需要设备ID,那么下面的代码可能适用于您。

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

借助以下功能获取设备UUID、型号、品牌名称及其版本号。

在Android 10中完美工作,无需允许读取手机状态权限。

代码段:

private void fetchDeviceInfo() {
    String uniquePseudoID = "35" +
            Build.BOARD.length() % 10 +
            Build.BRAND.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 serial = Build.getRadioVersion();
    String uuid=new UUID(uniquePseudoID.hashCode(), serial.hashCode()).toString();
    String brand=Build.BRAND;
    String modelno=Build.MODEL;
    String version=Build.VERSION.RELEASE;
    Log.e(TAG, "fetchDeviceInfo: \n "+
            "\n uuid is : "+uuid+
            "\n brand is: "+brand+
            "\n model is: "+modelno+
            "\n version is: "+version);
}

调用Above函数并检查上述代码的输出。请在android工作室中查看您的日志猫。如下所示:

检查系统信息设备唯一标识符

文档:http://docs.unity3d.com/Documentation/ScriptReference/SystemInfo-deviceUniqueIdentifier.html

唯一的设备标识符。它保证对每个设备都是唯一的(只读)。

iOS:在iOS7之前的设备上,它将返回MAC地址的哈希。在iOS7设备上,它将是UIDevice identifierForVendor,如果由于任何原因失败,则是ASIdentifierManager advertisingIdentifier。