最近做的一个项目中需要用到Android设备唯一码(UUID)来标识一台设备,

Android中设备唯一码有很多,如:MAC地址、IMEI号(DeviceId)、IMSI号、ANDROID_ID、序列号(SerialNumber)等,

但并不是所有设备上都能稳定获取到这些值。

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

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

1.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资料记载入系统去。

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;

缺点:

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

解决方案:

一种比较折衷的办法,在获取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

极光推送的设备唯一性标识 RegistrationID

对于 App 云平台系统,如何唯一地识别移动设备是非常重要的。否则,每次用户在设备上卸载掉应用再重新安装,后端系统只能把这个用户当作一个全新的用户了。

Android 上识别设备的唯一性,因为这个圈太乱,所以设备本身的任何标识都是无法直接用作设备唯一标识的。iOS 是系统强力限制被唯一识别的,目前唯一可以部分满足条件是 IDFA,但需要你的 App 本身的确嵌入了广告。

很多开发者使用极光推送时,都有这个疑问:极光推送是如何来做设备的唯一性识别的。本文解析极光推送如何尽可能地来唯一识别设备。

极光推送对安装在设备上的 App 使用 RegistrationID 作为标识。极光推送要『尽可能』确保设备的唯一性,就是要使得 RegistrationID 尽可能唯一。

RegistrationID 的定义

关于 RegistrationID 极光官方文档有如下的定义:

集成了 JPush SDK 的应用程序在第一次 App 启动后,成功注册到 JPush 服务器时,JPush 服务器会给客户端返回唯一的该设备的标识 – RegistrationID。JPush SDK 会以广播的形式发送 RegistrationID 到应用程序。

有了这个标识,App 编程可以把这个 RegistrationID 保存到自己的应用服务器上,然后就可以根据 RegistrationID 来向设备推送消息或者通知。

RegistrationID 变化可能性

如果 App 不卸载,是直接覆盖安装,Android, iOS 上 RegistrationID 的值都不会变化。

如果 App 是卸载之后再次安装:

  • Android 上 RegistrationID 基本不会变;
  • iOS 上如果启用了 IDFA 变化可能性不大,如果未启用 IDFA 则每次安装 RegistrationID 都会变;

RegistrationID 生成规则解析

Android 平台

Android 上因为国内存在大量山寨设备的原因,正常的 IMEI, Mac Address, AndroidID 这些可以考虑用作唯一标识的值,都是不可以用的,因为这些值在一批设备中可能都是同一个值。

极光的基本思路是:

  1. 生成一个 DeviceID 保存到 Settings, External Storage。依赖本地存储,应用被卸载后重新安装这些存储里的 DeviceID 还在的话,就是同一个设备。这一条理论上解决 90% 的不变性问题。
  2. DeviceID 之外增加补充规则:综合根据 IMEI, MAC Address, AndroidID 这几个值来判断,是否可能是老设备。

具体的逻辑细节,也是根据实际运行情况,以及收集到的反馈不断调整的,大多数逻辑可在服务器端调整。

iOS平台

鉴于 iOS 系统设计上限制设备唯一标识,所以极光一直使用 Device Token 作为标识,也因为极光推送本身就是需要 Device Token 这个值才可能运作的。

iOS 9 版本之后,每次卸载后重装都会导致 Device Token 变化,所以对于极光后台来说,都只能被识别为新用户。

极光 SDK 新版本增加了 IDFA 选项,在集成初始化 SDK 时可选把 IDFA 这个值设置进来,这样极光后台就优先根据 IDFA 值来识别用户,从有一定的可能性应用被卸载后重装还能识别回老设备。

IDFA 是广告标识符,是 iOS 专门为广告跟踪唯一地识别用户而设计的。在 iOS 设备上,设备 -> 隐私 -> 广告这个页面,有一个设置项:限制广告跟踪。默认是未选中状态的,即是关闭状态,是不限制的。用户可以选中,从而限制广告跟踪。设置项之外还有一个按钮:还原广告标识符…。如果用户点击了这个按钮,则 IDFA 值会变化。

 

默认的情况下,没有限制广告跟踪,可以取到 IDFA 这个值。并且用户未点击『还原广告标识』时,这个值是不会变的。这样就达到了唯一地标识设备、跟踪到用户的目标。

但是,但是,请一定留意,IDFA 并不是一定可以启用的,是需要你的 App 的确有广告功能才可以用的,否则 Apple 在上架审核时有可能发现从而拒绝上架。

关于苹果 App 上架对 IDFA 的要求,可参考这里的说明:The Advertising Identifier (IDFA)

高级使用建议

因为 RegistrationID 是 JPush SDK 注册完成之后才得到的,所以调用 SDK API 来获取 RegistrationID 的值时需要稍注意,不是总能够立即得到。

比如 iOS 上建议在监听到 kJPFNetworkDidLoginNotification 这个通知后的代码里,来获取 RegistrationID 的值。

Android 上有写 Settings 的权限,是可以写数据到 Settings 里边的,相当于被当作一个永久存储点了。 外部存储一般指 SDCard,现在越来越多手机直接手机自带了,类似于 iPhone 的作法。

