详解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的手机,可能会变
SerialNumber
从Android2.3(“Gingerbread”)开始可用,可以通过android.os.Build.SERIAL获取,对于没有通话功能的设备,它会返回一个唯一的deviceID,
以下几个是stackoverflow上评论较多的几个,没贴完,还有其他,综合的,用到以上的部分方式:
地址:http://stackoverflow.com/questions/2785485/is-there-a-unique-android-device-id
有兴趣的朋友可以再仔细看看
支持率比较高的(支持票数157):androidID-->剔除2.2版本(API8)中有问题的手机,使用UUID替代
importandroid.content.Context;
importandroid.content.SharedPreferences;
importandroid.provider.Settings.Secure;
importandroid.telephony.TelephonyManager;
importjava.io.UnsupportedEncodingException;
importjava.util.UUID;
publicclassDeviceUuidFactory{
protectedstaticfinalStringPREFS_FILE="device_id.xml";
protectedstaticfinalStringPREFS_DEVICE_ID="device_id";
protectedstaticvolatileUUIDuuid;
publicDeviceUuidFactory(Contextcontext){
if(uuid==null){
synchronized(DeviceUuidFactory.class){
if(uuid==null){
finalSharedPreferencesprefs=context
.getSharedPreferences(PREFS_FILE,0);
finalStringid=prefs.getString(PREFS_DEVICE_ID,null);
if(id!=null){
//Usetheidspreviouslycomputedandstoredinthe
//prefsfile
uuid=UUID.fromString(id);
}else{
finalStringandroidId=Secure.getString(
context.getContentResolver(),Secure.ANDROID_ID);
//UsetheAndroidIDunlessit'sbroken,inwhichcase
//fallbackondeviceId,
//unlessit'snotavailable,thenfallbackonarandom
//numberwhichwestoretoaprefsfile
try{
if(!"9774d56d682e549c".equals(androidId)){
uuid=UUID.nameUUIDFromBytes(androidId
.getBytes("utf8"));
}else{
finalStringdeviceId=((TelephonyManager)
context.getSystemService(
Context.TELEPHONY_SERVICE)
.getDeviceId();
uuid=deviceId!=null?UUID
.nameUUIDFromBytes(deviceId
.getBytes("utf8")):UUID
.randomUUID();
}
}catch(UnsupportedEncodingExceptione){
thrownewRuntimeException(e);
}
//Writethevalueouttotheprefsfile
prefs.edit()
.putString(PREFS_DEVICE_ID,uuid.toString())
.commit();
}
}
}
}
}
/**
*ReturnsauniqueUUIDforthecurrentandroiddevice.AswithallUUIDs,
*thisuniqueIDis"veryhighlylikely"tobeuniqueacrossallAndroid
*devices.MuchmoresothanANDROID_IDis.
*
*TheUUIDisgeneratedbyusingANDROID_IDasthebasekeyifappropriate,
*fallingbackonTelephonyManager.getDeviceID()ifANDROID_IDisknownto
*beincorrect,andfinallyfallingbackonarandomUUIDthat'spersisted
*toSharedPreferencesifgetDeviceID()doesnotreturnausablevalue.
*
*Insomerarecircumstances,thisIDmaychange.Inparticular,ifthe
*deviceisfactoryresetanewdeviceIDmaybegenerated.Inaddition,if
*auserupgradestheirphonefromcertainbuggyimplementationsofAndroid
*2.2toanewer,non-buggyversionofAndroid,thedeviceIDmaychange.
*Or,ifauseruninstallsyourapponadevicethathasneitheraproper
*AndroidIDnoraDeviceID,thisIDmaychangeonreinstallation.
*
*NotethatifthecodefallsbackonusingTelephonyManager.getDeviceId(),
*theresultingIDwillNOTchangeafterafactoryreset.Somethingtobe
*awareof.
*
*WorksaroundabuginAndroid2.2formanydeviceswhenusingANDROID_ID
*directly.
*
*@seehttp://code.google.com/p/android/issues/detail?id=10603
*
*@returnaUUIDthatmaybeusedtouniquelyidentifyyourdeviceformost
*purposes.
*/
publicUUIDgetDeviceUuid(){
returnuuid;
}
}
根据版本进行判断的方式:Serial序列号-->UUID(支持数31)
通过Serial即可,在覆盖率上,你已经成功的获得了98.4%的用户,剩下的1.6%的用户系统是在9以下的。
通过AndroidID获取,前面已经说过,在8上,有些商家的手机会有一些bug,返回相同的AndroidID,如果Serial和AndroidID都不行
/**
*ReturnpseudouniqueID
*@returnID
*/
publicstaticStringgetUniquePsuedoID()
{
//Ifallelsefails,iftheuserdoeshavelowerthanAPI9(lower
//thanGingerbread),hasresettheirphoneor'Secure.ANDROID_ID'
//returns'null',thensimplytheIDreturnedwillbesolelybased
//offtheirAndroiddeviceinformation.Thisiswherethecollisions
//canhappen.
//Thankshttp://www.pocketmagic.net/?p=1662!
//TrynottouseDISPLAY,HOSTorID-theseitemscouldchange.
//Iftherearecollisions,therewillbeoverlappingdata
Stringm_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);
//Thanksto@RomanSL!
//http://stackoverflow.com/a/4789483/950427
//OnlydeviceswithAPI>=9haveandroid.os.Build.SERIAL
//http://developer.android.com/reference/android/os/Build.html#SERIAL
//Ifauserupgradessoftwareorrootstheirphone,therewillbeaduplicateentry
Stringserial=null;
try
{
serial=android.os.Build.class.getField("SERIAL").get(null).toString();
//Goaheadandreturntheserialforapi=>9
returnnewUUID(m_szDevIDShort.hashCode(),serial.hashCode()).toString();
}
catch(Exceptione)
{
//Stringneedstobeinitialized
serial="serial";//somevalue
}
//Thanks@Joe!
//http://stackoverflow.com/a/2853253/950427
//Finally,combinethevalueswehavefoundbyusingtheUUIDclasstocreateauniqueidentifier
returnnewUUID(m_szDevIDShort.hashCode(),serial.hashCode()).toString();
}
不用READ_PHONE_STATE权限直接获取ROM信息的方式:(支持率较低16)
Stringm_szDevIDShort="35"+//wemakethislooklikeavalidIMEI 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;//13digits
最后贴上自己在项目中用的:
publicstaticStringgetDeviceId(Contextcontext){
StringdeviceId="";
if(deviceId!=null&&!"".equals(deviceId)){
returndeviceId;
}
if(deviceId==null||"".equals(deviceId)){
try{
deviceId=getLocalMac(context).replace(":","");
}catch(Exceptione){
e.printStackTrace();
}
}
if(deviceId==null||"".equals(deviceId)){
try{
deviceId=getAndroidId(context);
}catch(Exceptione){
e.printStackTrace();
}
}
if(deviceId==null||"".equals(deviceId)){
if(deviceId==null||"".equals(deviceId)){
UUIDuuid=UUID.randomUUID();
deviceId=uuid.toString().replace("-","");
writeDeviceID(deviceId);
}
}
returndeviceId;
}
//IMEI码
privatestaticStringgetIMIEStatus(Contextcontext){
TelephonyManagertm=(TelephonyManager)context
.getSystemService(Context.TELEPHONY_SERVICE);
StringdeviceId=tm.getDeviceId();
returndeviceId;
}
//Mac地址
privatestaticStringgetLocalMac(Contextcontext){
WifiManagerwifi=(WifiManager)context
.getSystemService(Context.WIFI_SERVICE);
WifiInfoinfo=wifi.getConnectionInfo();
returninfo.getMacAddress();
}
//AndroidId
privatestaticStringgetAndroidId(Contextcontext){
StringandroidId=Settings.Secure.getString(
context.getContentResolver(),Settings.Secure.ANDROID_ID);
returnandroidId;
}
publicstaticvoidsaveDeviceID(Stringstr){
try{
FileOutputStreamfos=newFileOutputStream(file);
Writerout=newOutputStreamWriter(fos,"UTF-8");
out.write(str);
out.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
publicstaticStringreadDeviceID(){
StringBufferbuffer=newStringBuffer();
try{
FileInputStreamfis=newFileInputStream(file);
InputStreamReaderisr=newInputStreamReader(fis,"UTF-8");
Readerin=newBufferedReader(isr);
inti;
while((i=in.read())>-1){
buffer.append((char)i);
}
in.close();
returnbuffer.toString();
}catch(IOExceptione){
e.printStackTrace();
returnnull;
}
}
对于获取设备唯一ID并没有绝对的方案,这一点在android的官方博客中也提到了,不过以上几种方案,应该可以满足平时的需求,大家可以选择其中自己认为比较好的,用于自己的项目中。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。