如何找到Android设备的序列号?

我需要为Android应用程序使用唯一的ID,我认为该设备的序列号将是一个很好的候选人。 如何在我的应用程序中检索Android设备的序列号?

TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE); String uid = tManager.getDeviceId(); 

getSystemService是Activity类中的一个方法。 getDeviceID()将根据手机使用的无线电(GSM或CDMA)返回设备的MDN或MEID。

每个设备必须在这里返回一个唯一的值(假设它是一个电话)。 这应该适用于任何具有SIM插槽或CDMA无线电的Android设备。 你用自己的Android微波炉自己处理;-)

正如戴夫·韦伯(Dave Webb)提到的那样, Android开发人员博客有一篇文章涵盖了这一点。

我和谷歌的某个人谈了一些关于几个项目的补充说明。 以下是我在上述博客文章中没有提到的发现:

  • ANDROID_ID是首选解决方案。 ANDROID_ID在Android <= 2.1或> = 2.3的版本上是完全可靠的。 只有2.2有这个帖子中提到的问题。
  • 2.2中有几个厂商的几个设备受到ANDROID_ID的影响。
  • 据我所知,所有受影响的设备都有相同的ANDROID_ID ,即9774d56d682e549c 。 这也是仿真器报告的相同的设备ID,顺便说一句。
  • 谷歌认为,原始设备制造商已经为他们的许多或大部分设备修补了这个问题,但是我能够验证到2011年4月初,至少找到具有破坏的ANDROID_ID的设备还是很容易的。

根据Google的建议,我实现了一个类,它将为每个设备生成一个唯一的UUID,并在适当的时候使用ANDROID_ID作为种子,必要时返回TelephonyManager.getDeviceId(),如果失败,则使用随机生成的唯一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; } } 
 String serial = null; try { Class<?> c = Class.forName("android.os.SystemProperties"); Method get = c.getMethod("get", String.class); serial = (String) get.invoke(c, "ro.serialno"); } catch (Exception ignored) { } 

此代码使用隐藏的Android API返回设备序列号。

 String deviceId = Settings.System.getString(getContentResolver(), Settings.System.ANDROID_ID); 

虽然,不能保证Android ID将是一个唯一的标识符。

在Android开发者博客上有一篇很棒的文章讨论这个问题 。

它建议不要使用TelephonyManager.getDeviceId()因为它不适用于不是手机(如平板电脑)的Android设备,它需要READ_PHONE_STATE权限,并且在所有手机上都不可靠。

相反,您可以使用下列之一:

  • MAC地址
  • 序列号
  • ANDROID_ID

这篇文章讨论了每一个的利弊,这是值得阅读,所以你可以计算出哪个是最适合你的使用。

对于设备唯一的简单数字和其生命周期中的常量(禁止出厂重置或黑客入侵),请使用Settings.Secure.ANDROID_ID 。

 String id = Secure.getString(getContentResolver(), Secure.ANDROID_ID); 

要使用设备序列号(“系统设置/关于/状态”中显示的设备序列号),并返回到Android ID:

 String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.ANDROID_ID); 

IMEI是好的,但只适用于手机的Android设备。 您应该考虑支持平板电脑或其他Android设备,也没有电话。

你有一些替代品,如:建立班级成员,BT MAC,无线局域网MAC,甚至更好 – 所有这些的组合。

我已经在我的博客文章中解释了这些细节,请参阅: http : //www.pocketmagic.net/?p = 1662

由于在这里没有答案提到一个完美的,不能通过系统更新持续不变的ID,并且存在于所有设备中 (主要是因为没有Google提供的单个解决方案),所以我决定发布一个方法,通过结合两个可用的标识符,以及在运行时在它们之间进行选择的检查,是最好的事情。

在代码之前,有三个事实:

  1. 对于非GSM,3G,LTE等设备, TelephonyManager.getDeviceId() (akaIMEI)将无法正常工作或完全不工作,但即使没有插入SIM卡,甚至在没有插入SIM卡时也会始终返回唯一的ID没有SIM插槽存在(一些OEM已经这样做)。

  2. 由于姜饼(Android 2.3) android.os.Build.SERIAL 必须存在于任何不提供IMEI的设备上 ,也就是说,根据Android策略,没有上述硬件。

  3. 由于事实(2.), 这两个唯一标识符中的至少一个将始终存在 ,并且SERIAL 可以在IMEI同时存在。

