详解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的官方博客中也提到了,不过以上几种方案,应该可以满足平时的需求,大家可以选择其中自己认为比较好的,用于自己的项目中。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。