最近做的一个项目中需要用到Android设备唯一码(UUID)来标识一台设备,Android中设备唯一码有很多,如:MAC地址、IMEI号(DeviceId)、IMSI号、ANDROID_ID、序列号(SerialNumber)等,但并不是所有设备上都能稳定获取到这些值。

最后项目中采用的是MAC地址。

先总结一些搜索得知的各种值的缺点,再说说最后采用MAC地址的解决方案吧。
 

1.MAC地址:
Mac是设备网卡的唯一设别码,该码全球唯一,一般称为物理地址,硬件地址用来定义设备的位置。

获取MAC地址的方法有两种:

(1). 通过Linux命令查询

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public String getMacAddress() {

    String macAddress = null;

    String str = "";

    try {

        //linux下查询网卡mac地址的命令

        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) {

                macAddress = str.trim();// 去空格

                break;

            }

        }

    } catch (IOException ex) {

        ex.printStackTrace();

    }

    return macAddress;

}

缺点:

在当前没打开WiFi的情况下获取得到的MAC地址值为空,即使在执行这段代码前是有打开过WiFi,而执行这段代码时WiFi状态是关闭的,也不能获取到MAC地址。

 

(2). 通过Android官方的WifiManager类获取

1

2

3

4

5

6

7

8

9

10

11

public String getMacAddress() {

 

    String macAddress = null;

         

    WifiManager wifiManager =

        (WifiManager)MyApplication.getContext().getSystemService(Context.WIFI_SERVICE);

    WifiInfo info = (null == wifiManager ? null : wifiManager.getConnectionInfo());

         

    macAddress = info.getMacAddress();

    return macAddress;

}

需要加入权限

1

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

缺点:

这种方法虽然能在当前Wifi状态为关闭的情况下获取到MAC地址,但前提是在手机开机后要打开过一次Wifi,如果在某次开机后没打开过Wifi就调用这段代码,获取地址也是为空。

网上给出的解释是:WiFi的Mac address是一个被动资讯。一般在开机后,不会主动上报到系统裡。要待WiFi硬件启动后,才会把有关Mac address资料记载入系统去。

在Android6.0以后 google 为了运行时权限,对geMacAddress()作出修改。通过该方法得到的mac地址永远是一样的, 但是可以其他途径获取。

/*        获取mac地址有一点需要注意的就是android 6.0版本后,以下注释方法不再适用, 不管任何手机都会返回"02:00:00:00:00:00"这个默认的mac地址, 这是googel官方为了加强权限管理而禁用了getSYstemService(Context.WIFI_SERVICE)方法来获得mac地址。         */        // String macAddress= "";        // WifiManager wifiManager = (WifiManager) MyApp.getContext().getSystemService(Context.WIFI_SERVICE);        // WifiInfo wifiInfo = wifiManager.getConnectionInfo();        // macAddress = wifiInfo.getMacAddress();        // return macAddress;                String macAddress = null;        StringBuffer buf = new StringBuffer();        NetworkInterface networkInterface = null;        try {            networkInterface = NetworkInterface.getByName("eth1");            if (networkInterface == null) {                networkInterface = NetworkInterface.getByName("wlan0");            }            if (networkInterface == null) {                return "02:00:00:00:00:02";            }            byte[] addr = networkInterface.getHardwareAddress();            for (byte b : addr) {                buf.append(String.format("%02X:", b));            }            if (buf.length() > 0) {                buf.deleteCharAt(buf.length() - 1);            }            macAddress = buf.toString();        } catch (SocketException e) {            e.printStackTrace();            return "02:00:00:00:00:02";        }        return macAddress;    }

 

 

2.IMEI号(DeviceId)、IMSI号:

1

2

3

TelephonyManager mTelephonyMgr = (TelephonyManager) getSystemServic(Context.TELEPHONY_SERVICE);

String imsi = mTelephonyMgr.getSubscriberId();  //获取IMSI号

String imei = mTelephonyMgr.getDeviceId();  //获取IMEI号

需要加入权限

1

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

缺点:

IMEI号(国际移动设备身份码)、IMSI号(国际移动设备识别码)这两个是有电话功能的移动设备才具有,也就是说某些没有电话功能的平板是获取不到IMEI和IMSI号的。且在某些设备上getDeviceId()会返回垃圾数据。

 

3.ANDROID_ID:

ANDROID_ID 是设备首次启动时由系统随机生成的一串64位的十六进制数字。

1

