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


当前回答

在Google I/O上,Reto Meier发布了一个关于如何实现这一点的有力答案,这应该能满足大多数开发人员在安装过程中跟踪用户的需求。安东尼·诺兰(Anthony Nolan)在他的回答中指明了方向,但我想我应该写出完整的方法,这样其他人就可以很容易地看到如何做到这一点(我花了一段时间才弄清楚细节)。

这种方法将为您提供一个匿名、安全的用户ID,该ID将在不同设备(基于主要的Google帐户)和不同安装中为用户持久保存。基本方法是生成一个随机用户ID,并将其存储在应用程序的共享偏好中。然后使用Google的备份代理将链接到Google帐户的共享首选项存储在云中。

让我们了解一下完整的方法。首先,我们需要使用Android备份服务为SharedPreferences创建备份。通过注册应用程序开始http://developer.android.com/google/backup/signup.html.

谷歌会给你一个备份服务密钥,你需要将其添加到清单中。您还需要告诉应用程序使用BackupAgent,如下所示:

<application android:label="MyApplication"
         android:backupAgent="MyBackupAgent">
    ...
    <meta-data android:name="com.google.android.backup.api_key"
        android:value="your_backup_service_key" />
</application>

然后,您需要创建备份代理,并告诉它使用helper代理进行共享引用:

public class MyBackupAgent extends BackupAgentHelper {
    // The name of the SharedPreferences file
    static final String PREFS = "user_preferences";

    // A key to uniquely identify the set of backup data
    static final String PREFS_BACKUP_KEY = "prefs";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this,          PREFS);
        addHelper(PREFS_BACKUP_KEY, helper);
    }
}

要完成备份,您需要在主活动中创建BackupManager实例:

BackupManager backupManager = new BackupManager(context);

最后创建一个用户ID(如果它还不存在),并将其存储在SharedPreferences中:

  public static String getUserID(Context context) {
            private static String uniqueID = null;
        private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                MyBackupAgent.PREFS, 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();

            //backup the changes
            BackupManager mBackupManager = new BackupManager(context);
            mBackupManager.dataChanged();
        }
    }

    return uniqueID;
}

即使用户移动设备,此User_ID现在也将在安装过程中保持不变。

有关此方法的更多信息,请参阅Reto的演讲。

有关如何实施备份代理的详细信息,请参阅数据备份。我特别推荐底部的测试部分,因为备份不会立即发生,所以为了测试,必须强制备份。

其他回答

更新:在最近的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;

只是提醒大家阅读更多最新信息。对于Android O,系统管理这些ID的方式有一些变化。

https://android-developers.googleblog.com/2017/04/changes-to-device-identifiers-in.html

tl;dr Serial将需要PHONE权限,Android ID将根据不同的应用程序的包名和签名进行更改。

此外,谷歌还编制了一份很好的文档,提供了有关何时使用硬件和软件ID的建议。

https://developer.android.com/training/articles/user-data-ids.html

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

您将通过使用以下代码获得wifi mac地址,无论您在尝试连接到wifi时是否使用了随机地址,也无论wifi是否打开或关闭。

我使用了下面链接中的一个方法,并添加了一个小修改,以获得准确的地址,而不是随机化的地址:

在Android 6.0中获取MAC地址

public static String getMacAddr() {
StringBuilder res1 = new StringBuilder();
try {
List<NetworkInterface> all =     
Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nif : all) {    
if (!nif.getName().equalsIgnoreCase("p2p0")) continue;

        byte[] macBytes = nif.getHardwareAddress();
        if (macBytes == null) {
            continue;
        }

        res1 = new StringBuilder();
        for (byte b : macBytes) {
            res1.append(String.format("%02X:",b));
        }

        if (res1.length() > 0) {
            res1.deleteCharAt(res1.length() - 1);
        }
    }
} catch (Exception ex) {
}
return res1.toString();

}

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