Android 手机读取SIM卡信息 您所在的位置:网站首页 Sim Android 手机读取SIM卡信息

Android 手机读取SIM卡信息

2023-01-09 05:45| 来源: 网络整理| 查看: 265

概述

手机和 wifi 已经改变了人们的生活方式,成为生活的必需品。手机号码和宽带账号成为运营商相互竞争的重要一环,双卡双待的手机需求也逐渐增大,大多数手机厂商将主打手机改为双卡双待全网通,而运营商在占领主SIM卡后,对SIM卡2的欲望越来越大,获取SIM卡2的信息的需求也变大,只有知己知彼,才能占得先机。

这里简单介绍一下 Android 手机如何读取 Sim 卡信息

关键类

必要权限: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}

一、 一个重要的表 siminfo telephony.db 中记录Sim卡信息的表,可以从建表的 sql 语句中读取该表的信息 CREATE TABLE siminfo( _id INTEGER PRIMARY KEY AUTOINCREMENT, //主键ID,为使用中的subId icc_id TEXT NOT NULL, //卡槽ID sim_id INTEGER DEFAULT -1, //SIM_ID 卡槽ID: -1 - 没插入、 0 - 卡槽1 、1 - 卡槽2 display_name TEXT, //显示名 carrier_name TEXT, //运行商 name_source INTEGER DEFAULT 0, //显示名的来源,0 - 系统分配 1 - 用户修改 color INTEGER DEFAULT 0, //显示颜色,没什么用 number TEXT, //电话号码 display_number_format INTEGER NOT NULL DEFAULT 1, // data_roaming INTEGER DEFAULT 0, //是否支持漫游 mcc INTEGER DEFAULT 0, //移动国家码 mnc INTEGER DEFAULT 0 //移动网络码 );

可以通过 ContentProvider 进行查询

public void testReadNameByPhone() { Uri uri = Uri.parse("content://telephony/siminfo"); //访问raw_contacts表 ContentResolver resolver = getApplicationContext().getContentResolver(); Cursor cursor = resolver.query(uri, new String[]{"_id","icc_id", "sim_id","display_name","carrier_name","name_source","color","number","display_number_format","data_roaming","mcc","mnc"}, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { LogUtils.e(cursor.getString(cursor.getColumnIndex("_id"))); LogUtils.e(cursor.getString(cursor.getColumnIndex("sim_id"))); LogUtils.e(cursor.getString(cursor.getColumnIndex("carrier_name"))); LogUtils.e(cursor.getString(cursor.getColumnIndex("display_name"))); LogUtils.e(cursor.getString(cursor.getColumnIndex("number"))); } cursor.close(); } } 二、 二个重要的类 SubscriptionManager 读取 siminfo 数据库的信息管理类,仅支持5.1版本以上 TelephonyManager 手机SIM信息管理类 三、 三个重要id

slotId 卡槽ID 双卡的基本就是0,1

phoneId 电话ID 与 slotId 基本相同,双卡基本都是0,1,不过在源码 getDeviceId 方法中有个FIXME注释 // FIXME this assumes phoneId == slotId 因此Android源码也只是假设 phoneId == slotId,可能会在以后修改 phoneId

subId 在 TelephonyManager 类中最常用的ID,但也是最不固定的ID,随着使用手机号码的增加,这个值递增,其实本质就是siminfo的_id

读取信息方法 一、 版本超过5.1(API 22)

使用 SubscriptionManager 类进行读取信息

SubscriptionManager mSubscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); mSubscriptionManager.getActiveSubscriptionInfoCountMax();//手机SIM卡数 mSubscriptionManager.getActiveSubscriptionInfoCount();//手机使用的SIM卡数 List activeSubscriptionInfoList = mSubscriptionManager.getActiveSubscriptionInfoList();//手机SIM卡信息

通过 SubscriptionInfo 的实例进行读取信息,对应的是 Siminfo 的表字段,下面为该类源码:

package android.telephony; public class SubscriptionInfo implements Parcelable { /** * Size of text to render on the icon. */ private static final int TEXT_SIZE = 16; /** * Subscription Identifier, this is a device unique number * and not an index into an array */ private int mId; /** * The GID for a SIM that maybe associated with this subscription, empty if unknown */ private String mIccId; /** * The index of the slot that currently contains the subscription * and not necessarily unique and maybe INVALID_SLOT_ID if unknown */ private int mSimSlotIndex; /** * The name displayed to the user that identifies this subscription */ private CharSequence mDisplayName; /** * String that identifies SPN/PLMN * TODO : Add a new field that identifies only SPN for a sim */ private CharSequence mCarrierName; /** * The source of the name, NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE, * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT. */ private int mNameSource; /** * The color to be used for tinting the icon when displaying to the user */ private int mIconTint; /** * A number presented to the user identify this subscription */ private String mNumber; /** * Data roaming state, DATA_RAOMING_ENABLE, DATA_RAOMING_DISABLE */ private int mDataRoaming; /** * SIM Icon bitmap */ private Bitmap mIconBitmap; /** * Mobile Country Code */ private int mMcc; /** * Mobile Network Code */ private int mMnc; /** * ISO Country code for the subscription's provider */ private String mCountryIso; }

该类没有常用的手机IMEI值和IMSI值,这个值可以通过 TelephonyManager 进行读取,不过需要通过反射,具体可见下方关于 TelephonyManager 的介绍

telephonyManager.getDeviceId(subscriptionInfo.getSimSlotIndex());//通过slotID读取IMEI值,版本必须高于6.0(API 23) telephonyManager.getSubscriberId(subscriptionInfo.getSubscriptionId()) {;//通过subId读取IMSI值,版本必须高于6.0(API 23) 二、版本低于5.1版本

使用 TelephonyManager 读取SIM卡信息:

TelephonyManager 仅能读取默认卡的信息,几乎所有的通过ID读取副卡信息的接口都添加了@hide 注释,无法使用,因此只能通过反射的机制进行调取

2.1 TelephonyManager 读取主卡信息 TelephonyManager telephonyManager = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)); telephonyManager.getSimOperatorName(); //运营商信息 telephonyManager.getNetworkOperatorName(); //网络显示名 telephonyManager.getLine1Number(); //电话号码 telephonyManager.getDeviceId(); //IMEI值 telephonyManager.getSubscriberId(); //IMSI值 2.2 通过反射读取副卡信息

