如何获取Android 8.1设备的IMEI号?telephonyManager.getDeviceId已废弃
获取Android 8.1设备IMEI的正确方法及代码评估
嗨,我来帮你梳理下Android 8.1(对应API 27,即Build.VERSION_CODES.O_MR1)设备获取IMEI的正确方式,同时分析你提供的代码是否可行~
核心前提:权限要求
要获取IMEI,必须申请READ_PHONE_STATE权限:
- 先在
AndroidManifest.xml中声明权限:<uses-permission android:name="android.permission.READ_PHONE_STATE" /> - 对于Android 6.0(API 23)及以上设备,还需要动态申请权限,不能只依赖Manifest声明。你的代码里用了
@SuppressLint("MissingPermission"),这会跳过权限检查,非常危险——如果用户没授权,调用相关方法会直接抛出SecurityException导致崩溃。
你的代码存在的问题
我们逐条拆解你提供的代码:
- 废弃方法的使用:你先调用了
telephonyManager.getDeviceId(),这个方法在Android 8.0(API 26)就已被废弃。虽然在8.1上可能暂时还能运行,但它返回的可能是IMEI或MEID(取决于设备类型),语义不如getImei()明确,不推荐继续使用。 - 版本判断冗余:你写的
Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT完全没必要——getImei()是API 26才引入的,只要判断Build.VERSION.SDK_INT >= Build.VERSION_CODES.O就足够覆盖Android 8.0+(包括8.1)的场景。 - TelephonyManager未初始化:代码里的
telephonyManager没有显示初始化逻辑,要确保是通过getSystemService(Context.TELEPHONY_SERVICE)获取的实例,否则会触发空指针异常。 - Android ID的局限性:当IMEI获取不到时你用Android ID替代,但要注意:Android ID是系统生成的字符串,恢复出厂设置会改变,部分设备可能返回相同的ID,它不能完全替代IMEI的硬件唯一性。
修正后的可行代码
结合Android 8.1的特性,我整理了一份更严谨的代码,包含权限检查、动态申请兼容、双卡支持(可选):
import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.Log; import androidx.core.app.ActivityCompat; public class DeviceImeiHelper { private static final String TAG = "DeviceImeiHelper"; /** * 获取设备唯一标识(优先IMEI,失败则返回Android ID) */ public static String getDeviceIdentifier(Context context) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); String imei = null; // 1. 检查权限是否已授予 if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { Log.w(TAG, "未获取READ_PHONE_STATE权限,无法获取IMEI"); // 这里建议触发动态权限申请,而不是直接返回Android ID // 示例:如果是在Activity中,可以调用ActivityCompat.requestPermissions() return getAndroidID(context); } // 2. 根据Android版本选择正确的方法获取IMEI try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Android 8.0+ 使用getImei(),支持双卡(传入卡槽索引,0为第一个卡槽) imei = telephonyManager.getImei(0); } else { // 低于Android 8.0,使用已废弃的getDeviceId()做兼容 imei = telephonyManager.getDeviceId(); } } catch (SecurityException e) { Log.e(TAG, "获取IMEI失败:", e); } // 3. 如果IMEI为空, fallback到Android ID if (imei == null || imei.isEmpty()) { imei = getAndroidID(context); Log.d(TAG, "IMEI获取失败,使用Android ID替代:" + imei); } return imei; } /** * 获取Android ID */ private static String getAndroidID(Context context) { return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); } }
额外注意事项
- 双卡设备处理:如果你的应用需要支持双卡设备,可以通过
getImei(int slotIndex)指定卡槽索引(0或1),获取对应卡槽的IMEI。 - 非蜂窝设备:如果设备没有蜂窝模块(比如WiFi平板),
getImei()会返回null,此时只能依赖Android ID或其他标识(比如设备序列号,但序列号也需要权限)。 - 隐私合规:获取IMEI属于敏感用户数据,需要符合地区隐私法规(如GDPR),必须获得用户明确授权,且告知用户数据用途。
内容的提问来源于stack exchange,提问作者Priyanka Yadav
相关产品推荐
相关产品推荐

