【问题标题】:Unique ID of Android deviceAndroid 设备的唯一 ID
【发布时间】:2010-12-17 06:22:32
【问题描述】:

我想要一些 Android 设备的唯一 ID。我用下面的代码试过了

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

但我知道这仅适用于手机。

如果我的应用在某些笔记本电脑、上网本或其他类型的设备上运行怎么办?在这种情况下,我如何获得唯一 ID?

【问题讨论】:

  • @Mudassir:所以基本上你想要一些“一成不变”、“硬编码”的东西,它永远不会改变并且 100% 可靠???英特尔尝试过...阅读此 schneier.com/essay-187.html
  • @MisterSquonk 我想要那种东西。我喜欢“一成不变”。 :-)
  • @Mudassir:祝你好运找到它,但如果你能找到它,我会感到惊讶。最多我会按照最不可能被更改/黑客攻击的东西的原则工作,或者作为尽可能“独特”的东西的基础。之后,尝试编写代码来弥补沿途的任何问题。
  • @rds:我知道它已经问过了,而且我也尝试了我在问题中提到的上一篇文章中给出的解决方案。我的标准不同。

标签: android


【解决方案1】:

android 手机上共有三种标识符。

  1. IMEI
  2. IMSI

    String ts = Context.TELEPHONY_SERVICE;
    TelephonyManager mTelephonyMgr = (TelephonyManager) getSystemService(ts);
    String imsi = mTelephonyMgr.getSubscriberId();
    String imei = mTelephonyMgr.getDeviceId();
    
  3. Android ID 它是在设备首次启动时生成的 64 位十六进制字符串。 一般不会更改,除非恢复出厂设置。

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

【讨论】:

【解决方案2】:

很抱歉碰到一个旧线程,但是这个问题让我很头疼,我找到了一篇好文章供某人阅读,这对我很有帮助。

有时需要在 Android 应用程序开发期间获取基于 Android 的智能手机设备的唯一 ID。当用户想要跟踪应用程序的唯一设备安装时,这是必要的。

这在 Android 开发人员只想将 Push 消息发送到少数特定设备的情况下也很有用。所以这里有必要为每台设备都有一个 UDID。

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

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

1) IMEI:(国际移动设备标识)

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

获取设备IMEI的代码sn-p如下,

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

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

使用 IMEI 作为设备 ID 的优势:

IMEI 对于每台设备都是独一无二的。 即使重新安装了应用程序或者设备已植根或恢复出厂设置,它对于设备仍然是唯一的。

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

IMEI 依赖于设备的 Simcard 插槽,因此无法获取不使用 Simcard 的设备的 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 的优势:

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

它将在所有设备中保持唯一性,并且可以在没有 Simcard 插槽的手机上使用。

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

如果用户升级了 Android 操作系统版本,那么这可能会发生变化。 如果设备已植根或在设备上完成出厂重置,则 ID 会更改。 还有一个已知的问题是中国的安卓设备制造商有一些设备具有相同的 Android_ID。

3) WLAN MAC 地址字符串

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

获取设备WLAN MAC地址的代码sn-p如下所示,

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

您的应用将需要清单文件中提供的“android.permission.ACCESS_WIFI_STATE”权限。

使用 WLAN MAC 地址作为设备 ID 的优势:

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

使用WLAN MAC地址作为Device ID的缺点:

如果设备没有wifi硬件那么你会得到空MAC地址,但通常可以看到大多数Android设备都有wifi硬件,市场上几乎没有没有wifi硬件的设备。

4) 蓝牙地址字符串

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

获取蓝牙设备地址的代码sn-p如下,

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

要获取上述代码,您的应用需要清单文件中提供的“android.permission.BLUETOOTH”权限。

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

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

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

如果有任何其他方法可以获取 UDID 并且掩盖了上述方法的缺点,那么我很想在我的 Android 应用程序中探索这些方法。 PL。在评论框中分享这些内容,以及如果有任何建议或疑问。

Here's the article

