转至http://blog.csdn.net/u014651216/article/details/50767326
IMEI
方式:TelephonyManager.getDeviceId():
问题
范围:只能支持拥有通话功能的设备,对于平板不可以。
持久性:返厂,数据擦除的时候不彻底,保留了原来的标识。
权限:需要权限:Android.permission.READ_PHONE_STATE
bug: 有些厂家的实现有bug,返回一些不可用的数据
Mac地址
ACCESS_WIFI_STATE权限
有些设备没有WiFi,或者蓝牙,就不可以,如果WiFi没有打开,硬件也不会返回Mac地址,不建议使用
ANDROID_ID
2.2(Froyo,8)版本系统会不可信,来自主要生产厂商的主流手机,至少有一个普遍发现的bug,这些有问题的手机相同的ANDROID_ID: 9774d56d682e549c
但是如果返厂的手机,或者被root的手机,可能会变
Serial Number
从Android 2.3 (“Gingerbread”)开始可用,可以通过android.os.Build.SERIAL获取,对于没有通话功能的设备,它会
返回一个唯一的device ID,
以下几个是stackoverflow上评论较多的几个,没贴完,还有其他,综合的,用到以上的部分方式:
地址:http://stackoverflow.com/questions/2785485/is-there-a-unique-android-device-id
google官方的相关博客:http://android-developers.blogspot.com/2011/03/identifying-app-installations.html
有兴趣的朋友可以再仔细看看
支持率比较高的(支持票数157):androidID --> 剔除2.2版本(API 8)中有问题的手机,使用UUID替代
- import android.content.Context;
- import android.content.SharedPreferences;
- import android.provider.Settings.Secure;
- import android.telephony.TelephonyManager;
- import java.io.UnsupportedEncodingException;
- import java.util.UUID;
- public class DeviceUuidFactory {
- protected static final String PREFS_FILE = "device_id.xml";
- protected static final String PREFS_DEVICE_ID = "device_id";
- protected static volatile UUID uuid;
- public DeviceUuidFactory(Context context) {
- if (uuid == null) {
- synchronized (DeviceUuidFactory.class) {
- if (uuid == null) {
- final SharedPreferences prefs = context
- .getSharedPreferences(PREFS_FILE, 0);
- final String id = prefs.getString(PREFS_DEVICE_ID, null);
- if (id != null) {
- // Use the ids previously computed and stored in the
- // prefs file
- uuid = UUID.fromString(id);
- } else {
- final String androidId = Secure.getString(
- context.getContentResolver(), Secure.ANDROID_ID);
- // Use the Android ID unless it's broken, in which case
- // fallback on deviceId,
- // unless it's not available, then fallback on a random
- // number which we store to a prefs file
- try {
- if (!"9774d56d682e549c".equals(androidId)) {
- uuid = UUID.nameUUIDFromBytes(androidId
- .getBytes("utf8"));
- } else {
- final String deviceId = ((TelephonyManager)
- context.getSystemService(
- Context.TELEPHONY_SERVICE)
- .getDeviceId();
- uuid = deviceId != null ? UUID
- .nameUUIDFromBytes(deviceId
- .getBytes("utf8")) : UUID
- .randomUUID();
- }
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- // Write the value out to the prefs file
- prefs.edit()
- .putString(PREFS_DEVICE_ID, uuid.toString())
- .commit();
- }
- }
- }
- }
- }
- /**
- * Returns a unique UUID for the current android device. As with all UUIDs,
- * this unique ID is "very highly likely" to be unique across all Android
- * devices. Much more so than ANDROID_ID is.
- *
- * The UUID is generated by using ANDROID_ID as the base key if appropriate,
- * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
- * be incorrect, and finally falling back on a random UUID that's persisted
- * to SharedPreferences if getDeviceID() does not return a usable value.
- *
- * In some rare circumstances, this ID may change. In particular, if the
- * device is factory reset a new device ID may be generated. In addition, if
- * a user upgrades their phone from certain buggy implementations of Android
- * 2.2 to a newer, non-buggy version of Android, the device ID may change.
- * Or, if a user uninstalls your app on a device that has neither a proper
- * Android ID nor a Device ID, this ID may change on reinstallation.
- *
- * Note that if the code falls back on using TelephonyManager.getDeviceId(),
- * the resulting ID will NOT change after a factory reset. Something to be
- * aware of.
- *
- * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
- * directly.
- *
- * @see http://code.google.com/p/android/issues/detail?id=10603
- *
- * @return a UUID that may be used to uniquely identify your device for most
- * purposes.
- */
- public UUID getDeviceUuid() {
- return uuid;
- }
- }
根据版本进行判断的方式:Serial序列号-->UUID (支持数31)
通过Serial 即可,在覆盖率上,你已经成功的获得了98.4%的用户,剩下的1.6%的用户系统是在9 以下的。
通过AndroidID获取,前面已经说过,在8上,有些商家的手机会有一些bug,返回相同的AndroidID,如果Serial和AndroidID都不行
- /**
- * Return pseudo unique ID
- * @return ID
- */
- public static String getUniquePsuedoID()
- {
- // If all else fails, if the user does have lower than API 9 (lower
- // than Gingerbread), has reset their phone or 'Secure.ANDROID_ID'
- // returns 'null', then simply the ID returned will be solely based
- // off their Android device information. This is where the collisions
- // can happen.
- // Thanks http://www.pocketmagic.net/?p=1662!
- // Try not to use DISPLAY, HOST or ID - these items could change.
- // If there are collisions, there will be overlapping data
- 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();
- }
不用READ_PHONE_STATE权限直接获取ROM信息的方式:(支持率较低 16)
- String m_szDevIDShort = "35" + //we make this look like a valid IMEI
- Build.BOARD.length()%10+ Build.BRAND.length()%10 +
- Build.CPU_ABI.length()%10 + Build.DEVICE.length()%10 +
- Build.DISPLAY.length()%10 + Build.HOST.length()%10 +
- Build.ID.length()%10 + Build.MANUFACTURER.length()%10 +
- Build.MODEL.length()%10 + Build.PRODUCT.length()%10 +
- Build.TAGS.length()%10 + Build.TYPE.length()%10 +
- Build.USER.length()%10 ; //13 digits
最后贴上自己在项目中用的:
- public static String getDeviceId(Context context) {
- String deviceId = "";
- <span style="white-space:pre"> </span>if (deviceId != null && !"".equals(deviceId)) {
- <span style="white-space:pre"> </span>return deviceId;
- <span style="white-space:pre"> </span>}
- if (deviceId == null || "".equals(deviceId)) {
- try {
- deviceId = getLocalMac(context).replace(":", "");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- if (deviceId == null || "".equals(deviceId)) {
- try {
- deviceId = getAndroidId(context);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- if (deviceId == null || "".equals(deviceId)) {
- if (deviceId == null || "".equals(deviceId)) {
- UUID uuid = UUID.randomUUID();
- deviceId = uuid.toString().replace("-", "");
- writeDeviceID(deviceId);
- }
- }
- return deviceId;
- }
- // IMEI码
- private static String getIMIEStatus(Context context) {
- TelephonyManager tm = (TelephonyManager) context
- .getSystemService(Context.TELEPHONY_SERVICE);
- String deviceId = tm.getDeviceId();
- return deviceId;
- }
- // Mac地址
- private static String getLocalMac(Context context) {
- WifiManager wifi = (WifiManager) context
- .getSystemService(Context.WIFI_SERVICE);
- WifiInfo info = wifi.getConnectionInfo();
- return info.getMacAddress();
- }
- // Android Id
- private static String getAndroidId(Context context) {
- String androidId = Settings.Secure.getString(
- context.getContentResolver(), Settings.Secure.ANDROID_ID);
- return androidId;
- }
- public static void saveDeviceID(String str) {
- try {
- FileOutputStream fos = new FileOutputStream(file);
- Writer out = new OutputStreamWriter(fos, "UTF-8");
- out.write(str);
- out.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static String readDeviceID() {
- StringBuffer buffer = new StringBuffer();
- try {
- FileInputStream fis = new FileInputStream(file);
- InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
- Reader in = new BufferedReader(isr);
- int i;
- while ((i = in.read()) > -1) {
- buffer.append((char) i);
- }
- in.close();
- return buffer.toString();
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- }
对于获取设备唯一ID并没有绝对的方案,这一点在android的官方博客中也提到了,不过以上几种方案,应该可以满足平时的需求,大家可以选择其中自己认为比较好的,用于自己的项目中。不知道其他朋友在项目中是如何处理的,欢迎交流讨论。