Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2019-10-08:如何获取Android设备唯一ID? #159

Open
Moosphan opened this issue Oct 8, 2019 · 8 comments
Open

2019-10-08:如何获取Android设备唯一ID? #159

Moosphan opened this issue Oct 8, 2019 · 8 comments
Labels
question Further information is requested

Comments

@Moosphan
Copy link
Owner

Moosphan commented Oct 8, 2019

No description provided.

@Kebiiii
Copy link

Kebiiii commented Oct 8, 2019

  1. imei
    国际移动设备识别码,是第一个想到的,是手机的身份证,刷机不会被改变

缺点:
只适用于电话功能设备 不适用于pad
6.0以后需要动态申请权限
有些设备会返回错误

2.手机WiFi或蓝牙的MAC地址
缺点:
硬件限制:并不是所有的设备都有WiFi和蓝牙硬件 但其实大部分设备都是支持wifi和蓝牙的了,所以这条并不重要
如果WiFi没有打开过,是无法获取其Mac地址的(高版本获取到的mac将是固定的:02:00:00:00:00:00);
高版本好像有方法可以获取到,但也要适配一系列版本,以后变动要持续适配
https://blog.csdn.net/chaozhung_no_l/article/details/78329371
蓝牙是只有在打开的时候才能获取到其Mac地址(需要动态申请权限)
**

3.Serial Number
硬件序列,在Android 2.2 以上可以通过 android.os.Build.SERIAL 获得序列号

缺点:
https://stackoverflow.com/questions/11029294/android-how-to-programmatically-access-the-device-serial-number-shown-in-the-av
https://developer.android.com/reference/android/os/Build.html#SERIAL

A hardware serial number, if available. Alphanumeric only, case-insensitive. For apps targeting SDK higher than Build.VERSION_CODES.O_MR1 this field is set to UNKNOWN.
硬件序列号(如果有)。 仅限字母数字,不区分大小写。 对于定位SDK高于Build.VERSION_CODES.O_MR1的应用,此字段设置为UNKNOWN。
26以后被弃用,getSerial ()替代,需要动态申请READ_PHONE_STATE权限

4.android Id
设备首次启动产生的,不需要获取权限
8.0中,只要程序包名称和签名密钥相同,ANDROID_ID值就不会在程序包卸载/重新安装时更改
获取方法:
String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

缺点:
设备恢复出厂设置会被重置
部分手机返回为空或固定值9774d56d682e549c
考虑到动态申请权限成本较高,可接受恢复出厂重置androidId
公司几部测试机从4.4 5.0 6.0 7.0 8.0 均测试以下方法能成功获取到相同androidId

经上几种比较android id方式较为可靠
最终方法如下:

private static String deviceId = null;

public static String getDeviceId() {
if (!TextUtils.isEmpty(deviceId)) {
return deviceId;
}
if (!TextUtils.isEmpty(SPUtils.getStringValue(DEVICE_ID_KEY, ""))) {
//从sp中获取
deviceId = SPUtils.getStringValue(DEVICE_ID_KEY, "");
}else{
//sp中没有
String uuId;
String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
if (TextUtils.isEmpty(androidId) || TextUtils.equals("9774d56d682e549c", androidId)) {
uuId = UUID.randomUUID().toString();
} else {
//构造UUID,防止直接暴露ANDROID_ID
uuId = new UUID(androidId.hashCode(), ((long) androidId.hashCode() << 32)).toString();
}
deviceId = uuId.replace("-", "");
//保存sp
SPUtils.setStringValue(DEVICE_ID_KEY, deviceId);
}
return deviceId;
}

@gabyallen
Copy link

Android ID
uuid
deviceid
蓝牙或Wi-Fimac的地址
硬件和型号

@Reginer
Copy link

Reginer commented Oct 9, 2019

看需求了,如果用来做单点登录,那用应用首次安装时间足够了。
做统计类的,把首次安装时间放到卸载删不掉的地方。

@Moosphan Moosphan added the question Further information is requested label Oct 10, 2019
@messi-wpy
Copy link

  1. imei
    国际移动设备识别码,是第一个想到的,是手机的身份证,刷机不会被改变

缺点:
只适用于电话功能设备 不适用于pad
6.0以后需要动态申请权限
有些设备会返回错误

2.手机WiFi或蓝牙的MAC地址
缺点:
硬件限制:并不是所有的设备都有WiFi和蓝牙硬件 但其实大部分设备都是支持wifi和蓝牙的了,所以这条并不重要
如果WiFi没有打开过,是无法获取其Mac地址的(高版本获取到的mac将是固定的:02:00:00:00:00:00);
高版本好像有方法可以获取到,但也要适配一系列版本,以后变动要持续适配
https://blog.csdn.net/chaozhung_no_l/article/details/78329371
蓝牙是只有在打开的时候才能获取到其Mac地址(需要动态申请权限)
**

