详解Android获取设备唯一ID的几种方式
先来看看几种比较单一的方式:
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,
以下几个是*上评论较多的几个,没贴完,还有其他,综合的,用到以上的部分方式:
地址:
有兴趣的朋友可以再仔细看看
支持率比较高的(支持票数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://*.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://*.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 = ""; if (deviceid != null && !"".equals(deviceid)) { return deviceid; } 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的官方博客中也提到了,不过以上几种方案,应该可以满足平时的需求,大家可以选择其中自己认为比较好的,用于自己的项目中。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。