Android设备唯一标识的讨论(一)

今天我在这里讨论的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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值