【问题标题】:Identify a physical device in android在android中识别物理设备
【发布时间】:2016-04-25 06:31:07
【问题描述】:

我正在开发一个应用程序,我想在其中唯一地识别每台设备。我不能接受imei,因为某些平板电脑不支持通话,所以在这些情况下它将为空。我无法获取 wifi/蓝牙 mac 地址,因为当它关闭时,它会返回 null。

我不能使用 android_id,因为在重置手机时它会发生变化,以及当设备具有多个配置文件时,每个配置文件都有不同的 android_id,因此这也不是唯一的设备标识。

识别物理设备而非用户的最佳方法是什么。

编辑

我已经阅读了这个Is there a unique Android device ID?,但我找不到我的答案。

【问题讨论】:

标签: android


【解决方案1】:

我建议使用 mac 地址,然后对其进行哈希处理。

您可以查看this answer,但它仍然需要一个 sim。

你可以这样获取 Mac 地址:

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

然后对其进行 md5 哈希。

我认为它会工作的。

别忘了添加

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

在您的清单中。

【讨论】:

  • 这要求wifi应该打开。如果它关闭,则返回 null .. 我已经在问题中提到了这一点
【解决方案2】:

大多数用户都有一个与 Android 设备关联的 Google 帐户(仅在极少数情况下他们不会)。您可以使用AccountPicker获取确切的 gmail 电子邮件地址(当然,这是唯一的),而无需添加任何权限来获取帐户。

并使用电子邮件和手机型号或制造商或序列号的组合作为设备的唯一 ID。 (用户可能会使用两台设备,但他所有设备的可能性很低一样)

您的应用需要包含 Google Play 服务,但它不需要 任何权限。

整个过程将在旧版本的 Android 上失败(2.2+ 是 必需)或者如果 Google Play 不可用,您应该考虑 那个案例。

源代码示例:

private static final int REQUEST_CODE_EMAIL = 1;
    private TextView email = (TextView) findViewById(R.id.email);

    // ...

    try {
        Intent intent = AccountPicker.newChooseAccountIntent(null, null,
                new String[] { GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE }, false, null, null, null, null);
        startActivityForResult(intent, REQUEST_CODE_EMAIL);
    } catch (ActivityNotFoundException e) {
        // TODO
    }

    // ...

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE_EMAIL && resultCode == RESULT_OK) {
            String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
            email.setText(accountName);
        }
    }
上述信息的

来源是:This Answer on SO - 与过去提出的类似但略有不同的问题。

This Post - 还有一些很好的方法可以满足您的目的。

【讨论】:

    【解决方案3】:

    这是一个非常重要和有趣的问题,所以想详细回答一下。

    有几种唯一检测Android设备的方法,但问题是由于各种原因,它们中的大多数都不可靠。

    i) IMEI

    这是迄今为止最常用的方法,但仅适用于手机,需要此不必要的权限android.permission.READ_PHONE_STATE

    ii) Android ID

    这也可以在恢复出厂设置或设备已植根时更改。不是一种非常可靠的唯一性方法。

    iii) WLAN 和蓝牙 MAC 地址

    这要求设备具有这些功能并获得android.permission.ACCESS_WIFI_STATEandroid.permission.BLUETOOTH 等权限。如果 wifi 或蓝牙关闭,这也将不起作用。

    iv) 电话号码或电子邮件 ID

    这是确定唯一性最不可靠的方法,如果不是完全必要的话,也不应该是一种选择方法。

    那么现在的出路是什么,伪唯一 ID。您无需任何额外权限即可从设备创建自己的“几乎唯一 ID”。

    听起来不错?让我们直接进入方法。

    /**
     * Return pseudo unique ID
     * @return ID
     */
    public static String getUniquePsuedoID() {
        // If all else fails, if the user does have lower than API 9 (lower
        // than Gingerbread), has reset their device or 'Secure.ANDROID_ID'
        // returns 'null', then simply the ID returned will be solely based
        // off their Android device information. This is where the collisions
        // can happen.
        // Thanks http://www.pocketmagic.net/?p=1662!
        // Try not to use DISPLAY, HOST or ID - these items could change.
        // If there are collisions, there will be overlapping data
        String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);
    
        // Thanks to @Roman SL!
        // http://stackoverflow.com/a/4789483/950427
        // Only devices with API >= 9 have android.os.Build.SERIAL
        // http://developer.android.com/reference/android/os/Build.html#SERIAL
        // If a user upgrades software or roots their device, there will be a duplicate entry
        String serial = null;
        try {
            serial = android.os.Build.class.getField("SERIAL").get(null).toString();
    
            // Go ahead and return the serial for api => 9
            return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
        } catch (Exception exception) {
            // String needs to be initialized
            serial = "serial"; // some value
        }
    
        // Thanks @Joe!
        // http://stackoverflow.com/a/2853253/950427
        // Finally, combine the values we have found by using the UUID class to create a unique identifier
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    }
    

    在为任何 Android 设备生成伪唯一 ID 时会考虑各种因素。但这并不完美。

    这些 ID 可能会发生冲突,但这种情况非常罕见,非常非常罕见。所以从技术上讲,这是您在大多数用例中都可以依赖的东西。

    【讨论】:

    • 我们是否需要为 android.os.Build.class.getField("SERIAL") 请求 READ_PHONE_STATE 权限??
    【解决方案4】:

    我想到的一个简单方法是使用 registry 服务器。

    使用这种方法,您的所有用户都需要将他们的应用(即他们的设备)注册到注册服务。然后注册服务器依次为他们分配一个唯一的令牌,该令牌随后应在应用程序中使用。

    【讨论】:

      【解决方案5】:

      就我而言,我正在使用下面的代码。它实际上识别硬件,而不是用户或任何配置文件。

      尽管使用了 IMEI 号码,但我认为它可以满足您的需求,因为它被认为是可选的:

      public static String getUniqueId(Context ctx) {
          final TelephonyManager tm = (TelephonyManager)ctx.getSystemService(Context.TELEPHONY_SERVICE);
          String id = tm.getDeviceId();
      
          if (id == null) {
              id = Build.SERIAL;
          }
      
          return DigestHelper.getSHADigest(id); // I'm using a SHA for convenience, and for not being able to reverse it, but you can do anything needed with this String.
      }
      

      此代码需要您的清单中的以下权限:&lt;uses-permission android:name="android.permission.READ_PHONE_STATE" /&gt;

      这对我有用,没有兼容性问题:Build.SERIAL 是随 API 9 添加的,对平板电脑或其他没有 IMEI 的设备很有用。对于低于 9 的 API,所有设备都是手机,所以它们都有 IMEI(你还支持低于 9 的 API 级别,真的吗?)。所以最终得到一个空 ID 或 NoClassDefFoundError 是没有风险的。

      作为旁注,Build.SERIAL 应该是唯一的“if available”。我从来没有遇到过既没有 IMEI 也没有这个序列号的实际设备,所以我对“如果可用”的东西从来没有任何问题。

      【讨论】:

      • Build.SERIAL 不改变吗?
      • @Williams 它不应该更改为硬件序列号。我所知道的事实是,我从来没有收到客户的投诉,他们看到他们的设备突然无法识别,因为我从来没有因为一些混淆而遇到麻烦。这就是让我使用它的原因。现在我更愿意看到这个写在 API 规范中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-19
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多