稳定获取Android设备唯一码(UUID)的解决方案
最近做的一个项目中需要用到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 这些可以考虑用作唯一标识的值,都是不可以用的,因为这些值在一批设备中可能都是同一个值。
极光的基本思路是:
- 生成一个 DeviceID 保存到 Settings, External Storage。依赖本地存储,应用被卸载后重新安装这些存储里的 DeviceID 还在的话,就是同一个设备。这一条理论上解决 90% 的不变性问题。
- 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)的解决方案的更多相关文章
- Android设备唯一码的获取
Android设备唯一码的获取 UTDID是集团无线设备统一ID方案,目的是给每一台设备一个ID,作为唯一标识.UTDID由客户端生成,并在设备中各个客户端之间共享.UTDID的生成中包含时间戳和随机 ...
- 获取Android设备唯一标识码
概述 有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一的识别码.虽然Android系统中提供了这样设备识别码,但是由于Android系统版本.厂商定制系统中的Bug等限制,稳定性和唯一 ...
- android 设备唯一码的获取,Cpu号,Mac地址
开发Android应用中,我们常常需要设备的唯一码来确定客户端. Android 中的几中方法,使用中常常不可靠 1. DEVICE_ID 假设我们确实需要用到真实设备的标识,可能就需要用到DEVIC ...
- android设备唯一码的获取,cpu号,mac地址
抄自http://blog.csdn.net/hpccn/article/details/7872141 开发Android应用中,我们常常需要设备的唯一码来确定客户端. Android 中的几中方法 ...
- Android 获取手机(ios,android)的设备唯一码(mac地址, IMEI)
{ /*获取手机(ios,android)的设备唯一码(mac地址, IMEI)2018年02月16日 ⁄ 综合 ⁄ 共 2697字 ⁄ 字号 小 中 大 ⁄ 评论关闭 app中总会用到客户端下载量数 ...
- 获取设备唯一标识 uuid(采用第三方库SSKeychain)
SSKeyChain 下载链接: http://pan.baidu.com/s/1booV3VD 密码: ivdi /** * 获取设备唯一标识 uuid */ +(NSString*) uuid ...
- 获取iOS设备唯一标识
[获取iOS设备唯一标识] 1.已禁用-[UIDevice uniqueIdentifier] 苹果总是把用户的隐私看的很重要.-[UIDevice uniqueIdentifier]在iOS5实际在 ...
- 获取Android设备屏幕分辨率
1.Android 4.3引入的wm工具: a.获取Android设备屏幕分辨率: adb shell wm size b.获取android设备屏幕密度: adb shell wm density ...
- Android 开发 获取Android设备的屏幕高宽
获得屏幕的宽度和高度有很多种方法: //1.通过WindowManager获取 DisplayMetrics dm = new DisplayMetrics(); heigth = dm.height ...
随机推荐
- 剥开比原看代码11:比原是如何通过接口/create-account创建帐户的
作者:freewind 比原项目仓库: Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchai ...
- Linux 下上手 STC89C52RC
第一次接触单片机,自然选择了简单的51单片机.然而我的操作系统是 Linux .在 Windows 下上手51似乎很容易.但是 Linux 上搭建 51 开发环境不是很顺. 那么谈谈 Linux 我如 ...
- 【译】第39节---EF6-数据库命令日志
原文:http://www.entityframeworktutorial.net/entityframework6/database-command-logging.aspx 本节,我们学习如何记录 ...
- [从零开始搭网站三]CentOS配置JDK
点击下面连接查看从零开始搭网站全系列 从零开始搭网站 上一章我介绍了,如何不用每次都输密码连接服务器.那么这一章终于要开始服务器的开发环境配置了. 1:先输入以下代码来检验有没有已经安装的CDK: r ...
- vs 2015 编译cocos2d-x-3.9
下载地址:链接: https://pan.baidu.com/s/1IkQsMU6NoERAAQLcCUMcXQ 提取码: p1pb 或者去官网下载. 解压后,进入build文件夹,点击如下工程链接 ...
- np.zeros
np.zeros构造一个全部由0组成的矩阵 用法:zeros(shape, dtype = float, order = 'C') 参数: shape:形状 dtype类型: t ,位域,如t4代表4 ...
- 从DFS到记忆化DFS到动态规划
什么是动态规划? 动态规划(Dynamic Programming)是通过组合子问题的解来解决问题的.动态规划是用于求解包含重叠子问题的最优化问题的方法.其基本思想是,将原问题分解为相似的子问题.在求 ...
- 《剑指offer》第五十一题(数组中的逆序对)
// 面试题51:数组中的逆序对 // 题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组 // 成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. #include &l ...
- MySQL中如何建立主从复制
## 1 概述 ## MySQL内建的复制功能是构建大型,高性能应用程序的基础.将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某一台主机的数据复制到其它主机(slaves) ...
- 在Spring Boot中使用 @ConfigurationProperties 注解, @EnableConfigurationProperties
但 Spring Boot 提供了另一种方式 ,能够根据类型校验和管理application中的bean. 这里会介绍如何使用@ConfigurationProperties.继续使用mail做例子. ...