我在 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) 中将录制的自定义声音用于推送通知

Android 获取 唯一GUID ,替换 IMEI (兼容 Android 10+获取IMEI问题)

如何在 Makefile 规则中将 env 变量传递给 shell 脚本