代码获取Android DeviceId

Posted Kevin He

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码获取Android DeviceId相关的知识,希望对你有一定的参考价值。

目录

DeviceId是什么?

基础知识

国际移动设备识别码(IMEI)

移动设备识别码(MEID )

AndroidID

设备MAC地址

代码获取Android DeviceId?

参考文章


  • DeviceId是什么?

DeviceIdD是用来标识一台android物理设备的唯一id(后续统称DID)。那么如何获取它呢?

Google提供了TelephonyManager.getDeviceId方法来获取Android的DID。该API是获取GSM手机的国际移动设备识别码(IMEI)或者 CDMA手机的移动设备识别码(MEID )。但该API存在一些限制。

因此,各大互联网公司都有生产、维护DID的基建SDK,本文旨在梳理清DID的相关上下文。

全称“International Mobile Equipment Identity”,是通常所说的手机序列号、手机“串号”。用于在移动电话网络中识别每一部独立的手机等移动通信设备,相当于移动电话的身份证,序列号共有15~17位数字,通过在手机拨号键盘中输入*#06#即可查询。

但存在以下限制:

​1.自API23(Android 6.0)开始,获取IMEI需要用户予"android.permission.READ_PHONE_STATE";
2.自API29(Android 10.0)开始,您的应用必须是设备或个人资料所有者应用具有特殊运营商权限或具有 READ_PRIVILEGED_PHONE_STATE 特许权限,才能访问这些标识符。
3.某些小厂商某型号的手机IMEI可能相同。

全称“Mobile Equipment Identifier”,是CDMA手机的身份识别码,也是每台CDMA手机或通讯平板唯一的识别码。通过这个识别码,网络端可以对该手机进行跟踪和监管。用于CDMA制式的手机。MEID的数字范围是十六进制的,和IMEI的格式类似。

存在的限制同IMEI的限制。

又称SSAID。设备启动时,随机生成一个 64 位数字(表示为十六进制字符串),对于应用签名密钥、用户和设备的每个组合都是唯一的。 ANDROID_ID 的值受签名密钥和用户的限制。

但存在如下限制:

1.如果在设备上执行恢复出厂设置或 APK 签名密钥更改,则该值可能会更改。
2.某些小厂商的Android手机可能为null或相同。
  • 设备MAC地址

MAC 地址具有全局唯一性,无法由用户重置,在恢复出厂设置后也不会变化。

但存在如下限制:

在 Android 6.0(API 级别 23)到 Android 9(API 级别 28)中,本地设备 MAC 地址(如 WLAN 和蓝牙)无法通过第三方 API 使用。WifiInfo.getMacAddress() 方法和BluetoothAdapter.getDefaultAdapter().getAddress() 方法会返回02:00:00:00:00:00。

不过业界也有一些hack的做法,不建议使用。

其他诸如BuildSerial、GoogleAID也有各种各样的限制,在这里不做统一赘述。

  • 代码获取Android DeviceId?

该段代码参考自:I am getting IMEI null in Android Q?,简化代码&添加注释。

Android版本号参考:Android历史版本

需要说明的是,这段代码仅适用于Demo级产品的大多数场景,并不能完全保证DID的唯一性。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String deviceId = getIMEIDeviceId(this);
        Log.i("deviceId is:", deviceId);
    }

    public static String getIMEIDeviceId(Context context) {
        String deviceId;
        //当APK运行在Android10(API>=29)及以上时,获取到的是AndroidID
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
        } else {
            final TelephonyManager mTelephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            //当APK运行在Android6.0(API>=23)及以上时,需要check有无READ_PHONE_STATE权限。
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                    return "";
                }
            }
            assert mTelephony != null;
            //如果TelephonyManager获取到的DeviceId不为null
            if (mTelephony.getDeviceId() != null) {
                //获取GSM手机的国际移动设备识别码(IMEI)或者 CDMA手机的移动设备识别码(MEID).
                deviceId = mTelephony.getDeviceId();
            } else {
                //如果DeviceId为null,我们的DID依然是AndroidID。
                deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
            }
        }
        return deviceId;
    }
}
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • 参考文章

唯一标识符最佳做法

TelephonyManager

I am getting IMEI null in Android Q?

Android 10 使用getDeviceId()和getIMEI()的问题及方案

以上是关于代码获取Android DeviceId的主要内容,如果未能解决你的问题,请参考以下文章

Android 使用两个不同的代码片段获取当前位置 NULL

Android获取各个应用程序的缓存文件代码小片段(使用AIDL)

Android 实用代码片段

Android 实用代码片段

如何从Android片段中的相机获取图像

我的Android进阶之旅关于Android平台获取文件的mime类型:为啥不传小写后缀名就获取不到mimeType?为啥android 4.4系统获取不到webp格式的mimeType呢?(代码片段