安卓设备的唯一标识符

53

我想获取Android设备的唯一标识符。我已经尝试使用以下代码

String ts = Context.TELEPHONY_SERVICE;
TelephonyManager telephonyManager = (TelephonyManager) this.getSystemService(ts);

但是我知道这只适用于手机。

那么如果我的应用程序在笔记本电脑、小型笔记本电脑或其他类型的设备上运行怎么办?在这种情况下,如何获取唯一标识符?


2
@Mudassir:所以你基本上想要的是一些“铁板钉钉”,“硬编码”的东西,它永远不会改变,并且是100%可靠的吗?英特尔试过了...阅读这篇文章schneier.com/essay-187.html - Squonk
@MisterSquonk 我想要类似的东西。我喜欢“set in stone”。 :-) - Mudassir
@Mudassir:祝你好运,但如果你能找到它,我会感到惊讶。最多,我会从最不可能被更改/黑客攻击的事物原则出发,用作为尽可能“独特”的基础,然后尝试编写代码来弥补沿途遇到的任何问题。 - Squonk
已经在 https://dev59.com/CnE95IYBdhLWcg3wadOq 上提问。 - rds
2
@rds:我知道这个问题已经被问过了,而且我也尝试了之前帖子中提供的解决方案,正如我在问题中所提到的。但我的标准是不同的。 - Mudassir
@rds:您链接的问题是关于检索安卓序列号的具体问题。而这个问题则是关于获取一种在非安卓设备上也可用的ID的具体问题。 - Greg Sansom
13个回答

46

在安卓手机上有三种标识符。

  1. IMEI
  2. IMSI

