我在 Android 中收到 IMEI 为空的问题?

I am getting IMEI null in Android Q?

我从电话管理员那里得到的 IMEI ID 为空。怎么办?

有什么解决方法吗?

Android Q 已限制访问 IMEI 和序列号。它仅适用于具有特殊运营商许可的平台和应用程序。此外,权限 READ_PRIVILEGED_PHONE_STATE 不适用于非平台应用程序。

如果您尝试访问它,则会抛出以下异常

java.lang.SecurityException: getImeiForSlot: The user 10180 does not meet the requirements to access device identifiers.

请参考文档: https://developer.android.com/preview/privacy/data-identifiers#device-ids

Also refer Issue

Targeting Android Q,第三方应用根本无法获取IMEI。 Android Q doc 在陈述

时具有误导性

Starting in Android Q, apps must have the READ_PRIVILEGED_PHONE_STATE privileged permission in order to access the device's non-resettable identifiers, which include both IMEI and serial number. https://developer.android.com/preview/privacy/data-identifiers#device-ids

但是当我实际尝试实现它时,我收到了这个异常:

java.lang.SecurityException: getDeviceId: The user 10132 does not meet the requirements to access device identifiers.

有人在 google 的问题跟踪器上报告了此问题,Google 员工表示这是有意为之的行为,Q+ 上的 IMEI 仅适用于系统级应用程序。

Status: Won't Fix (Intended Behavior) This is Working As Intended. IMEI is a personal identifier and this is not given out to apps as a matter of policy. There is no workaround.

https://issuetracker.google.com/issues/129583175#comment10

从 Android 开始,这将无法工作 问:第三方应用程序不能使用 IMEI,也不能使用 phone 和其他 non-resettable 设备标识符的序列号。

能够使用这些权限的唯一权限是 READ_PRIVILEGED_PHONE_STATE,任何第三方应用程序都不能使用它 - 制造和软件应用程序。如果您使用该方法,您将收到错误安全异常或收到 null .

您仍然可以尝试使用以下方式获取唯一 ID:

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),Secure.ANDROID_ID);

正如最佳实践所建议的那样。 " 您可以避免使用硬件标识符,例如 SSAID(Android ID)和 IMEI,而不限制所需的功能。"

最好使用实例 ID,例如 String uniqueID = UUID.randomUUID().toString();FirebaseInstanceId.getInstance().getId();

他们提到: 如果您的应用是设备或配置文件所有者应用,则您只需要 READ_PHONE_STATE 权限即可访问不可重置的设备标识符,即使您的应用的目标是 Android 10 或更高。

我尝试通过 EMM 作为设备所有者应用进行部署,但没有成功。

你可以换其他方式,我用uuid代替设备id

 String uniquePseudoID = "35" +
            Build.BOARD.length() % 10 +
            Build.BRAND.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;
    String serial = Build.getRadioVersion();
    String uuid = new UUID(uniquePseudoID.hashCode(), serial.hashCode()).toString();
    AppLog.d("Device ID",uuid);

如果您的应用面向 Android10 或更高版本,则会发生 SecurityException。

以下模块受到影响...

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

所以你无法获得 android 10 的 IMEI 号,你必须为此使用另一个唯一标识符,如 Android ID

设备唯一的 64 位十六进制数

私有字符串android_id = Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID);

不确定 IMEI 号码,但您可以通过这种方式获取 simSerialNumber 和其他运营商信息。

getSimSerialNumber()需要Android10以后的特权权限,第三方应用无法注册此权限。

参见:https://developer.android.com/about/versions/10/privacy/changes#non-resettable-device-ids

一个可能的解决方案是使用 Android 5.1 中的 TELEPHONY_SUBSCRIPTION_SERVICE 来检索 sim 序列号。步骤如下:

  • 检查 READ_PHONE_STATE 权限。
  • 获取有效订阅列表。(Returns所有有效 SIM 卡的列表)
  • 从订阅对象中检索 sim 详细信息。

       if ( isPermissionGranted(READ_PHONE_STATE) ) {
    
            String simSerialNo="";
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
    
                SubscriptionManager subsManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 
    
                List<SubscriptionInfo> subsList = subsManager.getActiveSubscriptionInfoList();
    
                if (subsList!=null) {
                    for (SubscriptionInfo subsInfo : subsList) {
                        if (subsInfo != null) {
                            simSerialNo  = subsInfo.getIccId();
                        }
                    }
                }
            } else {
                TelephonyManager tMgr = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                simSerialNo = tMgr.getSimSerialNumber();
            }
        }
    

检查这是否有帮助

如果需要,您可以尝试将工作配置文件安装到手机中 phone 并将您的应用程序包含在同一个包中,反之亦然。

我试过了,它有效,如果你遵循这个 repo 就很简单:https://github.com/googlesamples/android-testdpc

当您安装工作配置文件时,您的应用程序将安装在此配置文件中,您将有权访问 IMEI。

现在还有一个昨天固定为 Android10 的例子: https://github.com/android/enterprise-samples/pull/29

根据google docs.

对不可重置设备标识符的限制

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

Caution: Third-party apps installed from the Google Play Store cannot declare privileged permissions.

因此,您可以获得 Android 唯一 ID,而不是 imei。

        String imei = "";
        TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
                if (telephonyManager != null) {
                    try {
                        imei = telephonyManager.getImei();
                    } catch (Exception e) {
                        e.printStackTrace();
                        imei = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
                    }
                }
            } else {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_PHONE_STATE}, 1010);
            }
        } else {
            if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
                if (telephonyManager != null) {
                    imei = telephonyManager.getDeviceId();
                }
            } else {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_PHONE_STATE}, 1010);
            }
        }

我迟到了 post 回答。我仍然相信我的回答会帮助别人。 Android 10 限制开发者访问 IMEI 号码。

您可以通过获取软件 ID 获得替代解决方案。您可以使用软件 ID 作为唯一 ID。请找到我在应用程序中使用的以下代码。

public static String getDeviceId(Context context) {

 String deviceId;

    if (android.os.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);
        if (mTelephony.getDeviceId() != null) {
            deviceId = mTelephony.getDeviceId();
        } else {
            deviceId = Settings.Secure.getString(
                    context.getContentResolver(),
                    Settings.Secure.ANDROID_ID);
        }
    }

    return deviceId;
}

获取IMEI号码的最佳方式如下:

    public static String getIMEIDeviceId(Context context) {

        String deviceId;

        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);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                    return "";
                }
            }
            assert mTelephony != null;
            if (mTelephony.getDeviceId() != null)
            {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                {
                    deviceId = mTelephony.getImei();
                }else {
                    deviceId = mTelephony.getDeviceId();
                }
            } else {
                deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
            }
        }
        Log.d("deviceId", deviceId);
        return deviceId;
    }

直接复制方法使用即可。一定会的。但是,您可能知道无法在 android Q(版本 10)中获取 IMEI。在这段代码中,您可以通过任何设备或任何 API 级别获得唯一标识符(alternative id)。 100% 有效 谢谢你!! 并享受编码 :)