【讨论】:

    【解决方案3】:
    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;
    
    }
    

    【讨论】:

    • 如果你答对了 接受答案...很乐意帮助你:-)
    • 这个生成的ID在设备重启后总是一样的?
    【解决方案4】:

    看常数 ANDROID_ID android.provider.Secure.Settings 看看是否有帮助。

    我正在添加一些来自官方文档的有用链接;

    【讨论】:

    • @Mudassir:问题确实是“如果我的应用程序在某些笔记本电脑、上网本或其他类型的设备上运行怎么办?在这种情况下我如何获得唯一的 ID?”
    • @Mudassir:是的……但是在不同的情况下,几乎任何事情都可能发生变化。这取决于您希望事物的“独特性”和“永久性”程度。如果在恢复出厂设置期间更改了 UID,那么下次使用您正在编写的任何应用程序时都会使设备“无效”。此外,恢复出厂设置后,您的应用必须重新安装。
    • 据传ANDROID_ID 在某些手机/固件版本上不是唯一的
    • +1 克里斯。文档说它是一个随机数,所以你不能指望它肯定是一个唯一的数字......对于其余的好答案也是 +1
    【解决方案5】:

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

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

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

    我个人认为这是可以接受的,但并不理想。 Android 提供的标识符在所有情况下都不起作用,因为大多数标识符取决于手机的无线电状态(wifi 开/关、蜂窝开/关、蓝牙开/关)。其他如 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();
        }
    }
    

    【讨论】:

    • 博客说“对于绝大多数应用程序,要求是识别特定的安装,而不是物理设备”但是上面代码创建的 id 并不可靠,就像用户清除应用程序数据一样,设备 id 被删除并创建新的设备 id。测试了 10 次,每次创建新的 id。 :(
    【解决方案6】:

    使用MAC address

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

    任何连接到网络的设备都保证有一个 MAC 地址,您可以在 Android 上通过转到设置 > 关于手机 > 状态找到它。

    您应该能够使用Bluetooth API 获取蓝牙 Mac 地址。

    【讨论】:

    • 我不知道 Android 是否免疫,但 MAC 地址可以在许多系统上伪造。
    • 它可以在上网本或平板设备上使用吗?如何以编程方式获取它?
    • 是的 MAC(或至少本地报告)可以在任何有根的设备上被覆盖。
    • @Mudassir:是的,MAC 可用于任何具有网络访问权限的设备。如何以编程方式获取它取决于您使用的语言 - 您可能需要点击 Google 或打开另一个问题。
    • @MisterSquonk:你是对的,但我不确定这是否真的有点过分——它应该被视为一个 ID,但不足以进行身份​​验证。
    【解决方案7】:

    你可以试试这个:

    String deviceId = Secure.getString(this.getContentResolver(),
                    Secure.ANDROID_ID);
    

    【讨论】:

      【解决方案8】:

      Settings.Secure#ANDROID_ID 将 Android ID 作为唯一的 64 位十六进制字符串返回。

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

      【讨论】:

        【解决方案9】:

        如果系统中启用了网络设备(蓝牙等)(打开),您可以获得 MAC 地址。但设备可能有蓝牙、WiFi 等或什么都没有。

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

        【讨论】:

        • 我想唯一标识一个设备。如何使用随机数生成器?
        • 这是一个大问题,因为UID应该由设备开发人员实现。生成 ID,保存在 SharedPreference 中并用于识别设备
        【解决方案10】:
        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();
        

        【讨论】:

          【解决方案11】:
          TextView textAndroidId = (TextView)findViewById(R.id.androidid);
          String AndroidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
          textAndroidId.setText("My ID is: " + AndroidId);
          

          【讨论】:

            【解决方案12】:

            由于对 MAC 地址和其他与电话相关的 API 应用了新的限制,并且只有当这些硬件相关的唯一标识符是系统应用程序的一部分并且具有所需的权限时,他们才能访问它们。

            来自docs

            When working with Android identifiers, follow these best practices:
            
            Avoid using hardware identifiers. In most use cases, you can avoid using hardware identifiers, such as SSAID (Android ID), without limiting required functionality.
            
            Android 10 (API level 29) adds restrictions for non-resettable identifiers, which include both IMEI and serial number. Your app must be a device or profile owner app, have special carrier permissions, or have the READ_PRIVILEGED_PHONE_STATE privileged permission in order to access these identifiers.
            
            Only use an Advertising ID for user profiling or ads use cases. When using an Advertising ID, always respect users' selections regarding ad tracking. Also, ensure that the identifier cannot be connected to personally identifiable information (PII), and avoid bridging Advertising ID resets.
            
            Use a Firebase installation ID (FID) or a privately stored GUID whenever possible for all other use cases, except for payment fraud prevention and telephony. For the vast majority of non-ads use cases, an FID or GUID should be sufficient.
            
            Use APIs that are appropriate for your use case to minimize privacy risk. Use the DRM API for high-value content protection and the SafetyNet APIs for abuse protection. The SafetyNet APIs are the easiest way to determine whether a device is genuine without incurring privacy risk.
            
            The remaining sections of this guide elaborate on these rules in the context of developing Android apps.
            

            最好的情况是我们使用 FID 或 GUID 来识别每次安装的应用程序的唯一性,您可以这样做。

             fun getDeviceId(): String {
                return FirebaseInstallations.getInstance().id.result ?: UUID.randomUUID().toString()
            }
            

            【讨论】:

              【解决方案13】:

              您可以检查权限并评估它将为您提供设备 ID 的值:

              private static final int REQUEST_READ_PHONE_STATE = 1;
              
              int permissionCheck = ContextCompat.checkSelfPermission(getContext(),
              Manifest.permission.READ_PHONE_STATE);
              
                  if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
                      ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_READ_PHONE_STATE);
                  } else {
                      TelephonyManager tManager = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
                      String uid = tManager.getDeviceId();
                      System.out.print(uid);
                  }
              

              输出:358240051111110

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-08-07
                • 1970-01-01
                • 1970-01-01
                • 2016-03-13
                • 1970-01-01
                相关资源
                最近更新 更多