String ts = Context.TELEPHONY_SERVICE;
TelephonyManager mTelephonyMgr = (TelephonyManager) getSystemService(ts);
String imsi = mTelephonyMgr.getSubscriberId();
String imei = mTelephonyMgr.getDeviceId();
  • Android ID是在设备第一次启动时生成的一个64位十六进制字符串。 通常情况下,除非进行恢复出厂设置,否则不会更改。

  • Secure.getString(getContentResolver(), Secure.ANDROID_ID);
    

    3
    更新3: 字符串unique_id = android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); 参考:http://developer.android.com/reference/android/provider/Settings.Secure.html#ANDROID_ID - Pankaj Kumar

    41

    很抱歉打扰了一个旧帖子,但这个问题令我头痛。我找到了一篇好的文章供大家阅读,这确实帮了我很多。

    在Android应用程序开发中,有时需要获取基于Android的智能手机设备的唯一标识符。这在用户想要跟踪应用程序的唯一设备安装情况的情况下是必要的。

    这在Android开发人员想要仅向少数特定设备发送推送消息的情况下也很有用。因此,在这里对每个设备都拥有一个UDID变得必要。

    在Android中,有许多替代设备UDID的方法。以下列出了一些获取Android应用程序中UDID的方法及其优缺点以及获取设备ID所需的任何必要权限:

    • IMEI:(国际移动设备身份码)
    • Android ID
    • WLAN MAC地址字符串
    • 蓝牙地址字符串

    1)IMEI:(International Mobile Equipment Identity)

    IMEI号码是获取设备ID的非常好的主要来源。它对于每个设备都是唯一的,并且依赖于设备硬件。因此,它对于每个设备都是唯一的,并且在设备的整个生命周期内都是永久的。

    获取设备IMEI的代码片段如下:

    TelephonyManager TelephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
    String m_deviceId = TelephonyMgr.getDeviceId();
    

    为此,您的应用程序将需要在清单文件中给予“android.permission.READ_PHONE_STATE”权限。

    使用IMEI作为设备标识的优点:

    IMEI对于每个设备都是唯一的。 即使重新安装应用程序或设备进行根刷或出厂设置,它仍然是该设备的唯一标识。

    使用IMEI作为设备标识的缺点:

    IMEI依赖于设备的Sim卡槽,因此无法为不使用Sim卡的设备获取IMEI。 在双卡设备中,我们为同一设备获取2个不同的IMEI,因为它有2个Sim卡槽。

    2) Android ID

    Android_ID是在设备首次启动时生成和存储的唯一64位数字。当设备恢复出厂设置时,Android_ID会被清除并重新生成。

    以下是获取Android_ID的代码:

    String m_androidId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
    

    使用Android_ID作为设备ID的优点:

    它是所有类型设备(智能手机和平板电脑)的唯一标识符。无需任何权限。

    它在所有设备上保持唯一,并且适用于没有Sim卡槽的手机。

    使用Android_ID作为设备ID的缺点:

    如果用户升级了Android操作系统版本,则可能会更改此ID。如果设备被root或设备进行了出厂设置,则ID将发生更改。此外,已知某些中国Android设备制造商存在同一Android_ID的问题。

    3)WLAN MAC地址字符串

    我们还可以使用WLAN MAC地址获取Android手机的唯一ID。MAC地址对于所有设备都是唯一的,并且适用于所有类型的设备。

    以下是获取设备WLAN MAC地址的代码片段:

    WifiManager m_wm = (WifiManager)getSystemService(Context.WIFI_SERVICE); 
    String m_wlanMacAdd = m_wm.getConnectionInfo().getMacAddress();
    

    您的应用程序需要在清单文件中授予“android.permission.ACCESS_WIFI_STATE”权限。

    使用 WLAN MAC 地址作为设备标识符的优点:

    它是所有类型的设备(智能手机和平板电脑)的唯一标识符。 如果重新安装应用程序,它仍然是唯一的。

    将 WLAN MAC 地址用作设备标识符的缺点:

    如果设备没有 WiFi 硬件,则会得到空 MAC 地址,但通常情况下,大多数 Android 设备都有 WiFi 硬件,并且市场上几乎没有没有 WiFi 硬件的设备。

    4) 蓝牙地址字符串

    我们还可以使用 Bluetooth 设备获取 Android 手机的唯一 ID。每个具有蓝牙硬件的设备的蓝牙设备地址都是唯一的。

    获取 Bluetooth 设备地址的代码片段如下所示,

    BluetoothAdapter m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
    String m_bluetoothAdd = m_BluetoothAdapter.getAddress();
    

    要获取上述代码,您的应用程序需要在清单文件中授予“android.permission.BLUETOOTH”权限。

    使用蓝牙设备地址作为设备ID的优点: 它是所有类型设备(智能手机和平板电脑)的唯一标识符。 所有设备通常只有一个蓝牙硬件,并且它不会更改。

    使用蓝牙设备地址作为设备ID的缺点: 如果设备没有蓝牙硬件,则会得到null。

    我认为这些是用于获取Android智能手机设备的唯一设备ID的几种最佳方法以及使用它们的优缺点。现在轮到您根据Android应用程序开发需求来决定使用哪种方法。

    如果还有其他获取UDID的方法,并且可以弥补上述方法的缺点,那么我很乐意在我的Android应用程序中尝试这些方法。请在评论框中分享,并提出任何建议或疑问。

    这是文章链接


    24
    Secure.getString(getContentResolver(), Secure.ANDROID_ID);
    

    这并不适用于所有设备。

    一些安卓设备存在问题,当我们尝试获取设备ID时,某些设备会返回null。解决这个问题的唯一方法是自己生成一个伪设备ID。这个函数将为您生成一个唯一的设备ID。您可以根据需要更改此函数。我也曾为解决这个问题而苦苦挣扎。

    public String getDeviceID() {
    
    /*String Return_DeviceID = USERNAME_and_PASSWORD.getString(DeviceID_key,"Guest");
    return Return_DeviceID;*/
    
    TelephonyManager TelephonyMgr = (TelephonyManager) getApplicationContext().getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
    String m_szImei = TelephonyMgr.getDeviceId(); // Requires
    // READ_PHONE_STATE
    
    // 2 compute DEVICE ID
    String m_szDevIDShort = "35"
    + // we make this look like a valid IMEI
    Build.BOARD.length() % 10 + Build.BRAND.length() % 10
    + Build.CPU_ABI.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; // 13 digits
    // 3 android ID - unreliable
    String m_szAndroidID = Secure.getString(getContentResolver(),Secure.ANDROID_ID);
    // 4 wifi manager, read MAC address - requires
    // android.permission.ACCESS_WIFI_STATE or comes as null
    WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
    String m_szWLANMAC = wm.getConnectionInfo().getMacAddress();
    // 5 Bluetooth MAC address android.permission.BLUETOOTH required
    BluetoothAdapter m_BluetoothAdapter = null; // Local Bluetooth adapter
    m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    String m_szBTMAC = m_BluetoothAdapter.getAddress();
    System.out.println("m_szBTMAC "+m_szBTMAC);
    
    // 6 SUM THE IDs
    String m_szLongID = m_szImei + m_szDevIDShort + m_szAndroidID+ m_szWLANMAC + m_szBTMAC;
    System.out.println("m_szLongID "+m_szLongID);
    MessageDigest m = null;
    try {
    m = MessageDigest.getInstance("MD5");
    } catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
                    }
    m.update(m_szLongID.getBytes(), 0, m_szLongID.length());
    byte p_md5Data[] = m.digest();
    
    String m_szUniqueID = new String();
    for (int i = 0; i < p_md5Data.length; i++) {
    int b = (0xFF & p_md5Data[i]);
    // if it is a single digit, make sure it have 0 in front (proper
    // padding)
    if (b <= 0xF)
    m_szUniqueID += "0";
    // add number to string
    m_szUniqueID += Integer.toHexString(b);
    }
    m_szUniqueID = m_szUniqueID.toUpperCase();
    
    Log.i("-------------DeviceID------------", m_szUniqueID);
    Log.d("DeviceIdCheck", "DeviceId that generated MPreferenceActivity:"+m_szUniqueID);
    
    return m_szUniqueID;
    
    }
    

    如果你翻译正确,请接受答案...很高兴能帮到你:-) - Sreedev
    这个生成的ID即使设备重启后也是一样的吗? - user7176550
    这个问题在于设备ID在应用重新安装后不会保留,并且由于设备自动生成,它永远不会是唯一的。在我的情况下,我只希望有一个可靠的ID,用于解决我的应用程序问题,并且该ID需要与硬件相关联。 - TheRealChx101

    21

    http://developer.android.com/reference/android/provider/Settings.Secure.html#ANDROID_ID - Mudassir
    1
    @Mudassir:问题确实说“如果我的应用程序正在某个笔记本电脑、迷你笔记本或其他类型的设备上运行,我该如何在这种情况下获取唯一的标识符?” - Greg Sansom
    2
    @Mudassir:是的...但在不同情况下几乎任何事情都可能改变。这取决于您希望事物有多“独特”和多“永久”。如果UID在出厂重置期间更改,则下次使用您编写的任何应用程序时“使设备无效”。此外,在出厂重置后,您的应用程序将需要重新安装。 - Squonk
    4
    据传某些手机/固件版本上的ANDROID_ID并不唯一。 - Chris Stratton
    1
    +1 Chris。文档说这是一个随机数,所以你不能确定它一定是唯一的... 剩下的好答案也加一分。 - DeRagan
    显示剩余6条评论

    8

    如需了解有关如何为每个安装应用程序的Android设备获取唯一标识符的详细说明,请参阅此官方Android开发者博客文章:

    http://android-developers.blogspot.com/2011/03/identifying-app-installations.html

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

    我个人认为这样做是可以接受的,但并不理想。 Android提供的没有一个标识符适用于所有情况,因为大多数标识符都依赖于手机的无线电状态(wifi开/关,蜂窝网络开/关,蓝牙开/关)。其他标识符(例如Settings.Secure.ANDROID_ID)必须由制造商实现,并不能保证唯一性。

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

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

    该博客指出:“对于绝大多数应用程序,要求的是识别特定的安装,而不是物理设备”,但是上述代码创建的ID并不可靠,因为如果用户清除应用数据,则设备ID将被删除,并且它会创建新的设备ID。测试了10次,每次都会创建新的ID。 :( - Mudassar
    @Mudassar 确实如此。并不是非常理想。如果用户能够伪造硬件ID,那也没有关系。我只希望有一个“永久”的ID,这样我就知道首次连接到我的服务的设备,并将其与一个账户关联起来,以便进行故障排除,永远地保留。 - TheRealChx101

    8
    你可以尝试这个: ```html ```
    String deviceId = Secure.getString(this.getContentResolver(),
                    Secure.ANDROID_ID);
    

    6

    使用 MAC 地址

    一个媒体访问控制地址(MAC地址)是分配给网络接口的唯一标识符。

    任何连接到网络的设备都有一个 MAC 地址,你可以在 Android 设备上通过进入“设置” > “关于手机” > “状态”来查找它。

    你可以使用Bluetooth API获取蓝牙 MAC 地址。


    我不知道Android是否免疫,但在许多系统上MAC地址可以被伪造。 - Squonk
    它是否可用于Netbooks或平板电脑等设备上?我如何通过编程方式获取它? - Mudassir
    2
    是的,任何已经被root的设备都可以覆盖MAC地址(或至少本地报告)。 - Chris Stratton
    @Mudassir:是的,只要设备具有网络访问权限,MAC地址就可以使用。如何以编程方式获取它取决于您使用的语言-您可能需要搜索谷歌或提出另一个问题。 - Greg Sansom
    @MisterSquonk:你说得对,但我不确定这是否真的很重要——它应该被视为一个标识符,但不能用于身份验证。 - Greg Sansom

    3

    Settings.Secure#ANDROID_ID 返回 Android ID,它是一个唯一的 64 位十六进制字符串。

    import android.provider.Settings.Secure;
    
    private String android_id = Secure.getString(getContext().getContentResolver(),
                                                            Secure.ANDROID_ID);
    

    2

    如果系统中启用了网络设备(例如蓝牙等),您可以获取MAC地址。但设备可能具有蓝牙、WiFi等或者没有任何设备。

    您可以编写自己的唯一ID生成器(例如,随机生成20个数字或符号)。


    我想唯一地识别一个设备。我该如何使用随机数生成器? - Mudassir
    这是一个大问题,因为UID应该由设备开发人员实现。 生成ID,保存在SharedPrefference中,并用于识别设备。 - mysuperass

    2
    final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
    
       final String tmDevice, tmSerial, tmPhone, 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(), ((<span id="IL_AD3" class="IL_AD">long</span>)tmDevice.hashCode() << 32) | tmSerial.hashCode());
       String deviceId = deviceUuid.toString();
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接