我在 Android Q 中将 IMEI 设为空?
Posted
技术标签:
【中文标题】我在 Android Q 中将 IMEI 设为空?【英文标题】:I am getting IMEI null in Android Q? 【发布时间】:2020-04-16 00:16:15 【问题描述】:我从电话管理员那里得到了 IMEI ID 空值。怎么办?
有什么解决方法吗?
【问题讨论】:
你在模拟器上试试吗? 没有。 Google Pixel 1. 几个小时前注册,发现我的应用没有获得 IMEI 号码 我没有尝试过 android Q,但我读到他们正在限制对不可重置设备标识符的访问 问题是我使用 IMEI 进行欺诈检测。替代品,如 ANDROID_ID 不是 100% 可靠的。我需要设备独有的东西才能将设备列入黑名单.. 在 Android 10 之前,恐怕没有其他方法可以获取 IMEI。您可以拥有任何其他唯一 ID。这完全取决于您的用例。如果您想跟踪唯一的设备,您可以使用 ANDROID_ID,它对于 Android 27 的不同包名称是不同的,并且对于 27 以下的每个设备都是唯一的。 【参考方案1】: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
【讨论】:
TelephonyManager.getSubscriberId
怎么样,这是 NetworkStatsManager.queryDetailsForUid
的唯一使用方式?
你是对的。 source.android.com/devices/tech/config/device-identifiers
我们可以使用 TELEPHONY_SUBSCRIPTION_SERVICE (> Android 5.1) 获取 sim 序列号和运营商信息。有关详细信息,请参阅下面的答案。
谁能提一下如何制作一个具有特殊运营商权限的平台或应用程序
@ArulMani 没有尝试,但我想没有通用的方法可以这样做。您需要root您的设备并授予应用程序root权限或将应用程序刷新到自定义rom或其他东西。一般来说,尽量避免这些个性化数据,并自行或使用 Firebase 创建一个匿名的唯一 ID【参考方案2】:
针对 Android Q,第三方应用根本无法访问 IMEI。 Android Q doc在陈述时具有误导性
从 Android Q 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 特权权限,以访问设备的不可重置 标识符,包括 IMEI 和序列号。 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.
有人在谷歌的问题跟踪器上报告了这一点,谷歌员工说这是预期行为,Q+ 上的 IMEI 仅适用于系统级应用。
状态:无法修复(预期行为)这是按预期工作的。 IMEI 是个人标识符,它不会作为应用程序提供给应用程序 政策问题。没有解决方法。
https://issuetracker.google.com/issues/129583175#comment10
【讨论】:
您链接的文档还指出Caution: Third-party apps installed from the Google Play Store cannot declare privileged permissions.
。因此,只有系统应用程序才能获得权限。不过,root 用户仍然可以访问它。【参考方案3】:
这在 Android Q 中不起作用。第三方应用不能使用 IMEI,也不能使用手机的序列号和其他不可重置的设备标识符。
能够使用这些权限的唯一权限是 READ_PRIVILEGED_PHONE_STATE,并且不能由任何第三方应用程序使用 - 制造和软件应用程序。如果您使用该方法,您将收到错误安全异常或获取 null 。
您仍然可以尝试使用以下方法获取唯一 ID:
import android.provider.Settings.Secure;
private String android_id = Secure.getString(getContext().getContentResolver(),Secure.ANDROID_ID);
【讨论】:
android studio 警报在这里:Using getString to get device identifiers is not recommended.
developer.android.com/training/articles/user-data-ids.html
获取唯一 ID 的最佳方式是什么? @zakjma
“尝试获取唯一 ID”是什么意思。对于非系统应用程序,此尝试将始终失败。对吗?
@M.UsmanKhan 不,这不会失败,因为您在这里得到的是“AndroidId”而不是“IMEI”,从 Api 级别“29”开始,“IMEI”号码没有解决方法【参考方案4】:
正如最佳实践所建议的那样。 “您可以避免使用硬件标识符,例如 SSAID (Android ID) 和 IMEI,而不会限制所需的功能。”
宁可使用实例 ID,例如 String uniqueID = UUID.randomUUID().toString();
或 FirebaseInstanceId.getInstance().getId();
【讨论】:
用户可能希望通过重新安装应用程序来重置他们的偏好,因此通过重新安装应用程序来保留信息并不是最佳做法。这就是为什么不推荐使用硬件 ID 的原因,因为它们仅限于设备并且用户无法重置它们。在大多数情况下,应用范围的 ID 就足够了。查看最佳实践developer.android.com/training/articles/user-data-ids#java 应用重新安装后如何检测特定应用? 我想这取决于用例。如上所述,不建议在重新安装应用程序后保留用户 ID,因为用户随后会受到长期跟踪且无法重置。本文针对不同用例提供解决方案developer.android.com/training/articles/user-data-ids#java【参考方案5】:他们提到: 如果您的应用是设备或配置文件所有者应用,则您只需要 READ_PHONE_STATE 权限即可访问不可重置的设备标识符,即使您的应用面向 Android 10 或更高版本。
我尝试通过 EMM 作为设备所有者应用进行部署,但没有成功。
【讨论】:
【参考方案6】:你可以改变其他方式,我使用 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);
【讨论】:
@MalwinderSinghM 不需要硬件权限,搜索为 IMEI,它是唯一的。 @VenRen,uniquePseudoID 是否足以替代imei,否则uniquePseudoID 可能与其他手机相同,尤其是相同的手机。 最好加上“首次应用启动时间”,会非常独特 我已经读到同一运营商的相同设备上的 tt'll 相同,您可以检查一下吗?【参考方案7】:如果您的应用面向 Android 10 或更高版本,则会发生 SecurityException。
以下模块受到影响...
Build
getSerial()
TelephonyManager
getImei()
getDeviceId()
getMeid()
getSimSerialNumber()
getSubscriberId()
因此您无法获取 android 10 的 IMEI no,您必须为此使用另一个唯一标识符,例如 Android ID
设备唯一的 64 位十六进制编号
私有字符串 android_id = Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID);
【讨论】:
您需要知道的是,ANDROID_ID 对于应用签名密钥、用户和设备的每个组合都是唯一的。 ANDROID_ID 的值由签名密钥和用户限定。如果在设备上执行恢复出厂设置或 APK 签名密钥更改,则该值可能会更改。【参考方案8】:不确定 IMEI 号码,但您可以通过这种方式获取 simSerialNumber 和其他运营商信息。
getSimSerialNumber() 从 Android 10 开始需要特权权限,第三方应用无法注册此权限。
见:https://developer.android.com/about/versions/10/privacy/changes#non-resettable-device-ids
一种可能的解决方案是使用 Android 5.1 中的 TELEPHONY_SUBSCRIPTION_SERVICE 来检索 sim 序列号。以下步骤:
检查 READ_PHONE_STATE 权限。 获取活动订阅列表。(返回所有活动 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();
检查是否有帮助
【讨论】:
这应该行不通。根据developer.android.com/about/versions/10/privacy/…,getSimSerialNumber 也应该从 READ_PHONE_STATE 移动到 READ_PRIVELEGED_PHONE_STATE @Mike 这已经过测试并且运行良好。 getSimSerialNumber 在 else 块中,仅对 它在 android Q 上也适用于我。不过确实很奇怪,我想知道 android 团队是否忽略了这一点......【参考方案9】:如果需要,您可以尝试将工作资料安装到手机中,并将您的应用包含在同一个包中,反之亦然。
我试过了,它很有效,如果你关注这个 repo 就很简单:https://github.com/googlesamples/android-testdpc
当您安装工作配置文件时,您的应用会安装在此配置文件中,并且您将可以访问 IMEI。
现在还有一个昨天针对 Android 10 修复的示例: https://github.com/android/enterprise-samples/pull/29
【讨论】:
你好乔尔,你能提供更多关于这方面的信息吗?我正在尝试但仍然无法获取 IMEI。 您好 Yusuph,您有什么问题?您使用的是哪个版本的 Android? 我使用的是 Android 10 但是你的问题是什么?为什么不工作?你能放一个日志或类似日志的东西吗?我在许多设备上进行了测试,结果很好 我已经安装了测试 DPC -> 现在我应该遵循哪些步骤【参考方案10】:根据谷歌docs.
对不可重置设备标识符的限制
从 Android 10 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 特权权限才能访问设备的不可重置标识符,其中包括 IMEI 和序列号。
注意:从 Google Play 商店安装的第三方应用程序不能 声明特权权限。
因此,您可以获取 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);
【讨论】:
【参考方案11】:我迟到了发布答案。我仍然相信我的回答会对某人有所帮助。 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;
【讨论】:
这不会造成问题吗?因为 Google 也不推荐 Secure.ANDROID_ID 如果软件更新了会改变吗?【参考方案12】:获取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 级别获取唯一标识符(替代 id)。 它工作 100% 谢谢!! 并享受编码:)
【讨论】:
Settings.Secure.ANDROID_ID 不是 IMEI 号码以上是关于我在 Android Q 中将 IMEI 设为空?的主要内容,如果未能解决你的问题,请参考以下文章
我在 Android 10 中收到 IMEI 号码错误 [关闭]
如何通过代码编程获取设备的 IMEI/ESN 号码但在 android > 6
Android--史上最全最完整,获取设备信息获取手机唯一标识
Xamarin.Android 无法在 Android 10 (Q) 中将录制的自定义声音用于推送通知