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


当前回答

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

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

其他回答

在类文件中添加以下代码:

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

插件AndroidManifest.xml:

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

API级别9(Android 2.3-姜饼)中的Build类中添加了一个Serial字段。文档表示它代表硬件序列号。因此,如果设备上存在,它应该是唯一的。

我不知道API级别>=9的所有设备是否都支持(=不为空)。

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

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

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

1.使用提供唯一id(即IMEI)的电话管理器。参见示例,

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

这需要为您的用户提供android.permission.READ_PHONE_STATE,这很难证明遵循您所做的应用程序类型。

没有电话服务的设备(如平板电脑)必须报告一个唯一的设备ID,该ID可以通过android.os.Build.SERIAL从android 2.3 Gingerbread获得。一些具有电话服务的电话还可以定义序列号。就像不是所有的Android设备都有序列号一样,这种解决方案并不可靠。在设备首次启动时,会生成并存储一个随机值。此值可通过Settings.Secure.ANDROID_ID获得。它是一个64位数字,在设备的生命周期内应保持不变。ANDROID_ID似乎是唯一设备标识符的好选择,因为它适用于智能手机和平板电脑。要检索值,可以使用以下代码:,StringandroidId=Settings.Secure.getString(getContentResolver(),Settings.Secure.ANDROID_ID);

但是,如果在设备上执行出厂重置,则该值可能会更改。制造商的流行手机也存在一个已知的缺陷,每个实例都有相同的ANDROID_ID。显然,该解决方案并非100%可靠。

使用UUID。由于大多数应用程序的要求是识别特定的安装,而不是物理设备,因此,如果使用UUID类,获取用户的唯一id是一个很好的解决方案。以下解决方案由来自Google的Reto Meier在Google I/O演示中提出,

SharedPreferences sharedPrefs = context.getSharedPreferences(
         PREF_UNIQUE_ID, Context.MODE_PRIVATE);
uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);

更新:选项#1和#2在android 10之后不再可用,因为谷歌进行了隐私更新。因为选项2和3需要关键许可。

有关如何为安装应用程序的每个Android设备获取唯一标识符的详细说明,请参阅官方Android开发者博客“识别应用程序安装”。

似乎最好的方法是在安装时自己生成一个,然后在重新启动应用程序时读取它。

我个人认为这是可以接受的,但并不理想。Android提供的标识符在所有情况下都不起作用,因为大多数都取决于手机的无线电状态(Wi-Fi开/关、手机开/关和蓝牙开/关)。其他设置(如Settings.Secure.ANDROID_ID)必须由制造商实现,并且不保证是唯一的。

以下是将数据写入安装文件的示例,该文件将与应用程序本地保存的任何其他数据一起存储。

public class Installation {
    private static String sID = null;
    private static final String INSTALLATION = "INSTALLATION";

    public synchronized static String id(Context context) {
        if (sID == null) {
            File installation = new File(context.getFilesDir(), INSTALLATION);
            try {
                if (!installation.exists())
                    writeInstallationFile(installation);
                sID = readInstallationFile(installation);
            } 
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return sID;
    }

    private static String readInstallationFile(File installation) throws IOException {
        RandomAccessFile f = new RandomAccessFile(installation, "r");
        byte[] bytes = new byte[(int) f.length()];
        f.readFully(bytes);
        f.close();
        return new String(bytes);
    }

    private static void writeInstallationFile(File installation) throws IOException {
        FileOutputStream out = new FileOutputStream(installation);
        String id = UUID.randomUUID().toString();
        out.write(id.getBytes());
        out.close();
    }
}