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

115

我需要在Android应用程序中使用唯一标识符,而我认为设备的序列号是一个好的选择。如何在我的应用程序中检索Android设备的序列号?


2
不要忘记在你的清单文件中添加 android:name="android.permission.READ_PHONE_STATE"。 - Michael SIlveus
1
请查看以下链接:https://dev59.com/V3E85IYBdhLWcg3wbS1h#3102499 - Seva Alekseyev
如果您想获取一个不需要任何权限的唯一ID,您可以使用这个库来生成每个设备的唯一ID,使用Identity.getDeviceId(context),或者通过Identity.getInstallationId(context)获取您的应用程序安装标识符。 - caw
18个回答

1

正如 @haserman 所说:

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

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

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

1

Build.SERIAL 是最简单的方法,但并不完全可靠,因为它可能为空,有时会返回与您设备设置中看到的不同的值(证明 1, 证明 2)。

根据设备制造商和Android版本,有几种获取该号码的方法,因此我决定将我能找到的每个可能的解决方案编译成一个单一的gist。以下是其简化版:

public static String getSerialNumber() {
    String serialNumber;

    try {
        Class<?> c = Class.forName("android.os.SystemProperties");
        Method get = c.getMethod("get", String.class);

        serialNumber = (String) get.invoke(c, "gsm.sn1");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ril.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ro.serialno");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "sys.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = Build.SERIAL;

        // If none of the methods above worked
        if (serialNumber.equals(""))
            serialNumber = null;
    } catch (Exception e) {
        e.printStackTrace();
        serialNumber = null;
    }

    return serialNumber;
}

1

Android操作系统设备的唯一设备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); 
         }

但我强烈建议使用谷歌推荐的这种方法:

识别应用程序安装


0
public static String getManufacturerSerialNumber() {
  String serial = null; 
  try {
      Class<?> c = Class.forName("android.os.SystemProperties");
      Method get = c.getMethod("get", String.class, String.class);
      serial = (String) get.invoke(c, "ril.serialnumber", "unknown");
  } catch (Exception ignored) {}
  return serial;
}

适用于API 29和30,在三星Galaxy S7、S9 Xcover上进行了测试


0

我知道这个问题很久了,但是它可以在一行代码中完成

String deviceID = Build.SERIAL;


据我所知,这将在设备的操作系统更新后发生变化,例如从4.4.2到4.4.4或其他版本。 - Den Drobiazko

0

从Android 10开始,应用程序必须具有READ_PRIVILEGED_PHONE_STATE特权权限才能访问设备的不可重置标识符,包括IMEI和序列号。

受影响的方法包括以下内容:

Build getSerial() TelephonyManager getImei() getDeviceId() getMeid() getSimSerialNumber() getSubscriberId()

READ_PRIVILEGED_PHONE_STATE仅适用于平台


-1

我发现@emmby上面发布的示例类是一个很好的起点。但是它有一些缺陷,正如其他帖子中提到的那样。最主要的问题是它不必要地将UUID持久化到XML文件中,然后总是从该文件中检索它。这使得该类容易被黑客攻击:任何拥有root手机的人都可以编辑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;
    }

将ID放入共享首选项会损害获得真正唯一ID的原始目的。例如,如果您想将该ID用作某些限制的键,则当熟练的用户对设备进行Root并访问共享首选项文件时,您将会受到影响。它的内容可能会被复制,这意味着... - Eugene Wechsler
还有一个错误是MB和你的答案都犯了。如果你使用randomUUID作为设备ID和应用程序ID,它适用于所有设备,无论它们是手机还是其他设备,也不管它们是否是Google实验室设备。 - Fred Grott

-2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接