注意:事实(1.)和(2.) 基于Google声明

通过以上事实,通过检查是否存在IMEI绑定的硬件,可以始终具有唯一的标识符,如果不存在,则返回到SERIAL,因为不能检查现有的SERIAL是否有效。 以下静态类提供了2种方法来检查这种存在并使用IMEI或SERIAL:

 import java.lang.reflect.Method; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.Log; public class IDManagement { public static String getCleartextID_SIMCHECK (Context mContext){ String ret = ""; TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); if(isSIMAvailable(mContext,telMgr)){ Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId()); return telMgr.getDeviceId(); } else{ Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID); // return Settings.Secure.ANDROID_ID; return android.os.Build.SERIAL; } } public static String getCleartextID_HARDCHECK (Context mContext){ String ret = ""; TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); if(telMgr != null && hasTelephony(mContext)){ Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId() + ""); return telMgr.getDeviceId(); } else{ Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID); // return Settings.Secure.ANDROID_ID; return android.os.Build.SERIAL; } } public static boolean isSIMAvailable(Context mContext, TelephonyManager telMgr){ int simState = telMgr.getSimState(); switch (simState) { case TelephonyManager.SIM_STATE_ABSENT: return false; case TelephonyManager.SIM_STATE_NETWORK_LOCKED: return false; case TelephonyManager.SIM_STATE_PIN_REQUIRED: return false; case TelephonyManager.SIM_STATE_PUK_REQUIRED: return false; case TelephonyManager.SIM_STATE_READY: return true; case TelephonyManager.SIM_STATE_UNKNOWN: return false; default: return false; } } static public boolean hasTelephony(Context mContext) { TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); if (tm == null) return false; //devices below are phones only if (Build.VERSION.SDK_INT < 5) return true; PackageManager pm = mContext.getPackageManager(); if (pm == null) return false; boolean retval = false; try { Class<?> [] parameters = new Class[1]; parameters[0] = String.class; Method method = pm.getClass().getMethod("hasSystemFeature", parameters); Object [] parm = new Object[1]; parm[0] = "android.hardware.telephony"; Object retValue = method.invoke(pm, parm); if (retValue instanceof Boolean) retval = ((Boolean) retValue).booleanValue(); else retval = false; } catch (Exception e) { retval = false; } return retval; } } 

我会建议使用getCleartextID_HARDCHECK 。 如果反射不在您的环境中,请使用getCleartextID_SIMCHECK方法,但请考虑它是否适合您的特定SIM卡存在需求。

PS :请注意,原始设备制造商已经成功地针对谷歌政策 (具有相同SERIAL的多个设备) 进行了漏洞扫描 ,并且谷歌至少在大型OEM中有一个已知案例(未透露,我不知道哪个品牌这是要么,我猜三星)。

免责声明 :这回答了获取唯一设备ID的原始问题,但OP引入了歧义,指出他需要APP的唯一ID。 即使对于这样的场景,Android_ID会更好,但通过2个不同的ROM安装(甚至可以是相同的ROM),通过应用程序的Titanium备份之后,它将无法工作。 我的解决方案保持独立于闪存或工厂重置的持久性,并且只有在通过黑客/硬件模块发生IMEI或串行篡改时才会失败。

所有上述方法都存在问题。 在Google I / O Reto Meier发布了一个强有力的答案,即如何解决这个问题,以满足大多数开发者在安装过程中跟踪用户的需求。

这种方法将为您提供一个匿名,安全的用户ID,在不同设备(包括基于主Google帐户的平板电脑)上跨用户持续使用,并跨越同一设备上的安装。 基本的方法是生成一个随机的用户ID,并将其存储在应用程序共享首选项中。 然后,您使用Google的备份代理将链接到Google帐户的共享首选项存储在云中。

让我们通过完整的方法。 首先,我们需要使用Android备份服务为我们的SharedPreferences创建一个备份。 首先通过以下链接注册您的应用: http : //developer.android.com/google/backup/signup.html

Google会为您提供您需要添加到清单的备份服务密钥。 您还需要告诉应用程序使用BackupAgent,如下所示:

 <application android:label="MyApplication" android:backupAgent="MyBackupAgent"> ... <meta-data android:name="com.google.android.backup.api_key" android:value="your_backup_service_key" /> </application> 

