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

 

0 0
原创粉丝点击