想必大家在开发Android项目的时候,多多少少会遇到“如何惟一地标识一台Android设备”等类似的问题。不只是以前,即使是现在乃至可以预见的将来,这个问题都将一直存在。

如果大家使用搜索工具搜索的话,大家也能够找到很多的解决方案,但每种方式都多多少少有些缺陷。

我在这里呢,将向大家解释一下诸多常见方案的不足之处,以及推荐一种相对而言比较靠谱的方法。

首先先要说明一下Android设备的情况。我们大家都知道,在起初的时候,Android设备仅仅意味着是“手机”。如果情况一直是这样就好了。可是事实并不是这样的,我们知道,随着Google以及Android的发展壮大,Android系统在除了支持手机之外,也开始向其它领域发展。截止到Android 5.0的时候,Android系统已经能够支持诸如手持设备、可穿戴设备等,详细来说就是已经支持手机、平板、手表、眼镜、电视、盒子以及汽车。所有的这些情况将影响各个解决方案的实际效果。

好,下面我们来一一揭开各个解决方案不足之处的神秘面纱。

ANDROID_ID

ANDROID_ID存在于android.provider.Settings.Secure.ANDROID_ID.它可以通过下面的方式获取得到:

1 String android_id = Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID); 
View Code

这一个64位的16进制字符串。它在设备首次启动时被创建并存储起来。但是在设备恢复出厂设置或者刷机之时,将不得存在,只能在再次启动时重新生成。这是它的劣势之一。然后,还有,在2.2之前,这种方式并不是百分百可靠的。其次,在主要手持设备生产商生产的流行设备中,还有一个可以被显著观测到的bug,那就是诸多设备拥有相同的ANDROID_ID。所以,ANDROID_ID并不是一个完美的解决方案。

DEVICEID

DEVICEID,顾名思义,“设备id”。是由手机运营商添加进手机中的。它可以通过以下方式获取到:

1 TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);2 String tmDevice = "" + tm.getDeviceId();
View Code

它的返回值将依据运营商的不同,可能返回手机的IMEI或MEID或ESN。由于它是手机运营商添加进去的,所以可能存在收下诸多问题:

  • 非手机:对于不能打电话的平板、智能手表、电视甚至汽车等非手机设备,并不存在这种惟一的标识符。
  • 持续性问题:在拥有DEVICEID的设备上,在经过刷机或者工厂设置后,这个值有可能没有被清理干净。如果是这种情况,我们可能将它们认为是同一设备。
  • 优先级问题:想要获取deviceid需要READ_PHONE_STATE权限。如果你在应用中并未使用到电话,使用这个权限将会很令人不安。
  • 已知Bug问题:这种方式的实现在有些机器上是有bug的,会返回一些垃圾信息,比如0或者"*".

所以,DEVICEID也不能完美的解决这个问题。

SIMSERIALNUMBER

SimSerialNumber也是由手机运营商放进去的,它的获取方式是这样的:

1 TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);2 String tmSerial = "" + tm.getSimSerialNumber();
View Code

它的不靠谱之处也尤如DeviceId。

SERIALNUMBER

它是2.3之后才引入的。它的值存在于android.os.Build.SERIAL.SerialNumber。但是对于不支持通话的设备,得先需要唯一的deviceid。

Mac地址

也许有人可能想到依据设备的WiFi或者蓝牙硬件来获取Mac地址来惟一标识设备。但是这种方式是不值得推荐的。因为它并非问题可以获取得到的,因为它需要设备WiFi或者蓝牙开着。所以,如果设备不打开蓝牙呢?如果设备没有打开WiFi而是使用的2G、3G或者4G呢?所以这也是一个不靠谱的方式。

UUID

以上几种标识Android设备的方式都不尽如人意思。难道就没有一种方式可以稳定、可靠且唯一地标识Androi硬件设备的吗?

诶,等一等,标识Android设备非得使用设备的硬件信息吗?难得使用非硬件就不能标识设备了吗?

好吧,答案是UUID。UUID(Universal Unique ID)是软件界的“通用唯一ID”,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成的API。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字

UUID由以下几部分的组合:
  1. 当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同。
  2. 时钟序列。
  3. 全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得。
UUID的唯一缺陷在于生成的结果串会比较长。关于UUID这个标准使用最普遍的是微软的GUID(Globals Unique Identifiers)。在ColdFusion中可以用CreateUUID()函数很简单地生成UUID,其格式为:xxxxxxxx-xxxx- xxxx-xxxxxxxxxxxxxxxx(8-4-4-16),其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。而标准的UUID格式为:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx (8-4-4-4-12),可以从cflib 下载CreateGUID() UDF进行转换。

对于一个开发人员而言,想要追踪应用的每一次安装,是非常普遍,也十分合乎情理的。要追踪应用的安装,你可以使用UUID来作为标识,在安装之后应用首次运行之时创建它。下面是一个叫作“Intallation”的类,带有一个静态方法id(Contextcontext),返回应用的UUID。你可以将更多有关安装的数据写入”ISTALLATION”文件中。

 1 public class Installation { 2   private static String sID = null; 3   private static final String INSTALLATION = "INSTALLATION"; 4  5   public synchronized static String id(Context context) { 6     if (sID == null) {  7       File installation = new File(context.getFilesDir(), INSTALLATION); 8       try { 9         if (!installation.exists())10           writeInstallationFile(installation);11         sID = readInstallationFile(installation);12       } catch (Exception e) {13         throw new RuntimeException(e);14       }15     }16     return sID;17   }18 19   private static String readInstallationFile(File installation) throws IOException {20     RandomAccessFile f = new RandomAccessFile(installation, "r");21     byte[] bytes = new byte[(int) f.length()];22     f.readFully(bytes);23     f.close();24     return new String(bytes);25   }26 27   private static void writeInstallationFile(File installation) throws IOException {28     FileOutputStream out = new FileOutputStream(installation);29     String id = UUID.randomUUID().toString();30     out.write(id.getBytes());31     out.close();32   }33 }
Installation.java

它是通过软件产生的UUId来惟一地标识软件在该设备上的安装来标识这台设备,而非通过硬件信息。当然,这种方式是通过将UUID保存在本地文件中来实现的,如果你清空了本应用数据或者删除了该文件的话,应用将重新生成一个UUID,这也就意味着设备的惟一标识符发生了变化,这是一台新设备。

UUID是一个随机的数值,那么它万一发生了重复值呢?好吧,这是一串32位的十六进制的数字,它产生重复值的概率是16的32次方之一,自己去算概率!!!

更多相关文章

  1. 关于蓝牙设备之间共享网络的问题(android4.2)
  2. [置顶] Android 开发之旅:view的几种布局方式及实践
  3. 谈谈我的Android多渠道打包方式
  4. Android设备检测
  5. android 解析服务器数据使用json还是xml方式
  6. android中的两种打包方式,及多渠道打包
  7. android内存溢出处理方式之一
  8. android 加载图片的三种方式
  9. Android 使用HttpClient方式提交POST请求

随机推荐

  1. Android(安卓)UI之ImageView
  2. Android平台上神器Tasker的教程和其他参
  3. Android开发学习资源
  4. Android(安卓)Studio官方文档之在Android
  5. android debug set screen rotation
  6. 解析Android中的线程
  7. 在线生成免费android ios图标
  8. Android四大图片缓存框架之-Fresco(一)
  9. Android(安卓)Studio或Idea中必备插件、
  10. android 消息机制浅析