Android获取的IMEI只有14位问题解决
此文章已收入Android偶遇杂症合集(持续更新)
1、遇到的问题
在手机设置里的信息上IMEI有15位的数字,但通过代码获得却只有14位,少了最后一位数字。手机重新开机,代码获得了正确的15位数字。最终测试现象,获取方法不可控,返回值可能14位也可能15位,使用时很容易导致数据异常。
2、获取IMEI的常规方式
public static String getIMEI(Context context){
String imei = "";
try {
TelephonyManager tm = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
imei = tm.getDeviceId();
}else {
Method method = tm.getClass().getMethod("getImei");
imei = (String) method.invoke(tm);
}
} catch (Exception e) {
e.printStackTrace();
}
return imei;
}
3、解决方式
3.1 IMEI的结构
第一部分 TAC,Type Allocation Code,类型分配码,由8位数字组成(早期是6位), 是区分手机品牌和型号的编码,该代码由GSMA及其授权机构分配。其中TAC码前两位又是分配机构标识 (Reporting Body Identifier),是授权IMEI码分配机构的代码,如01为美国CTIA,35为英国BABT,86为中国TAF。
第二部分 FAC,Final Assembly Code,最终装配地代码,由2位数字构成, 仅在早期TAC码为6位的手机中存在,所以TAC和FAC码合计一共8位数字。FAC码用于生产商内部区分生产地代码。
第三部分 SNR,Serial Number,序列号,由第9位开始的6位数字组成,区分每部手机的生产序列号。
第四部分 CD,Check Digit,验证码,由前14位数字通过 Luhn算法计算得出。
由此看出,最后一位是可以直接由前14位计算出来的,那么我们直接判断长度后再计算一遍就好了。
3.2 Luhn算法
- 将偶数位数字分别乘以2,分别计算个位数和十位数之和
- 将奇数位数字相加,再加上上一步算得的值
- 如果得出的数个位是0则校验位为0,否则为10减去个位数
如:35 89 01 80 69 72 41
偶数位乘以2得到
5*2=10 、 9*2=18 、 1*2=02 、 0*2=00 、 9*2=18 、 2*2=04 、 1*2=02
计算(奇数位数字)+(上一步计算的偶数位乘积的十位 + 个位),得到
3+(1+0)+8+(1+8)+0+(0+2)+8+(0+0)+6+(1+8)+7+(0+4)+4+(0+2)=63
最后位校验位为 10-3 = 7
所以完整是358901806972417
3.3 Java实现
public static String getIMEI14To15(String imei) {
int last = 0, i = 0, temp;
while (i < imei.length()){
// 加上奇数位
result += Integer.parseInt(imei.substring(i, ++i));
// 偶数位乘以2
temp = Integer.parseInt(imei.substring(i, ++i)) * 2;
// 加上偶数位的十位和个位,这里做了优化操作
// 偶数位乘2的乘积范围为[0, 18],小于10直接加,大于10则个位与十位的和等于乘积减9
result += temp < 10 ? temp : temp - 9;
}
// 取最终和的个位
result %= 10;
// 若为0则为0,否则为10减去个位
result = result == 0? 0 : 10 - result;
return imei + result;
}
public static String getIMEI(Context context){
String imei = "";
try {
TelephonyManager tm = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
imei = tm.getDeviceId();
}else {
Method method = tm.getClass().getMethod("getImei");
imei = (String) method.invoke(tm);
}
} catch (Exception e) {
e.printStackTrace();
}
if (imei != null && imei.length() == 14) {
imei = getIMEI14To15(imei);
}
return imei;
}