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


当前回答

只获取一次设备ID,然后将其存储在数据库或文件中。在这种情况下,如果它是应用程序的第一次启动,它将生成一个ID并存储它。下次,它将只获取存储在文件中的ID。

其他回答

为了完整起见,以下是如何在Xamarin.Android和C#中获取Id:

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

或者如果您不在“活动”中:

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

其中上下文是传入的上下文。

Android设备mac id也是唯一的id。即使设备本身被格式化,它也不会改变。

使用以下代码获取mac id:

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

此外,不要忘记将适当的权限添加到AndroidManifest.xml:

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

这里有相当有用的信息。

它包括五种不同的ID类型:

IMEI(仅适用于使用手机的Android设备;需要Android.permission.READ_Phone_STATE)伪唯一ID(适用于所有Android设备)Android ID(可以为空,可以在工厂重置时更改,可以在根手机上更改)WLAN MAC地址字符串(需要android.permission.ACCESS_WIFI_STATE)BT MAC地址字符串(带蓝牙的设备,需要android.permission.蓝牙)

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

有很多不同的方法可以解决ANDROID_ID问题(有时可能为空,或者特定型号的设备总是返回相同的ID),有利弊:

实现自定义ID生成算法(基于应该是静态且不会更改的设备财产->谁知道呢)滥用其他ID,如IMEI、序列号、Wi-Fi/蓝牙MAC地址(它们不会存在于所有设备上,或者需要额外的权限)

我自己更喜欢使用现有的OpenUDID实现(请参见https://github.com/ylechelle/OpenUDID)适用于Android(请参见https://github.com/vieux/OpenUDID). 它很容易集成并利用ANDROID_ID和上述问题的回退。