然后,您需要创建备份代理并告诉它使用助手代理来共享首选项:

 public class MyBackupAgent extends BackupAgentHelper { // The name of the SharedPreferences file static final String PREFS = "user_preferences"; // A key to uniquely identify the set of backup data static final String PREFS_BACKUP_KEY = "prefs"; // Allocate a helper and add it to the backup agent @Override public void onCreate() { SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS); addHelper(PREFS_BACKUP_KEY, helper); } } 

要完成备份,您需要在主Activity中创建一个BackupManager实例:

 BackupManager backupManager = new BackupManager(context); 

最后创建一个用户ID,如果它不存在,并将其存储在SharedPreferences中:

  public static String getUserID(Context context) { private static String uniqueID = null; private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID"; if (uniqueID == null) { SharedPreferences sharedPrefs = context.getSharedPreferences( MyBackupAgent.PREFS, Context.MODE_PRIVATE); uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null); if (uniqueID == null) { uniqueID = UUID.randomUUID().toString(); Editor editor = sharedPrefs.edit(); editor.putString(PREF_UNIQUE_ID, uniqueID); editor.commit(); //backup the changes BackupManager mBackupManager = new BackupManager(context); mBackupManager.dataChanged(); } } return uniqueID; } 

即使用户切换设备,此用户标识现在也将在安装过程中保持不变。

有关此方法的更多信息,请参阅Reto的讲座http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html

有关如何实施备份代理的完整详细信息,请参阅以下开发人员网站: http : //developer.android.com/guide/topics/data/backup.html我特别建议底层的测试部分作为备份不是瞬间发生,所以要测试你必须强制备份。

另一种方法是在没有任何权限的应用程序中使用/ sys / class / android_usb / android0 / iSerial。

 user@creep:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial -rw-r--r-- root root 4096 2013-01-10 21:08 iSerial user@creep:~$ adb shell cat /sys/class/android_usb/android0/iSerial 0A3CXXXXXXXXXX5 

要在java中这样做,可以使用FileInputStream打开iSerial文件并读出字符。 只要确保你把它包装在一个异常处理程序中,因为不是所有的设备都有这个文件。

至少以下设备已知有这个文件世界可读:

  • Galaxy Nexus
  • Nexus S
  • 摩托罗拉Xoom 3g
  • 东芝AT300
  • HTC One V
  • 迷你MK802
  • 三星Galaxy S II

你也可以在这里看到我的博客文章: http : //insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.html在那里我讨论了什么其他文件可用的信息。

Android OS Device的唯一设备ID为字符串。

 String deviceId; final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); if (mTelephony.getDeviceId() != null){ deviceId = mTelephony.getDeviceId(); } else{ deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); } 

但我强烈建议Google ::

识别应用程序安装

我知道这个问题是旧的,但可以在一行代码中完成

String deviceID = Build.SERIAL;

正如@ haserman所说:

 TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE); String uid = tManager.getDeviceId(); 

但是必须在清单文件中包含权限:

 <uses-permission android:name="android.permission.READ_PHONE_STATE"/> 

我发现上面的@emmby发布的示例类是一个很好的起点。 但是正如其他海报所提到的那样,它有一些缺陷。 最主要的是它将UUID保存到一个不必要的XML文件中,然后总是从这个文件中检索它。 这使得开放的课程变得简单:任何拥有扎根手机的人都可以编辑XML文件,为自己提供一个新的UUID。

我已经更新了代码,只有在绝对必要的情况下(例如,当使用随机生成的UUID时),它才会保留到XML中,并根据@Brill Pappin的回答重新计算逻辑:

 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 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) || (androidId == null) ) { final String deviceId = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE )).getDeviceId(); if (deviceId != null) { uuid = UUID.nameUUIDFromBytes(deviceId.getBytes("utf8")); } else { uuid = UUID.randomUUID(); // Write the value out to the prefs file so it persists prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString() ).commit(); } } else { uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8")); } } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } } } } } /** * 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; } 

是。 这是一个设备硬件序列号,它是唯一的。 所以在API级别2.3和以上,你可以使用android.os.Build.ANDROID_ID来获取它。 对于低于2.3的API级别,使用TelephonyManager.getDeviceID()

你可以阅读这个http://android-developers.blogspot.in/2011/03/identifying-app-installations.html