我在 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
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.
从 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% 有效
谢谢你!!
并享受编码 :)
我从电话管理员那里得到的 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
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.
从 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% 有效 谢谢你!! 并享受编码 :)