读取副卡信息大多只需要1个参数,slotId 或者 subId,源码方法如下(我们主要关心的是IMEI和IMSI,主要看getDeviceId和getSubscriberId方法):

package android.telephony; public class TelephonyManager { /** * Returns the unique device ID of a subscription, for example, the IMEI for * GSM and the MEID for CDMA phones. Return null if device ID is not available. * *

Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * * @param slotId of which deviceID is returned */ public String getDeviceId(int slotId) { // FIXME this assumes phoneId == slotId try { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getDeviceIdForPhone(slotId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { return null; } } /** * Returns the unique subscriber ID, for example, the IMSI for a GSM phone * for a subscription. * Return null if it is unavailable. *

* Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * * @param subId whose subscriber id is returned * @hide */ public String getSubscriberId(int subId) { try { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { // This could happen before phone restarts due to crashing return null; } } /** * Returns the Service Provider Name (SPN). * * @hide */ public String getSimOperatorNameForPhone(int phoneId) { return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, ""); } /** * Returns the numeric name (MCC+MNC) of current registered operator * for a particular subscription. *

* Availability: Only when user is registered to a network. Result may be * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). * * @param phoneId * @hide **/ public String getNetworkOperatorForPhone(int phoneId) { return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); } /** * Returns the phone number string for line 1, for example, the MSISDN * for a GSM phone for a particular subscription. Return null if it is unavailable. *

* Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * OR * {@link android.Manifest.permission#READ_SMS} *

* The default SMS app can also use this. * * @param subId whose phone number for line 1 is returned * @hide */ public String getLine1Number(int subId) { String number = null; try { ITelephony telephony = getITelephony(); if (telephony != null) number = telephony.getLine1NumberForDisplay(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { } catch (NullPointerException ex) { } if (number != null) { return number; } try { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { // This could happen before phone restarts due to crashing return null; } } /** * Returns the serial number for the given subscription, if applicable. Return null if it is * unavailable. *

* @param subId for which Sim Serial number is returned * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * @hide */ public String getSimSerialNumber(int subId) { try { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { // This could happen before phone restarts due to crashing return null; } } }

可以看到源码中的这些方法均加了 @hide 的参数,无法直接调用,这里就需要用到反射:

/** * 通过反射调取@hide的方法 * * @param predictedMethodName 方法名 * @param id 参数 * @return 返回方法调用的结果 * @throws MethodNotFoundException 方法没有找到 */ private static String getReflexMethodWithId(String predictedMethodName, String id) throws MethodNotFoundException { String result = null; TelephonyManager telephony = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); try { Class telephonyClass = Class.forName(telephony.getClass().getName()); Class[] parameter = new Class[1]; parameter[0] = int.class; Method getSimID = telephonyClass.getMethod(predictedMethodName, parameter); Class[] parameterTypes = getSimID.getParameterTypes(); Object[] obParameter = new Object[parameterTypes.length]; if (parameterTypes[0].getSimpleName().equals("int")) { obParameter[0] = Integer.valueOf(id); } else { obParameter[0] = id; } Object ob_phone = getSimID.invoke(telephony, obParameter); if (ob_phone != null) { result = ob_phone.toString(); } } catch (Exception e) { LogUtils.d(e.fillInStackTrace()); throw new MethodNotFoundException(predictedMethodName); } return result; } /** * 通过反射调取@hide的方法 * * @param predictedMethodName 方法名 * @return 返回方法调用的结果 * @throws MethodNotFoundException 方法没有找到 */ private static String getReflexMethod(String predictedMethodName) throws MethodNotFoundException { String result = null; TelephonyManager telephony = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); try { Class telephonyClass = Class.forName(telephony.getClass().getName()); Method getSimID = telephonyClass.getMethod(predictedMethodName); Object ob_phone = getSimID.invoke(telephony); if (ob_phone != null) { result = ob_phone.toString(); } } catch (Exception e) { LogUtils.d(e.fillInStackTrace()); throw new MethodNotFoundException(predictedMethodName); } return result; }

现在就可以通过反射进行调用方法读取数据了

//IMEI,通过slotId,比较准确 getReflexMethodWithId("getDeviceId",“1”); //IMSI,通过subId,很不准确,保障准确率有两种方式 //1. 通过 SubscriptionInfo.getSubscriptionId() 获得准确的 subId 进行调用 //2. 从0开始遍历20次或更多次,找到不等于主卡IMSI的值 getReflexMethodWithId("getSubscriberId",“1”); //运营商信息,PhoneId,基本准确 getReflexMethodWithId(this, "getSimOperatorNameForPhone", “1”) //subId,很不准确 getReflexMethodWithId(this, "getSimCountryIso",“1”); //电话号码,subid,很不准确 getReflexMethodWithId(this, "getLine1Number", “1”);

特别注意:

电话号码和IMSI值都是用过 subId 进行读取的,这个值很不稳定,不一定就是1或者2,还有可能是3、4、5、6,不一定能读取出来,不过在5.1版本以上可以通过 subscriptionInfo.getSubscriptionId() 获得 subId,可以获得确定的IMEI值和IMSI值

根据 Android 版本的不同,有些方法不一定能反射得到,目前测试4.4没有问题

总结出来一个帮助类 PhoneUtils:

public class PhoneUtils { /** * 构造类 */ private PhoneUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } /** * 判断设备是否是手机 * * @return {@code true}: 是{@code false}: 否 */ public static boolean isPhone() { TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); return tm != null && tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; } /** * 获取IMEI码 *

需添加权限 {@code }

* * @return IMEI码 */ @SuppressLint("HardwareIds") public static String getIMEI() { TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); try { return tm != null ? tm.getDeviceId() : null; } catch (Exception ignored) { } return getUniquePsuedoID(); } /** * 通过读取设备的ROM版本号、厂商名、CPU型号和其他硬件信息来组合出一串15位的号码 * 其中“Build.SERIAL”这个属性来保证ID的独一无二,当API < 9 无法读取时,使用AndroidId * * @return 伪唯一ID */ public static String getUniquePsuedoID() { String m_szDevIDShort = "35" + Build.BOARD.length() % 10 + Build.BRAND.length() % 10 + Build.CPU_ABI.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; try { serial = android.os.Build.class.getField("SERIAL").get(null).toString(); return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString(); } catch (Exception e) { //获取失败,使用AndroidId serial = DeviceUtils.getAndroidID(); if (TextUtils.isEmpty(serial)) { serial = "serial"; } } return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString(); } /** * 获取IMSI码 *

需添加权限 {@code }

* * @return IMSI码 */ @SuppressLint("HardwareIds") public static String getIMSI() { TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); try { return tm != null ? tm.getSubscriberId() : null; } catch (Exception ignored) { } return null; } /** * 判断sim卡是否准备好 * * @return {@code true}: 是{@code false}: 否 */ public static boolean isSimCardReady() { TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); return tm != null && tm.getSimState() == TelephonyManager.SIM_STATE_READY; } /** * 获取Sim卡运营商名称 *

中国移动、如中国联通、中国电信

* * @return sim卡运营商名称 */ public static String getSimOperatorName() { TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); return tm != null ? tm.getSimOperatorName() : null; } /** * 获取Sim卡运营商名称 *

中国移动、如中国联通、中国电信

* * @return 移动网络运营商名称 */ public static String getSimOperatorByMnc() { TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); String operator = tm != null ? tm.getSimOperator() : null; if (operator == null) { return null; } switch (operator) { case "46000": case "46002": case "46007": return "中国移动"; case "46001": return "中国联通"; case "46003": return "中国电信"; default: return operator; } } /** * 获取Sim卡序列号 *

* Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * * @return 序列号 */ public static String getSimSerialNumber() { try { TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); String serialNumber = tm != null ? tm.getSimSerialNumber() : null; return serialNumber != null ? serialNumber : ""; } catch (Exception e) { } return ""; } /** * 获取Sim卡的国家代码 * * @return 国家代码 */ public static String getSimCountryIso() { TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); return tm != null ? tm.getSimCountryIso() : null; } /** * 读取电话号码 *

* Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * OR * {@link android.Manifest.permission#READ_SMS} *

* * @return 电话号码 */ public static String getPhoneNumber() { TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); try { return tm != null ? tm.getLine1Number() : null; } catch (Exception ignored) { } return null; } /** * 获得卡槽数,默认为1 * * @return 返回卡槽数 */ public static int getSimCount() { int count = 1; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { try { SubscriptionManager mSubscriptionManager = (SubscriptionManager) Utils.getContext().getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); if (mSubscriptionManager != null) { count = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); return count; } } catch (Exception ignored) { } } try { count = Integer.parseInt(getReflexMethod("getPhoneCount")); } catch (MethodNotFoundException ignored) { } return count; } /** * 获取Sim卡使用的数量 * * @return 0, 1, 2 */ public static int getSimUsedCount() { int count = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { try { SubscriptionManager mSubscriptionManager = (SubscriptionManager) Utils.getContext().getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); count = mSubscriptionManager.getActiveSubscriptionInfoCount(); return count; } catch (Exception ignored) { } } TelephonyManager tm = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) { count = 1; } try { if (Integer.parseInt(getReflexMethodWithId("getSimState", "1")) == TelephonyManager.SIM_STATE_READY) { count = 2; } } catch (MethodNotFoundException ignored) { } return count; } /** * 获取多卡信息 * * @return 多Sim卡的具体信息 */ public static List getSimMultiInfo() { List infos = new ArrayList(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { //1.版本超过5.1,调用系统方法 SubscriptionManager mSubscriptionManager = (SubscriptionManager) Utils.getContext().getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); List activeSubscriptionInfoList = null; if (mSubscriptionManager != null) { try { activeSubscriptionInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(); } catch (Exception ignored) { } } if (activeSubscriptionInfoList != null && activeSubscriptionInfoList.size() > 0) { //1.1.1 有使用的卡,就遍历所有卡 for (SubscriptionInfo subscriptionInfo : activeSubscriptionInfoList) { SimInfo simInfo = new SimInfo(); simInfo.mCarrierName = subscriptionInfo.getCarrierName(); simInfo.mIccId = subscriptionInfo.getIccId(); simInfo.mSimSlotIndex = subscriptionInfo.getSimSlotIndex(); simInfo.mNumber = subscriptionInfo.getNumber(); simInfo.mCountryIso = subscriptionInfo.getCountryIso(); try { simInfo.mImei = getReflexMethodWithId("getDeviceId", String.valueOf(simInfo.mSimSlotIndex)); simInfo.mImsi = getReflexMethodWithId("getSubscriberId", String.valueOf(subscriptionInfo.getSubscriptionId())); } catch (MethodNotFoundException ignored) { } infos.add(simInfo); } } } //2.版本低于5.1的系统,首先调用数据库,看能不能访问到 Uri uri = Uri.parse("content://telephony/siminfo"); //访问raw_contacts表 ContentResolver resolver = Utils.getContext().getContentResolver(); Cursor cursor = resolver.query(uri, new String[]{"_id", "icc_id", "sim_id", "display_name", "carrier_name", "name_source", "color", "number", "display_number_format", "data_roaming", "mcc", "mnc"}, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { SimInfo simInfo = new SimInfo(); simInfo.mCarrierName = cursor.getString(cursor.getColumnIndex("carrier_name")); simInfo.mIccId = cursor.getString(cursor.getColumnIndex("icc_id")); simInfo.mSimSlotIndex = cursor.getInt(cursor.getColumnIndex("sim_id")); simInfo.mNumber = cursor.getString(cursor.getColumnIndex("number")); simInfo.mCountryIso = cursor.getString(cursor.getColumnIndex("mcc")); String id = cursor.getString(cursor.getColumnIndex("_id")); try { simInfo.mImei = getReflexMethodWithId("getDeviceId", String.valueOf(simInfo.mSimSlotIndex)); simInfo.mImsi = getReflexMethodWithId("getSubscriberId", String.valueOf(id)); } catch (MethodNotFoundException ignored) { } infos.add(simInfo); } cursor.close(); } //3.通过反射读取卡槽信息,最后通过IMEI去重 for (int i = 0; i < getSimCount(); i++) { infos.add(getReflexSimInfo(i)); } List simInfos = ConvertUtils.removeDuplicateWithOrder(infos); if (simInfos.size() < getSimCount()) { for (int i = simInfos.size(); i < getSimCount(); i++) { simInfos.add(new SimInfo()); } } return simInfos; } @Nullable public static String getSecondIMSI() { int maxCount = 20; if (TextUtils.isEmpty(getIMSI())) { return null; } for (int i = 0; i < maxCount; i++) { String imsi = null; try { imsi = getReflexMethodWithId("getSubscriberId", String.valueOf(i)); } catch (MethodNotFoundException ignored) { LogUtils.d(ignored); } if (!TextUtils.isEmpty(imsi) && !imsi.equals(getIMSI())) { return imsi; } } return null; } /** * 通过反射获得SimInfo的信息 * 当index为0时,读取默认信息 * * @param index 位置,用来当subId和phoneId * @return {@link SimInfo} sim信息 */ @NonNull private static SimInfo getReflexSimInfo(int index) { SimInfo simInfo = new SimInfo(); simInfo.mSimSlotIndex = index; try { simInfo.mImei = getReflexMethodWithId("getDeviceId", String.valueOf(simInfo.mSimSlotIndex)); //slotId,比较准确 simInfo.mImsi = getReflexMethodWithId("getSubscriberId", String.valueOf(simInfo.mSimSlotIndex)); //subId,很不准确 simInfo.mCarrierName = getReflexMethodWithId("getSimOperatorNameForPhone", String.valueOf(simInfo.mSimSlotIndex)); //PhoneId,基本准确 simInfo.mCountryIso = getReflexMethodWithId("getSimCountryIso", String.valueOf(simInfo.mSimSlotIndex)); //subId,很不准确 simInfo.mIccId = getReflexMethodWithId("getSimSerialNumber", String.valueOf(simInfo.mSimSlotIndex)); //subId,很不准确 simInfo.mNumber = getReflexMethodWithId("getLine1Number", String.valueOf(simInfo.mSimSlotIndex)); //subId,很不准确 } catch (MethodNotFoundException ignored) { } return simInfo; } /** * 通过反射调取@hide的方法 * * @param predictedMethodName 方法名 * @return 返回方法调用的结果 * @throws MethodNotFoundException 方法没有找到 */ private static String getReflexMethod(String predictedMethodName) throws MethodNotFoundException { String result = null; TelephonyManager telephony = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); try { Class telephonyClass = Class.forName(telephony.getClass().getName()); Method getSimID = telephonyClass.getMethod(predictedMethodName); Object ob_phone = getSimID.invoke(telephony); if (ob_phone != null) { result = ob_phone.toString(); } } catch (Exception e) { LogUtils.d(e.fillInStackTrace()); throw new MethodNotFoundException(predictedMethodName); } return result; } /** * 通过反射调取@hide的方法 * * @param predictedMethodName 方法名 * @param id 参数 * @return 返回方法调用的结果 * @throws MethodNotFoundException 方法没有找到 */ private static String getReflexMethodWithId(String predictedMethodName, String id) throws MethodNotFoundException { String result = null; TelephonyManager telephony = (TelephonyManager) Utils.getContext().getSystemService(Context.TELEPHONY_SERVICE); try { Class telephonyClass = Class.forName(telephony.getClass().getName()); Class[] parameter = new Class[1]; parameter[0] = int.class; Method getSimID = telephonyClass.getMethod(predictedMethodName, parameter); Class[] parameterTypes = getSimID.getParameterTypes(); Object[] obParameter = new Object[parameterTypes.length]; if (parameterTypes[0].getSimpleName().equals("int")) { obParameter[0] = Integer.valueOf(id); } else if (parameterTypes[0].getSimpleName().equals("long")) { obParameter[0] = Long.valueOf(id); } else { obParameter[0] = id; } Object ob_phone = getSimID.invoke(telephony, obParameter); if (ob_phone != null) { result = ob_phone.toString(); } } catch (Exception e) { LogUtils.d(e.fillInStackTrace()); throw new MethodNotFoundException(predictedMethodName); } return result; } /** * SIM 卡信息 */ public static class SimInfo { /** 运营商信息:中国移动 中国联通 中国电信 */ public CharSequence mCarrierName; /** 卡槽ID,SimSerialNumber */ public CharSequence mIccId; /** 卡槽id, -1 - 没插入、 0 - 卡槽1 、1 - 卡槽2 */ public int mSimSlotIndex; /** 号码 */ public CharSequence mNumber; /** 城市 */ public CharSequence mCountryIso; /** 设备唯一识别码 */ public CharSequence mImei = getIMEI(); /** SIM的编号 */ public CharSequence mImsi; /** * 通过 IMEI 判断是否相等 * * @param obj * @return */ @Override public boolean equals(Object obj) { return obj != null && obj instanceof SimInfo && (TextUtils.isEmpty(((SimInfo) obj).mImei) || ((SimInfo) obj).mImei.equals(mImei)); } @Override public String toString() { return "SimInfo{" + "mCarrierName=" + mCarrierName + ", mIccId=" + mIccId + ", mSimSlotIndex=" + mSimSlotIndex + ", mNumber=" + mNumber + ", mCountryIso=" + mCountryIso + ", mImei=" + mImei + ", mImsi=" + mImsi + '}'; } } /** * 反射未找到方法 */ private static class MethodNotFoundException extends Exception { public static final long serialVersionUID = -3241033488141442594L; MethodNotFoundException(String info) { super(info); } } }



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有