String ANDROID_ID = Settings.System.getString(getContentResolver(), Settings.System.ANDROID_ID);

缺点:

①.设备刷机wipe数据或恢复出厂设置时ANDROID_ID值会被重置。

②.现在网上已有修改设备ANDROID_ID值的APP应用。

③.某些厂商定制的系统可能会导致不同的设备产生相同的ANDROID_ID。

④.某些厂商定制的系统可能导致设备返回ANDROID_ID值为空。

⑤.CDMA设备,ANDROID_ID和DeviceId返回的值相同

 

4.序列号SerialNumber:

从Android 2.3开始,通过android.os.Build.SERIAL方法可获取到一个序列号。没有电话功能的设备也都需要上给出此唯一的序列号。

1

String SerialNumber = android.os.Build.SERIAL;

缺点:

在某些设备上此方法会返回垃圾数据。


 

1.5 UniquePsuedoID

具体称呼不明, 但是从以下的情况看出是一些列硬件信息拼装获取到的内容。

1.5.1 具体的获取方式
 

public static String getUniquePsuedoID()  {     String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);        // Thanks to @Roman SL!      // http://stackoverflow.com/a/4789483/950427      // Only devices with API >= 9 have android.os.Build.SERIAL      // http://developer.android.com/reference/android/os/Build.html#SERIAL      // If a user upgrades software or roots their phone, there will be a duplicate entry      String serial = null;      try      {          serial = android.os.Build.class.getField("SERIAL").get(null).toString();            // Go ahead and return the serial for api => 9          return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();      }      catch (Exception e)      {          // String needs to be initialized          serial = "serial"; // some value      }        // Thanks @Joe!      // http://stackoverflow.com/a/2853253/950427      // Finally, combine the values we have found by using the UUID class to create a unique identifier      return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();  }

缺点:

由于是与设备信息直接相关,如果是同一批次出厂的的设备有可能出现生成的内容可能是一样的。(通过模拟器实验过,打开两个完全一样的模拟器,生成的内容是完全一下),所以如果单独使用该方法也是不能用于生成唯一标识符的。



 

解决方案:

一种比较折衷的办法,在获取MAC地址之前先判断当前WiFi状态,若开启了Wifi,则直接获取MAC地址,若没开启Wifi,则用代码开启Wifi,然后马上关闭,再获取MAC地址。

目前此方法测试成功,无论在哪种状态下都能正确取得设备的MAC地址(包括开机后未启动过Wifi的状态下),且在未开启Wifi的状态下,用代码开启Wifi并马上关闭,过程极短,不会影响到用户操作。

代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public String getMacAddress() {

 

    String macAddress = null;

    WifiManager wifiManager =

        (WifiManager)MyApplication.getContext().getSystemService(Context.WIFI_SERVICE);

    WifiInfo info = (null == wifiManager ? null : wifiManager.getConnectionInfo());

         

    if (!wifiManager.isWifiEnabled())

    {

        //必须先打开,才能获取到MAC地址

        wifiManager.setWifiEnabled(true);

        wifiManager.setWifiEnabled(false);

    }

    if (null != info) {

        macAddress = info.getMacAddress();

    }

    return macAddress;

}

需要加入如下权限

1

2

3

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"> uses-permission>

<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"> uses-permission>

<uses-permission android:name="android.permission.WAKE_LOCK"> uses-permission>

转自:http://www.goteny.com/develop/android/201412/452.html




 

更多相关文章

  1. ADB 连接不上 Android 设备
  2. ADB通过WIFI连接Android设备
  3. 获取Android设备常规参数信息(SN,IMEI)及定制信息
  4. Android 蓝牙通信开发(一) 搜索蓝牙设备
  5. Android的默认虚拟机地址
  6. Android 应用程序查找设备的方法——以串口为例
  7. Android设备一对多录屏直播--(UDP组播连接,Tcp传输)
  8. 电脑控制Android设备的软件——Total Control
  9. Android 定位地址,获取经纬度,并转换为中文地址

随机推荐

  1. The option 'android.enableAapt2' is de
  2. android接收adb发送的系统广播及自定义广
  3. Android(安卓)MVP代码生成插件MVPHelper
  4. Android实现中文词组转大写字母
  5. ScrollView中的控件占据ScrollView的matc
  6. 使用h5+下载并打开文件,支持Android,IOS
  7. Android-Toast的使用方法详解
  8. Android常见系统广播
  9. Android(安卓)系统中WiFi的部署
  10. android froyo framework内RIL.java类分