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


当前回答

如果添加:

Settings.Secure.getString(context.contentResolver,
    Settings.Secure.ANDROID_ID)

Android Lint将向您发出以下警告:

不建议使用getString获取设备标识符。检查信息:不建议使用这些设备标识符除了用于高价值欺诈预防和高级电话之外使用案例。对于广告用例,请使用AdvertisingIdClient$Info#getId,用于分析,请使用InstanceId#getId。

所以,你应该避免使用这个。

如Android开发者文档中所述:

1:避免使用硬件标识符。在大多数使用情况下,您可以避免使用硬件标识符,例如SSAID(Android ID)和IMEI,而不限制所需的功能。2:仅在用户分析或广告用例中使用广告ID。使用广告ID时,始终尊重用户的选择关于广告跟踪。此外,请确保标识符不能连接到个人身份信息(PII),并避免桥接广告ID重置。3:在所有其他用例中,尽可能使用实例ID或私有存储的GUID,但支付欺诈预防和电话除外。对于绝大多数非广告用例,实例ID或GUID应足够。4:使用适合您的用例的API,以最大限度地降低隐私风险。使用DRM API保护高价值内容用于滥用保护的SafetyNet API。SafetyNet API是确定设备是否为正品的最简单方法隐私风险。

其他回答

对于特定Android设备的硬件识别,您可以检查MAC地址。

你可以这样做:

在AndroidManifest.xml中

<uses permission android:name=“android.ppermission.INTERNET”/>

现在在您的代码中:

List<NetworkInterface> interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces());

for (NetworkInterface interface : interfacesList) {
   // This will give you the interface MAC ADDRESS
   interface.getHardwareAddress();
}

在每个Android设备中,他们至少有一个“wlan0”接口开关,即WI-FI芯片。即使未打开WI-FI,此代码也能正常工作。

附笔。它们是一堆其他接口,你可以从包含MACS的列表中获得,但这可以在手机之间改变。

更新:在最近的Android版本中,Android_ID的许多问题已经得到解决,我相信这种方法不再是必要的。请看一下安东尼的回答。

完整披露:我的应用程序最初使用了以下方法,但现在不再使用这种方法,我们现在使用了emmby的答案链接所指向的Android开发者博客条目中概述的方法(即,生成并保存UUID#randomUUID())。


这个问题有很多答案,其中大多数只在“某些”时间有效,不幸的是,这还不够好。

根据我对设备的测试(所有手机,至少有一部未激活):

所有测试的设备都返回了TelephonyManager.getDeviceId()的值所有GSM设备(均使用SIM进行测试)都返回了TelephonyManager.getSimSerialNumber()的值对于getSimSerialNumber(),所有CDMA设备均返回null(如预期)添加了Google帐户的所有设备都返回了ANDROID_ID的值所有CDMA设备都为ANDROID_ID和TelephonyManager.getDeviceId()返回相同的值(或相同值的派生)——只要在安装过程中添加了Google帐户。我还没有机会测试没有SIM卡的GSM设备,没有添加谷歌账户的GSM设备或任何处于飞行模式的设备。

因此,如果您想要设备本身独有的东西,TM.getDeviceId()就足够了。显然,有些用户比其他用户更偏执,因此对这些标识符中的一个或多个进行散列可能会很有用,这样该字符串对于设备来说实际上仍然是唯一的,但不会明确标识用户的实际设备。例如,使用String.hashCode()并结合UUID:

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);

final String tmDevice, tmSerial, 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(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

可能会导致类似的结果:00000000-54b3-e7c7-0000-000046bffd97

这对我来说足够好了。

正如Richard在下面提到的那样,不要忘记您需要权限才能读取TelephonyManager财产,因此请将此添加到您的清单中:

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

导入库

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;

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

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

注意,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:

public static String getDeviceId(Context ctx)
{
    TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);

    String tmDevice = tm.getDeviceId();
    String androidId = Secure.getString(ctx.getContentResolver(), Secure.ANDROID_ID);
    String serial = null;
    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) serial = Build.SERIAL;

    if(tmDevice != null) return "01" + tmDevice;
    if(androidId != null) return "02" + androidId;
    if(serial != null) return "03" + serial;
    // other alternatives (i.e. Wi-Fi MAC, Bluetooth MAC, etc.)

    return null;
}

以下代码使用隐藏的Android API返回设备序列号。但是,这个代码在三星Galaxy Tab上不起作用,因为这个设备上没有设置“ro.seriano”。

String serial = null;

try {
    Class<?> c = Class.forName("android.os.SystemProperties");
    Method get = c.getMethod("get", String.class);
    serial = (String) get.invoke(c, "ro.serialno");
}
catch (Exception ignored) {

}