这 2 个点如果数据都被破坏了,就的确通过本地 DeviceID 存储无法确认为唯一设备了。但是,服务器端还可以通过 IMEI/AndroidID 这些灵活地确认到是否同一设备。

以上转自  http://blog.jiguang.cn/registrationid/

稳定获取Android设备唯一码(UUID)的解决方案的更多相关文章

  1. Android设备唯一码的获取

    Android设备唯一码的获取 UTDID是集团无线设备统一ID方案,目的是给每一台设备一个ID,作为唯一标识.UTDID由客户端生成,并在设备中各个客户端之间共享.UTDID的生成中包含时间戳和随机 ...

  2. 获取Android设备唯一标识码

    概述 有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一的识别码.虽然Android系统中提供了这样设备识别码,但是由于Android系统版本.厂商定制系统中的Bug等限制,稳定性和唯一 ...

  3. android 设备唯一码的获取,Cpu号,Mac地址

    开发Android应用中,我们常常需要设备的唯一码来确定客户端. Android 中的几中方法,使用中常常不可靠 1. DEVICE_ID 假设我们确实需要用到真实设备的标识,可能就需要用到DEVIC ...

  4. android设备唯一码的获取,cpu号,mac地址

    抄自http://blog.csdn.net/hpccn/article/details/7872141 开发Android应用中,我们常常需要设备的唯一码来确定客户端. Android 中的几中方法 ...

  5. Android 获取手机(ios,android)的设备唯一码(mac地址, IMEI)

    { /*获取手机(ios,android)的设备唯一码(mac地址, IMEI)2018年02月16日 ⁄ 综合 ⁄ 共 2697字 ⁄ 字号 小 中 大 ⁄ 评论关闭 app中总会用到客户端下载量数 ...

  6. 获取设备唯一标识 uuid(采用第三方库SSKeychain)

    SSKeyChain 下载链接: http://pan.baidu.com/s/1booV3VD 密码: ivdi /** *  获取设备唯一标识 uuid */ +(NSString*) uuid ...

  7. 获取iOS设备唯一标识

    [获取iOS设备唯一标识] 1.已禁用-[UIDevice uniqueIdentifier] 苹果总是把用户的隐私看的很重要.-[UIDevice uniqueIdentifier]在iOS5实际在 ...

  8. 获取Android设备屏幕分辨率

    1.Android 4.3引入的wm工具: a.获取Android设备屏幕分辨率: adb shell wm size b.获取android设备屏幕密度: adb shell wm density ...

  9. Android 开发 获取Android设备的屏幕高宽

    获得屏幕的宽度和高度有很多种方法: //1.通过WindowManager获取 DisplayMetrics dm = new DisplayMetrics(); heigth = dm.height ...

随机推荐

  1. Docker Engine SDKs and API 的开发1

    Develop with Docker Engine SDKs and API Docker provides an API for interacting with the Docker daemo ...

  2. Levenshtein Distance,判断字符串的相似性

    private int LevenshteinDistance(string s1,string s2,int maxValue) { if (s1 == null|| s1.Length == 0) ...

  3. 51nod P1305 Pairwise Sum and Divide ——思路题

    久しぶり! 发现的一道有意思的题,想了半天都没有找到规律,结果竟然是思路题..(在大佬题解的帮助下) 原题戳>>https://www.51nod.com/onlineJudge/ques ...

  4. KMP字符串匹配(模板)

    描述: 给出两个字符串 s1 和 s2 ,其中 s2 为 s1 的子串,求出 s2 在 s1 中所有出现的位置.同时要求输出 s2 的 fail 数组. 思路: KMP模板. 标程: #include ...

  5. AjaxHandler

    概要 AjaxHandler组件是在ASP.NET MVC Web应用程序中实现ajax功能的一系列扩展方法,该组件的最初的实现方法借鉴了网上流行的部分源代码, ,经过博主不断完善和改进后推出的比较成 ...

  6. SpringBoot整合+logback日志配置

    本次演示的代码结构如下,基于maven,整合SpringBoot.Spring.Mybaits的SSM框架.同时测试logback日志框架的使用及配置. 1.创建maven工程,修改pom.xml文件 ...

  7. leecode第四十六题(全排列)

    class Solution { public: vector<vector<int>> permute(vector<int>& nums) { int ...

  8. web 常用颜色

    1. 推荐链接 RGB颜色值与十六进制颜色码转换工具 Web上16种基本颜色名称 WEB标准颜色 2. 个人常用 除了三原色,还有 #daf1ef#4DBCB0#ccc

  9. DOCTYPE的作用以及标准模式和兼容模式的区别

    <!doctype>声明必须处于HTML文档的头部,在<html>标签之前,告知浏览器的解析器用什么文档标准解析这个文档.DOCTYPE不存在或格式不正确会导致文档以兼容模式呈 ...

  10. 分析:java.lang.OutOfMemoryError: Java heap space

    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Hashta ...