Android设备唯一标识的讨论(一)
来源:互联网 发布:詹姆斯06年数据 编辑:程序博客网 时间:2024/06/06 17:43
今天我在这里讨论的Android设备唯一标识,是面向在市面上面出售的机型。通过找到这些机器中的唯一标识部分,来区别不同的手机硬件。而对于工程机,我们则没有办法进行很好的界定,因为其中很多参数值并非是标准的。另外,对于Android模拟器,则更是没有办法找到唯一标识。因为对于应用程序获取到的参数值,几乎都是通过Android SDK提供的接口,或者是通过adb shell命令来获取的。而任何的Android SDK的接口理论上在模拟器上面都是可以仿制(提供假的接口,返回自己希望得到的数据)的。而工程机在很大程度上,也可以做到这点。因为这两者都很大程度上基于更改源码来达成。
因此我们在这里仅讨论市面上出售的手机。
1.如何区分真机和模拟器
(1)通过IMEI(移动设备国际身份码)来识别
该值我们可以再手机拨号盘中输入*#06*来查看,默认情况下,模拟器上该值为15个0,区别于真机。真机则为手机电池下面的标签标准的值。
获取方法:
// Get IMEI public static String getIMEI(Context context) { String imei = null; TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (tm != null) { imei = tm.getDeviceId(); } Helper.showLog(TAG, "getIMEI:" + imei); return imei; }
需要申请权限
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
(2)通过Model (机型)来识别
每个厂商生产的手机,都会对这个Model进行定义,如Coolpad 7019,YPY_S450等,都是机型,代表了不同手机公司的不同机型。而模拟器的该值一般是sdk或者google_sdk。当然可能其他的手机平台商提供的model名称不同,如高通和MTK的模拟器名称可能不相同。因此可以收集这些常见手机平台的sdk名称来做排除。
获取方法:
// Get Model public static String getModel() { String model = android.os.Build.MODEL; Helper.showLog(TAG, "getModel:" + model); return model; }
(3)Mac Address来识别
这就是我们常说的WIFI的物理地址,该值理论上每台手机各不相同(当然可以通过平台公司提供的工具来自行改写),但是在模拟器上面,默认情况下没有硬件设备,因此不管是通过SDK提供的API,还是shell命令,获取的都为空值。
//Get Mac Address by Linux command public static String getMacAddressByCommand() { String macSerial = null; String str = ""; try { Process pp = Runtime.getRuntime().exec("cat /sys/class/net/wlan0/address "); InputStreamReader ir = new InputStreamReader(pp.getInputStream()); LineNumberReader input = new LineNumberReader(ir); for (; null != str;) { str = input.readLine(); if (str != null) { macSerial = str.trim(); break; } } } catch (IOException ex) { ex.printStackTrace(); } Helper.showLog(TAG, "getMacAddressByCommand:" + macSerial); return macSerial; } // Get Mac Address by Java API public static String getMacAddressByAPI(Context context) { WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); String macAddressAPI = null; if (wifi != null) { //Try to get mac address firstly,if empty,need switch on WIFI try { if (macAddressAPI == null) { WifiInfo info = wifi.getConnectionInfo(); macAddressAPI = info.getMacAddress(); } } catch (Exception e) {} if(macAddressAPI == null){ Helper.showLog(TAG, "getMacAddressByAPI:WIFI not init,need to switch on WIFI"); int state =wifi.getWifiState(); boolean isWifiEnabled = (state == WifiManager.WIFI_STATE_ENABLED) || (state == WifiManager.WIFI_STATE_ENABLING); if (!isWifiEnabled) { wifi.setWifiEnabled(true); } try { if (macAddressAPI == null) { WifiInfo info = wifi.getConnectionInfo(); macAddressAPI = info.getMacAddress(); } } catch (Exception e) { } finally { if (!isWifiEnabled) { wifi.setWifiEnabled(false); } } }else{ Helper.showLog(TAG, "getMacAddressByAPI:no need to switch on WIFI"); } } Helper.showLog(TAG, "getMacAddressByAPI:" + macAddressAPI); return macAddressAPI; }
需要申请 权限
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
我在这里尝试使用了两种方法的组合去获取mac地址,第一种方法是使用shell命令读取设备节点文件,获取mac地址,但是该值仅在WIFI开启的时候有效。而第二种方法则可以在WIFI关闭的情况下读取,这里也有一个限制,就是WIFI在开机后,有被开启过才行(虽然开启后再关闭也是可以的)。而且WIFI被动开启的期间也是没有办法读取到Mac地址的,因此开启的工作需要在前面完成,因此可以在程序加载的时候就去尝试开机一次WIFI,然后关闭掉。后面需要使用Mac地址的时候,就可以直接读取了。
对于Mac地址的获取,网上海有通过调用Linux的busybox来获取,参考代码如下
/* ***************************************************************** * 子函数:获得本地MAC地址 ***************************************************************** */ public String getMacAddress(){ String result = ""; String Mac = ""; result = callCmd("busybox ifconfig","HWaddr"); //如果返回的result == null,则说明网络不可取 if(result==null){ return "网络出错,请检查网络"; } //对该行数据进行解析 //例如:eth0 Link encap:Ethernet HWaddr 00:16:E8:3E:DF:67 if(result.length()>0 && result.contains("HWaddr")==true){ Mac = result.substring(result.indexOf("HWaddr")+6, result.length()-1); Log.i("test","Mac:"+Mac+" Mac.length: "+Mac.length()); if(Mac.length()>1){ Mac = Mac.replaceAll(" ", ""); result = ""; String[] tmp = Mac.split(":"); for(int i = 0;i<tmp.length;++i){ result +=tmp[i]; } } Log.i("test",result+" result.length: "+result.length()); } return result; } public String callCmd(String cmd,String filter) { String result = ""; String line = ""; try { Process proc = Runtime.getRuntime().exec(cmd); InputStreamReader is = new InputStreamReader(proc.getInputStream()); BufferedReader br = new BufferedReader (is); //执行命令cmd,只取结果中含有filter的这一行 while ((line = br.readLine ()) != null && line.contains(filter)== false) { //result += line; Log.i("test","line: "+line); } result = line; Log.i("test","result: "+result); } catch(Exception e) { e.printStackTrace(); } return result; }
但是需要设备支持busybox,但是默认的手机貌似都不支持,需要自己root后填入该工具,这个不适合开发应用。
另外还有一些方案,参照http://www.cnblogs.com/Amandaliu/archive/2011/11/06/2238177.html
- Android设备唯一标识的讨论(一)
- Android设备唯一标识的讨论(二)
- Android设备的唯一标识
- Android设备的唯一标识
- 如何唯一的标识一台Android设备
- android设备唯一标识
- 获取 Android 设备的唯一标识码
- 获取 Android 设备的唯一标识码
- 获取 Android 设备的唯一标识码
- android获得设备的全球唯一标识
- Android设备唯一标识ID的获取
- 获取 Android 设备的唯一标识码
- 获取 Android 设备的唯一标识码
- 获得android设备的唯一标识
- 设备的唯一标识
- 获取Android设备唯一标识(唯一序列号)
- android 手机设备唯一标识
- android 手机设备唯一标识
- POJ 2356 find multiple 鸽巢原理
- 实现MapReduce多文件自定义输出
- Maximum Depth of Binary Tree
- Hadoop安全模式
- [JAR包] android引入JAR包,打包成JAR包,打包成Library项目,导入Library项目
- Android设备唯一标识的讨论(一)
- Magento模块中添加计划任务Cron Job【magento二次开发】
- 时针和分针多久重合一次
- js数组去重复项
- According to TLD or attribute directive in tag file, attribute test does not accept any expressions
- 几种视频加密算法介绍
- Oracle Bulk Collect 学习
- third-order intercept understander
- Android ViewPager+Fragment 仿 Google Play