2019-10-08:如何获取Android设备唯一ID?
Moosphan opened this issue · 9 comments
- 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;
}
Android ID
uuid
deviceid
蓝牙或Wi-Fimac的地址
硬件和型号
看需求了,如果用来做单点登录,那用应用首次安装时间足够了。
做统计类的,把首次安装时间放到卸载删不掉的地方。
- 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#SERIALA 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有两个怎么办?获取的是哪个
双卡手机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
常用方法:
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中
IMEI ANDROIDID UUID
IMEI ANDROIDID UUID