【问题标题】:Creating a Globally Unique Android Identifier创建一个全球唯一的 Android 标识符
【发布时间】:2016-07-30 17:48:43
【问题描述】:

在谈到唯一的 Android ID 时,我相信每个人都见过this,但我也在尝试提出一种解决方案来唯一识别任何 Android 设备。我很乐意使用公开发布的课程,但我还没有找到。

在我的情况下,要求是能够唯一识别任何具有某种形式的互联网连接(例如 GPRS 或 Wi-Fi)并在 API 级别 8 (v2.2 Froyo) 上运行的设备。我不知道有任何设备没有 Wi-Fi 或 SIM 卡,如果有,请告诉我!

我们在 iOS 中通过使用 Wi-Fi mac 地址的哈希解决了这个问题,因为所有 iOS 设备应该都有这个。但是对于 Android,技术(例如上面引用的 SO 帖子的答案)是指可以返回 nullTelephonyManager 类(例如当设备没有 SIM 连接时,例如 Nexus 7)或getContext().getContentResolver(), Secure.ANDROID_ID 根据here 在Froyo 之前的版本上不是100% 可靠的(这对我来说是幸运的)。然而,它并没有说明 Froyo 之后的任何问题,所以如果有任何问题,请告诉我!我也读过这个可以返回null。根据here 的说法,它可以在恢复出厂设置时更改,但这不是主要问题。

所以我把它放在一起来生成一个希望唯一的 GUID: [此方法不完整!]

public static String GetDeviceId(Context context)
{
    // Custom String Hash 1
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("someRandomData"); // Not really needed, but means the stringBuilders value won't ever be null

    // TM Device String
    final TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
    String tmDeviceId = tm.getDeviceId(); // Could well be set to null!
    LogMsg.Tmp("TM Device String [" + tmDeviceId + "]");

    // Custom String Hash 2
    stringBuilder.append(tmDeviceId);
    int customHash = stringBuilder.toString().hashCode();
    LogMsg.Tmp("Custom String hash [" + customHash + "]");

    // Device ID String
    String androidIDString = android.provider.Settings.Secure.getString(context.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
    LogMsg.Tmp("Device ID String [" + androidIDString + "]");

    // Combined hashes as GUID
    UUID deviceUuid = new UUID(androidIDString.hashCode(), ((long)customHash << 32));
    LogMsg.Tmp("Combined hashes as GUID [" + deviceUuid.toString() + "]");

    return deviceUuid.toString();
}

所以你可能会发现tmDeviceId 被设置为null,在这种情况下customHash 将是相同的,无论设备如何,但结合androidIDString 应该是全局唯一的。我认为。显然,如果 tmDeviceIdandroidIDString 不可用,我需要解决并在那里抛出异常。

所以……这是矫枉过正吗?如果是这样,只使用context.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID 是否安全?

【问题讨论】:

  • “在我的情况下,要求是能够唯一识别任何设备”——如果你需要它来覆盖根设备用户,这是不可能的 AFAIK。当然,您使用的任何部分都可以由具有 root 权限的人修改。 “我不知道任何没有 Wi-Fi 或 SIM 卡的设备,如果有的话请告诉我!” -- Google TV 设备可能没有 WiFi,只能使用以太网。如果您在 Play 商店之外进行分发,则可能有其他设备没有移动数据或 WiFi。
  • @CommonsWare 感谢您的回复。如果我在问题中谈到的方法都返回null,我最初的想法是不支持该设备。您认为在 Froyo 的任何内容上使用 Secure.ANDROID_ID 是否安全?另外,我不认为有根设备是一个主要问题。我想这将允许某人欺骗其他人的不同设备,至少,如果他们知道他们在做什么,但我认为通过添加一个密钥(我有stringBuilder.append("someRandomData");)会使生成这个变得困难最终返回的设备 ID。
  • "您认为在 Froyo 的任何东西上使用 Secure.ANDROID_ID 是否安全?" -- 根设备用户可以更改它,而没有合法拥有 Play 商店的设备可能没有唯一值。
  • “我假设你会通过混淆来做到这一点?” -- 不能使用 ProGuard 混淆数据。 ProGuard 制造商的商业工具 DexGuard 显然可以做到这一点。但是,由于有人可以简单地修改 APK 以拦截密码,因此这将是有限的。
  • @Warpzit:我没有发布答案,因为这个评论线程并没有真正回答这个问题,除了指出问题本身的问题。有时,如果我插话评论,结果确实是答案,我会将其转换为答案。

标签: android guid uniqueidentifier


【解决方案1】:

为什么不像在 iOS 中那样获取设备的 MAC 地址?这也可以在 Android 设备中执行。

我会给出一个获取设备mac地址的代码sn-p..

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class HardwareUtil {

    public static String getMacAddress()
    {
        try{
            Process process = Runtime.getRuntime().exec("cat /sys/class/net/eth0/address");
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            int read;
            char[] buffer = new char[4096];
            StringBuffer output = new StringBuffer();
            while ((read = reader.read(buffer)) > 0){
                output.append(buffer, 0, read);
            }
            reader.close();
            process.waitFor();
            String hwaddr = output.toString();
            return hwaddr;
        }catch (IOException e) {
            e.printstacktrace();
        }catch (InterruptedException e){
            e.printstacktrace();
        }
    }

}

HardwareUtil.getMacAddress()会返回设备的mac地址。

编辑:如果 mac 地址不适合您的情况。关注会很有用!

public static String getDeviceId(Context context) {
    final String deviceId = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
    if (deviceId != null) {
        return deviceId;
    } else {
        return android.os.Build.SERIAL;
    }
}

如果您使用getDeviceId 方法,请不要忘记在您的AndoridManifest.xml 文件中添加以下权限。

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

【讨论】:

  • 这就是我最后所做的,问题是我相信如果你有root访问权限,你可以欺骗MAC地址。
  • 是的,你完全正确。如果你有根设备,你可以这样做。你试过 android.os.Build.SERIAL 吗?您可以使用此获取硬件序列号吗?看看这个link它可能对你有帮助。
  • 谢谢,我去看看。 android.os.Build.SERIAL 是保证存在的东西吗?
  • 是的,它从 API 级别 9 开始可用。我将编辑我的答案并提供另一个代码 sn-p。
  • 我不确定。只有我知道的设备才需要报告该号码。但是,API 文档说“硬件序列号,如果有的话”。所以我们可以简单地推导出一个等式“这可能并非所有设备都可用”。顺便说一句,您所说的所有设备是什么意思?平板电脑?智能电视?微波炉:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-24
相关资源
最近更新 更多