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


当前回答

是的,每个Android设备都有一个唯一的序列号,你可以从这个代码中得到它。Build.SERIAL。请注意,它只是在API级别9中添加的,可能不会出现在所有设备上。要在早期平台上获得唯一ID,您需要读取MAC地址或IMEI等信息。

其他回答

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

生成设备标识符

 private String generateDeviceIdentifier() {
    String uniqueDevicePseudoID = "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(uniqueDevicePseudoID.hashCode(), serial.hashCode()).toString();
    Log.e("DeviceIdentifier ", "\nDeviceIdentifier uuid is : " + uuid);
    return uuid;
}

输出

DeviceIdentifier uuid is : 00000000-36ab-9c3c-0000-0000714a4f37

此外,您还可以考虑Wi-Fi适配器的MAC地址。检索方式如下:

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

清单中需要权限android.permission.ACCESS_WIFI_STATE。

据报道,即使未连接Wi-Fi,也可用。如果上面的答案中的乔在他的许多设备上尝试一下,那就太好了。

在某些设备上,当Wi-Fi关闭时,它不可用。

注意:从Android6.x,它返回一致的假mac地址:02:00:00:00:00

不建议使用,因为deviceId可以在第三方手中用作跟踪,但这是另一种方式。

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

这是Reto Meier在今年的Google I/O演示中使用的代码,用于为用户获取唯一id:

private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";

public synchronized static String id(Context context) {
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                PREF_UNIQUE_ID, Context.MODE_PRIVATE);
        uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
        if (uniqueID == null) {
            uniqueID = UUID.randomUUID().toString();
            Editor editor = sharedPrefs.edit();
            editor.putString(PREF_UNIQUE_ID, uniqueID);
            editor.commit();
        }
    }
    return uniqueID;
}

如果你将此与备份策略相结合,将首选项发送到云(Reto的演讲中也有描述),你应该有一个与用户相关的id,在设备被擦除甚至更换后,它会一直存在。我计划在未来的分析中使用此项(换句话说,我还没有做过这一点:)。