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


当前回答

这里有30多个答案,有些是相同的,有些是独特的。这个答案是基于这些答案中的一些。其中一个是Lenn Dolling的回答。

它组合3个ID并创建32位十六进制字符串。这对我来说效果很好。

3个ID为:伪ID-根据物理设备规范生成ANDROID_ID-设置.Securite.ANDROID-ID蓝牙地址-蓝牙适配器地址

它将返回如下内容:551F27C060712A72730B0F734064B1

注意:您始终可以向longId字符串添加更多ID。例如,序列号。wifi适配器地址。伊梅。通过这种方式,您可以使每个设备都更独特。

@SuppressWarnings("deprecation")
@SuppressLint("HardwareIds")
public static String generateDeviceIdentifier(Context context) {

        String pseudoId = "35" +
                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;

        String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        String btId = "";

        if (bluetoothAdapter != null) {
            btId = bluetoothAdapter.getAddress();
        }

        String longId = pseudoId + androidId + btId;

        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(longId.getBytes(), 0, longId.length());

            // get md5 bytes
            byte md5Bytes[] = messageDigest.digest();

            // creating a hex string
            String identifier = "";

            for (byte md5Byte : md5Bytes) {
                int b = (0xFF & md5Byte);

                // if it is a single digit, make sure it have 0 in front (proper padding)
                if (b <= 0xF) {
                    identifier += "0";
                }

                // add number to string
                identifier += Integer.toHexString(b);
            }

            // hex string to uppercase
            identifier = identifier.toUpperCase();
            return identifier;
        } catch (Exception e) {
            Log.e("TAG", e.toString());
        }
        return "";
}

其他回答

这是Reto Meier在今年的Google I/O演示中使用的代码,用于为用户获取唯一id:

private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";

public synchronized static String id(Context context) {
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                PREF_UNIQUE_ID, 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();
        }
    }
    return uniqueID;
}

如果你将此与备份策略相结合,将首选项发送到云(Reto的演讲中也有描述),你应该有一个与用户相关的id,在设备被擦除甚至更换后,它会一直存在。我计划在未来的分析中使用此项(换句话说,我还没有做过这一点:)。

Android在Android O之后限制硬件相关Id,Android_Id是唯一Id的解决方案,但当反射设备,它将生成新的android_id以克服此问题问题是我们可以使用DRUMID。

val WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L)
val drumIDByteArray = MediaDrm(WIDEVINE_UUID).getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID)

val drumID = android.util.Base64.encodeToString(drumIDByteArray,android.util.Base64.DEFAULT)

我几年前就遇到过这个问题,并学会了基于各种答案来实现一个通用的解决方案。

我已经在一个真实世界的产品中使用通用解决方案好几年了。到目前为止,这对我来说很好。以下是基于提供的各种答案的代码片段。

注意,getEmail大多数时候都会返回null,因为我们没有明确请求权限。