3.Serial Number
硬件序列,在Android 2.2 以上可以通过 android.os.Build.SERIAL 获得序列号

缺点:
https://stackoverflow.com/questions/11029294/android-how-to-programmatically-access-the-device-serial-number-shown-in-the-av
https://developer.android.com/reference/android/os/Build.html#SERIAL

A hardware serial number, if available. Alphanumeric only, case-insensitive. For apps targeting SDK higher than Build.VERSION_CODES.O_MR1 this field is set to UNKNOWN.
硬件序列号(如果有)。 仅限字母数字,不区分大小写。 对于定位SDK高于Build.VERSION_CODES.O_MR1的应用,此字段设置为UNKNOWN。
26以后被弃用,getSerial ()替代,需要动态申请READ_PHONE_STATE权限

4.android Id
设备首次启动产生的,不需要获取权限
8.0中,只要程序包名称和签名密钥相同,ANDROID_ID值就不会在程序包卸载/重新安装时更改
获取方法:
String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

缺点:
设备恢复出厂设置会被重置
部分手机返回为空或固定值9774d56d682e549c
考虑到动态申请权限成本较高,可接受恢复出厂重置androidId
公司几部测试机从4.4 5.0 6.0 7.0 8.0 均测试以下方法能成功获取到相同androidId

经上几种比较android id方式较为可靠
最终方法如下:

private static String deviceId = null;

public static String getDeviceId() {
if (!TextUtils.isEmpty(deviceId)) {
return deviceId;
}
if (!TextUtils.isEmpty(SPUtils.getStringValue(DEVICE_ID_KEY, ""))) {
//从sp中获取
deviceId = SPUtils.getStringValue(DEVICE_ID_KEY, "");
}else{
//sp中没有
String uuId;
String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
if (TextUtils.isEmpty(androidId) || TextUtils.equals("9774d56d682e549c", androidId)) {
uuId = UUID.randomUUID().toString();
} else {
//构造UUID,防止直接暴露ANDROID_ID
uuId = new UUID(androidId.hashCode(), ((long) androidId.hashCode() << 32)).toString();
}
deviceId = uuId.replace("-", "");
//保存sp
SPUtils.setStringValue(DEVICE_ID_KEY, deviceId);
}
return deviceId;
}

双卡手机imei有两个怎么办?获取的是哪个

@Kebiiii
Copy link

Kebiiii commented Oct 16, 2019

双卡手机imei有两个怎么办?获取的是哪个

高版本用这个方法多个IMEI:
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
public void getSimInfoBySubscriptionManager(Context context) {
List list = SubscriptionManager.from(context).getActiveSubscriptionInfoList();
for (SubscriptionInfo info : list) {
Log.d("Q_M", "ICCID-->" + info.getIccId());
Log.d("Q_M", "subId-->" + info.getSubscriptionId());
Log.d("Q_M", "DisplayName-->" + info.getDisplayName());
Log.d("Q_M", "CarrierName-->" + info.getCarrierName());
Log.d("Q_M", "---------------------------------");
}
}

低版本用反射获取:

private void getAPI19SimInfo(Context context) {
Class<?> tm = null;
try {
tm = Class.forName("android.telephony.MSimTelephonyManager");

        Method getSubscriberIdMethod = tm.getMethod("getSubscriberId", int.class);
        Method getSimSerialNumberMethod = tm.getMethod("getSimSerialNumber", int.class);

        Object service = context.getSystemService("phone_msim");

        //0 代表卡1
        //1 代表卡2
        String s = (String) getSimSerialNumberMethod.invoke(service, 0);
        Log.d("Q_M", "-->" + s);

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

参考:https://blog.csdn.net/niyingxunzong/article/details/77188040

@xiaoxianBoy
Copy link

常用方法:
IMEI
权限(读手机权限)
可以手动更改(模拟器上) /关闭权限报错

Mac地址
访问WIFI权限
有些设备没有wifi(没有上网功能)/6.0以上版本返回的都是固定的02:00:00 之类地址

ANDROID_ID
设备首次运行,系统会随机生成一个64位的数字,转换成16进制保存
手机恢复出厂设置后值有变化/ 有些国产设备不会返回值

Serial Number (设备序列号)
有些国产手机(红米)会出现垃圾数据

实现思路:
1.获取设备的IMEI -->设备的Mac地址-->随机生成的UUID,
2.拼接在一起,然后用MD5加密
3.存储到本地的文件中,隐藏. 并且存储在App中的sp中
4.使用的时候先从sp中读取, 没有的再生成,然后把生成的唯一id保存到sp中

@mlinqirong
Copy link

IMEI ANDROIDID UUID

1 similar comment
@mlinqirong
Copy link

IMEI ANDROIDID UUID

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

7 participants