关于本文档

Android的开发者在一些特定情况下都需要知道手机中的唯一设备ID例如,跟踪应用程序的安装,生成用于复制保护的DRM时需要使用设备的唯一ID在本文档结尾处提供了作为参考的示例代码片段。

范围

本文提供有关如何读取各种Android设备的ID的介绍,用以使用标识号。本文假定用户已经安装了Android以及开发应用程序必要的工具。并且,本文假定用户已了解Android的基本知识。

简介在搭载Android操作系统的设备中,已经存在好几种类型的设备标识号。先前的所有Android设备都具有电话功能,因此查找每部设备硬件唯一的IMEIMEID,或ESN也很容易。但仅能使用Wifi的设备或音乐播放器没有电话硬件,所以没有这种类型的唯一标识号。本文阐述了如何读取不同Android设备的标识号。检索Android设备ID各种方式

以下是Android设备不同类型的识别设备ID

·唯一编号(IMEIMEIDESNIMSI

·MAC地址

·序列号

·ANDROID_ID

唯一编号(IMEIMEIDESNIMSI

说明在以前,当Android设备均作为电话使用时,寻找唯一标识号比较简单:()可用于找到(取决于网络技术)手机硬件唯一的IMEIMEIDESNIMSI编号。

TelephonyManager.getDeviceId

IMEIMEIDESNIMSI的定义如下:

•IMEI(国际移动设备识别码)唯一编号,用于识别GSMWCDMA手机以及一些卫星电话(移动设备识别码)全球唯一编号,用于识别CDMA移动电台设备的物理硬件,MEID出现的目的是取代ESN号段(电子序列号)(电子序列号)唯一编号,用于识别CDMA手机(国际移动用户识别码)与所有GSMUMTS网络手机用户相关联的唯一识别编号如需要检索设备的ID,在项目中要使用以下代码:

•MEID

•ESN

•IMSI

[java] view plain copy
  1. importandroid.telephony.TelephonyManager;
  2. importandroid.content.Context;
  3. Stringimeistring=null;
  4. Stringimsistring=null;
  5. {
  6. TelephonyManagertelephonyManager;
  7. telephonyManager=
  8. (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
  9. /*
  10. *getDeviceId()functionReturnstheuniquedeviceID.
  11. *forexample,theIMEIforGSMandtheMEIDorESNforCDMAphones.
  12. */
  13. imeistring=telephonyManager.getDeviceId();
  14. /*
  15. *getSubscriberId()functionReturnstheuniquesubscriberID,
  16. *forexample,theIMSIforaGSMphone.
  17. */
  18. imsistring=telephonyManager.getSubscriberId();
  19. }


如要只读取手机的状态,则需添加READ_PHONE_STATE许可到AndroidManifest.xml文件中。

[java] view plain copy
  1. <uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/>


缺点

•Android设备要具有电话功能

其工作不是很可靠

序列号

当其工作时,该值保留了设备的重置信息(恢复出厂设置),从而可以消除当客户删除自己设备上的信息,并把设备转另一个人时发生的错误。

Mac地址
说明

可通过检索找到设备的Wi - Fi或蓝牙硬件的Mac地址。但是,不推荐使用Mac地址作为唯一的标识号。

缺点设备要具备Wi – Fi功能(并非所有的设备都有Wi – Fi功能)如果设备目前正在使用Wi - Fi,则不能报告Mac地址

序列号

Android 2.3姜饼)开始,通过android.os.Build.SERIAL方法序列号可被使用。没有电话功能的设备也都需要上给出唯一的设备ID;某些手机也可以需要这样做。序列号可以用于识别MID(移动互联网设备)或PMP(便携式媒体播放器),这两种设备都没有电话功能。通过读取系统属性值“ro.serialno”的方法,可以使用序列号作为设备ID如检索序列号并作为设备ID使用,请参考下面的代码示例。

[java] view plain copy
  1. importjava.lang.reflect.Method;
  2. Stringserialnum=null;
  3. try{
  4. Class<?>c=Class.forName("android.os.SystemProperties");
  5. Methodget=c.getMethod("get",String.class,String.class);
  6. serialnum=(String)(get.invoke(c,"ro.serialno","unknown"));
  7. }
  8. catch(Exceptionignored)
  9. {
  10. }


缺点

序列号无法在所有Android设备上使用。

ANDROID_ID

说明

更具体地说,Settings.Secure.ANDROID_ID 是一串64位的编码(十六进制的字符串),是随机生成的设备的第一个引导,其记录着一个固定值,通过它可以知道设备的寿命(在设备恢复出厂设置后,该值可能会改变)。 ANDROID_ID也可视为作为唯一设备标识号的一个好选择。如要检索用于设备ID 的ANDROID_ID,请参阅下面的示例代码

[java] view plain copy
  1. StringandroidId=Settings.Secure.getString(getContentResolver(),Settings.Secure.ANDROID_ID);


缺点

•对于Android 2.2(“Froyo”)之前的设备不是100%的可靠

此外,在主流制造商的畅销手机中至少存在一个众所周知的错误,每一个实例都具有相同的ANDROID_ID

结论

对于绝大多数应用来说,只需识别特定的安装配置,而不需要识别物理设备。所幸是,这样做就省去了麻烦。

下面是部分使用设备ID的最佳途径:

支持各种设备类型的另一种方法是使用getDeviceID()APIro.serialno的组合

有许多值得参考的原因,来提醒开发者避免试图识别特定的设备。对于那些想做一下这方面尝试的用户,最好的办法可能是使用ANDROID_ID,并在一些传统设备上做尝试。

示例代码

下面是用于追踪Android设置的示例代码

: ReadDeviceID.java

[java] view plain copy
  1. packagecom.deviceid;
  2. importjava.lang.reflect.Method;
  3. importandroid.app.Activity;
  4. importandroid.content.Context;
  5. importandroid.os.Bundle;
  6. importandroid.provider.Settings;
  7. importandroid.telephony.TelephonyManager;
  8. importandroid.view.View;
  9. importandroid.view.View.OnClickListener;
  10. importandroid.widget.Button;
  11. importandroid.widget.TextView;
  12. publicclassReadDeviceIDextendsActivity{
  13. Buttonbt;
  14. TextViewidView;
  15. /**Calledwhentheactivityisfirstcreated.*/
  16. @Override
  17. publicvoidonCreate(BundlesavedInstanceState){
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.main);
  20. bt=(Button)findViewById(R.id.button1);
  21. idView=(TextView)findViewById(R.id.textView1);
  22. bt.setOnClickListener(newOnClickListener(){
  23. @Override
  24. publicvoidonClick(Viewv){
  25. Stringimeistring=null;
  26. Stringimsistring=null;
  27. TelephonyManagertelephonyManager=
  28. (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
  29. /*
  30. *getDeviceId()functionReturnstheuniquedeviceID.
  31. *forexample,theIMEIforGSMandtheMEIDorESNforCDMAphones.
  32. */
  33. imeistring=telephonyManager.getDeviceId();
  34. idView.append("IMEINo:"+imeistring+"\n");
  35. /*
  36. *getSubscriberId()functionReturnstheuniquesubscriberID,
  37. *forexample,theIMSIforaGSMphone.
  38. */
  39. imsistring=telephonyManager.getSubscriberId();
  40. idView.append("IMSINo:"+imsistring+"\n");
  41. /*
  42. *SystemPropertyro.serialnoreturnstheserialnumberasuniquenumber
  43. *WorksforAndroid2.3andabove
  44. */
  45. StringhwID=android.os.SystemProperties.get("ro.serialno","unknown");
  46. idView.append("hwID:"+hwID+"\n");
  47. Stringserialnum=null;
  48. try{
  49. Class<?>c=Class.forName("android.os.SystemProperties");
  50. Methodget=c.getMethod("get",String.class,String.class);
  51. serialnum=(String)(get.invoke(c,"ro.serialno","unknown"));
  52. idView.append("serial:"+serialnum+"\n");
  53. }catch(Exceptionignored){
  54. }
  55. Stringserialnum2=null;
  56. try{
  57. Classmyclass=Class.forName("android.os.SystemProperties");
  58. Method[]methods=myclass.getMethods();
  59. Object[]params=newObject[]{newString("ro.serialno"),newString(
  60. "Unknown")};
  61. serialnum2=(String)(methods[2].invoke(myclass,params));
  62. idView.append("serial2:"+serialnum2+"\n");
  63. }catch(Exceptionignored)
  64. {
  65. }
  66. /*
  67. *Settings.Secure.ANDROID_IDreturnstheuniqueDeviceID
  68. *WorksforAndroid2.2andabove
  69. */
  70. StringandroidId=Settings.Secure.getString(getContentResolver(),
  71. Settings.Secure.ANDROID_ID);
  72. idView.append("AndroidID:"+androidId+"\n");
  73. }
  74. });
  75. }
  76. }


: SystemProperties.java

[java] view plain copy
  1. packageandroid.os;
  2. /**
  3. *Givesaccesstothesystempropertiesstore.Thesystemproperties
  4. *storecontainsalistofstringkey-valuepairs.
  5. *
  6. *{@hide}
  7. */
  8. publicclassSystemProperties
  9. {
  10. publicstaticfinalintPROP_NAME_MAX=31;
  11. publicstaticfinalintPROP_VALUE_MAX=91;
  12. privatestaticnativeStringnative_get(Stringkey);
  13. privatestaticnativeStringnative_get(Stringkey,Stringdef);
  14. privatestaticnativeintnative_get_int(Stringkey,intdef);
  15. privatestaticnativelongnative_get_long(Stringkey,longdef);
  16. privatestaticnativebooleannative_get_boolean(Stringkey,booleandef);
  17. privatestaticnativevoidnative_set(Stringkey,Stringdef);
  18. /**
  19. *Getthevalueforthegivenkey.
  20. *@returnanemptystringifthekeyisn'tfound
  21. *@throwsIllegalArgumentExceptionifthekeyexceeds32characters
  22. */
  23. publicstaticStringget(Stringkey){
  24. if(key.length()>PROP_NAME_MAX){
  25. thrownewIllegalArgumentException("key.length>"+PROP_NAME_MAX);
  26. }
  27. returnnative_get(key);
  28. }
  29. /**
  30. *Getthevalueforthegivenkey.
  31. *@returnifthekeyisn'tfound,returndefifitisn'tnull,oranemptystringotherwise
  32. *@throwsIllegalArgumentExceptionifthekeyexceeds32characters
  33. */
  34. publicstaticStringget(Stringkey,Stringdef){
  35. if(key.length()>PROP_NAME_MAX){
  36. thrownewIllegalArgumentException("key.length>"+PROP_NAME_MAX);
  37. }
  38. returnnative_get(key,def);
  39. }
  40. /**
  41. *Getthevalueforthegivenkey,andreturnasaninteger.
  42. *@paramkeythekeytolookup
  43. *@paramdefadefaultvaluetoreturn
  44. *@returnthekeyparsedasaninteger,ordefifthekeyisn'tfoundor
  45. *cannotbeparsed
  46. *@throwsIllegalArgumentExceptionifthekeyexceeds32characters
  47. */
  48. publicstaticintgetInt(Stringkey,intdef){
  49. if(key.length()>PROP_NAME_MAX){
  50. thrownewIllegalArgumentException("key.length>"+PROP_NAME_MAX);
  51. }
  52. returnnative_get_int(key,def);
  53. }
  54. /**
  55. *Getthevalueforthegivenkey,andreturnasalong.
  56. *@paramkeythekeytolookup
  57. *@paramdefadefaultvaluetoreturn
  58. *@returnthekeyparsedasalong,ordefifthekeyisn'tfoundor
  59. *cannotbeparsed
  60. *@throwsIllegalArgumentExceptionifthekeyexceeds32characters
  61. */
  62. publicstaticlonggetLong(Stringkey,longdef){
  63. if(key.length()>PROP_NAME_MAX){
  64. thrownewIllegalArgumentException("key.length>"+PROP_NAME_MAX);
  65. }
  66. returnnative_get_long(key,def);
  67. }
  68. /**
  69. *Getthevalueforthegivenkey,returnedasaboolean.
  70. *Values'n','no','0','false'or'off'areconsideredfalse.
  71. *Values'y','yes','1','true'or'on'areconsideredtrue.
  72. *(caseinsensitive).
  73. *Ifthekeydoesnotexist,orhasanyothervalue,thenthedefault
  74. *resultisreturned.
  75. *@paramkeythekeytolookup
  76. *@paramdefadefaultvaluetoreturn
  77. *@returnthekeyparsedasaboolean,ordefifthekeyisn'tfoundoris
  78. *notabletobeparsedasaboolean.
  79. *@throwsIllegalArgumentExceptionifthekeyexceeds32characters
  80. */
  81. publicstaticbooleangetBoolean(Stringkey,booleandef){
  82. if(key.length()>PROP_NAME_MAX){
  83. thrownewIllegalArgumentException("key.length>"+PROP_NAME_MAX);
  84. }
  85. returnnative_get_boolean(key,def);
  86. }
  87. /**
  88. *Setthevalueforthegivenkey.
  89. *@throwsIllegalArgumentExceptionifthekeyexceeds32characters
  90. *@throwsIllegalArgumentExceptionifthevalueexceeds92characters
  91. */
  92. publicstaticvoidset(Stringkey,Stringval){
  93. if(key.length()>PROP_NAME_MAX){
  94. thrownewIllegalArgumentException("key.length>"+PROP_NAME_MAX);
  95. }
  96. if(val!=null&&val.length()>PROP_VALUE_MAX){
  97. thrownewIllegalArgumentException("val.length>"+
  98. PROP_VALUE_MAX);
  99. }
  100. native_set(key,val);
  101. }
  102. }


使用"ReadDeviceID" activity 创建"com.deviceid"项目。将布局"main.xml"改写成下面的代码

[java] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <TextView
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:text="@string/hello"
  11. />
  12. <Button
  13. android:text="GetDeviceID"
  14. android:id="@+id/button1"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content">
  17. </Button>
  18. <TextView
  19. android:id="@+id/textView1"
  20. android:layout_width="fill_parent"
  21. android:layout_height="wrap_content">
  22. </TextView>
  23. </LinearLayout>


在"AndroidManifest.xml"文件中添加"READ_PHONE_STATE"许可,使应用程序可以登陆互联网。

[java] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.deviceid"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <uses-sdkandroid:minSdkVersion="7"/>
  7. <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
  8. <activityandroid:name=".ReadDeviceID"
  9. android:label="@string/app_name">
  10. <intent-filter>
  11. <actionandroid:name="android.intent.action.MAIN"/>
  12. <categoryandroid:name="android.intent.category.LAUNCHER"/>
  13. </intent-filter>
  14. </activity>
  15. </application>
  16. <uses-permission
  17. android:name="android.permission.READ_PHONE_STATE">
  18. </uses-permission>
  19. </manifest>


输出结果

上方示例代码的输出结果如下图所示:

更多相关文章

  1. 10个 iOS 用户暂可以嘲笑 Android(安卓)的特点
  2. Android(安卓)Wear Preview- 创建通知(Creating Notifications fo
  3. android 拍照 Camera类 使用照相机进行拍照 翻译
  4. Android动态加载及hook资料汇总
  5. Android多媒体开发(3)————使用Android(安卓)NKD编译havlenapet
  6. android 开发中总结的一些经验
  7. Android-BLE低功耗蓝牙开发
  8. Android中shape的使用
  9. Android(安卓)使用CoordinatorLayout+AppBarLayout+CollapsingTo

随机推荐

  1. Android(安卓)迁移到 Androidx
  2. EditText属性
  3. Android(安卓)Binder驱动源码下载地址
  4. 基于Platinum库的DLNA开发
  5. 【Android(安卓)界面效果6】Android(安卓
  6. Android(安卓)中文 API (101) —— Async
  7. android 向serverGet和Post请求的两种方
  8. Android(安卓)studio 开发第一篇 APP项目
  9. android 开发之旅 R.java 常见问题
  10. android数据库使用小结