private static UniqueId getUniqueId() {
    MyApplication app = MyApplication.instance();

    // Our prefered method of obtaining unique id in the following order.
    // (1) Advertising id
    // (2) Email
    // (2) ANDROID_ID
    // (3) Instance ID - new id value, when reinstall the app.

    ////////////////////////////////////////////////////////////////////////////////////////////
    // ADVERTISING ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    AdvertisingIdClient.Info adInfo = null;
    try {
        adInfo = AdvertisingIdClient.getAdvertisingIdInfo(app);
    } catch (IOException e) {
        Log.e(TAG, "", e);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e(TAG, "", e);
    } catch (GooglePlayServicesRepairableException e) {
        Log.e(TAG, "", e);
    }

    if (adInfo != null) {
        String aid = adInfo.getId();
        if (!Utils.isNullOrEmpty(aid)) {
            return UniqueId.newInstance(aid, UniqueId.Type.aid);
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // EMAIL
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String email = Utils.getEmail();
    if (!Utils.isNullOrEmpty(email)) {
        return UniqueId.newInstance(email, UniqueId.Type.eid);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // ANDROID ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String sid = Settings.Secure.getString(app.getContentResolver(), Settings.Secure.ANDROID_ID);
    if (!Utils.isNullOrEmpty(sid)) {
        return UniqueId.newInstance(sid, UniqueId.Type.sid);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // INSTANCE ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String iid = com.google.android.gms.iid.InstanceID.getInstance(MyApplication.instance()).getId();
    if (!Utils.isNullOrEmpty(iid)) {
        return UniqueId.newInstance(iid, UniqueId.Type.iid);
    }

    return null;
}

public final class UniqueId implements Parcelable {
    public enum Type implements Parcelable {
        aid,
        sid,
        iid,
        eid;

        ////////////////////////////////////////////////////////////////////////////
        // Handling Parcelable nicely.

        public static final Parcelable.Creator<Type> CREATOR = new Parcelable.Creator<Type>() {
            public Type createFromParcel(Parcel in) {
                return Type.valueOf(in.readString());
            }

            public Type[] newArray(int size) {
                return new Type[size];
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeString(this.name());
        }

        // Handling Parcelable nicely.
        ////////////////////////////////////////////////////////////////////////////
    }

    public static boolean isValid(UniqueId uniqueId) {
        if (uniqueId == null) {
            return false;
        }
        return uniqueId.isValid();
    }

    private boolean isValid() {
        return !org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) && type != null;
    }

    private UniqueId(String id, Type type) {
        if (org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) || type == null) {
            throw new java.lang.IllegalArgumentException();
        }
        this.id = id;
        this.type = type;
    }

    public static UniqueId newInstance(String id, Type type) {
        return new UniqueId(id, type);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + id.hashCode();
        result = 31 * result + type.hashCode();
        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }

        if (!(o instanceof UniqueId)) {
            return false;
        }

        UniqueId uniqueId = (UniqueId)o;
        return this.id.equals(uniqueId.id) && this.type == uniqueId.type;
    }

    @Override
    public String toString() {
        return type + ":" + id;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Handling Parcelable nicely.

    public static final Parcelable.Creator<UniqueId> CREATOR = new Parcelable.Creator<UniqueId>() {
        public UniqueId createFromParcel(Parcel in) {
            return new UniqueId(in);
        }

        public UniqueId[] newArray(int size) {
            return new UniqueId[size];
        }
    };

    private UniqueId(Parcel in) {
        this.id = in.readString();
        this.type = in.readParcelable(Type.class.getClassLoader());
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeString(this.id);
        parcel.writeParcelable(this.type, 0);
    }

    // Handling Parcelable nicely.
    ////////////////////////////////////////////////////////////////////////////

    public final String id;
    public final Type type;
}

public static String getEmail() {
    Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
    AccountManager accountManager = AccountManager.get(MyApplication.instance());
    Account[] accounts = accountManager.getAccountsByType("com.google");
    for (Account account : accounts) {
        if (emailPattern.matcher(account.name).matches()) {
            String possibleEmail = account.name;
            return possibleEmail;
        }
    }

    accounts = accountManager.getAccounts();
    for (Account account : accounts) {
        if (emailPattern.matcher(account.name).matches()) {
            String possibleEmail = account.name;
            return possibleEmail;
        }
    }

    return null;
} 

我认为这是建立一个独特身份的骨架的最佳方式……看看吧。

伪唯一ID,适用于所有Android设备某些设备没有电话(例如平板电脑),或者出于某种原因,您不希望包含READ_phone_STATE权限。您仍然可以阅读ROM版本、制造商名称、CPU类型和其他硬件详细信息,如果您想将ID用于串行密钥检查或其他一般用途,这些信息将非常适合。以这种方式计算的ID不会是唯一的:可以找到两个具有相同ID的设备(基于相同的硬件和ROM映像),但实际应用程序中的变化可以忽略不计。为此,可以使用Build类:

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

大多数Build成员都是字符串,我们在这里所做的是获取它们的长度,并通过数字中的模来转换它。我们有13个这样的数字,我们在前面增加了两个(35),以具有与IMEI相同的大小ID(15个数字)。这里还有其他的可能性,好吧,看看这些字符串。返回355715565309247。无需特别许可,这使得该方法非常方便。


(额外信息:上面给出的技术是从Pocket Magic上的一篇文章中复制的。)

TelephonyManager.getDeviceId()返回唯一的设备ID,例如,GSM的IMEI和CDMA电话的MEID或ESN。

final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);            
String myAndroidDeviceId = mTelephony.getDeviceId(); 

但我建议使用:

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

    String   myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

有时TelephonyManager.getDeviceId()将返回null,因此为了确保唯一的id,您将使用以下方法:

public String getUniqueID(){    
    String myAndroidDeviceId = "";
    TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    if (mTelephony.getDeviceId() != null){
        myAndroidDeviceId = mTelephony.getDeviceId(); 
    }else{
         myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
    }
    return myAndroidDeviceId;
}