Android:检查手机是否为双卡
经过对论坛的大量研究,现在我知道没有办法find双SIM卡中的两个SIM卡(除了联系制造商)的IMSI或SIM序列号。 现在我改变的问题是,我们可以根本检测到手机有两个SIM卡? 我相信它可以用一些智慧来检测。 我能想到的几个方法是:
-
拨打一个USSD代码,并跟踪IMEI号码的日志(我在印度用* 139#试过了),这会给我提供SIM卡的IMEI号码。 (据推测,手机遵循Android的指导方针,有两个IMEI号码。)
-
存储SIM的SIM序列号和/或IMSI。 并且在检测到任何其他的IMSI /序列号之后,即使电话没有重新启动(即,SIM被切换),通过追踪一些日志或通过一些广播事件处理。
-
通过拨打* 06#您将可以看到两个IMEI号码。 通过某种方式,得到这两个数字。 (类似于文本的屏幕截图和图像parsing。)
如果有人可以想一些其他的方法,他们是最受欢迎的。 我真的很感激任何forms的帮助。 此外,如果任何人有任何关于制造商API或链接的信息,请与社区人员分享。
15年3月23日更新:
官方的多SIM卡API现在可以从Android 5.1开始使用
其他可能的select:
您可以使用Javareflection来获取这两个IMEI号码。
使用这些IMEI号码,您可以检查手机是否是双SIM卡。
尝试以下活动:
import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TelephonyInfo telephonyInfo = TelephonyInfo.getInstance(this); String imeiSIM1 = telephonyInfo.getImsiSIM1(); String imeiSIM2 = telephonyInfo.getImsiSIM2(); boolean isSIM1Ready = telephonyInfo.isSIM1Ready(); boolean isSIM2Ready = telephonyInfo.isSIM2Ready(); boolean isDualSIM = telephonyInfo.isDualSIM(); TextView tv = (TextView) findViewById(R.id.tv); tv.setText(" IME1 : " + imeiSIM1 + "\n" + " IME2 : " + imeiSIM2 + "\n" + " IS DUAL SIM : " + isDualSIM + "\n" + " IS SIM1 READY : " + isSIM1Ready + "\n" + " IS SIM2 READY : " + isSIM2Ready + "\n"); } }
这里是TelephonyInfo.java
:
import java.lang.reflect.Method; import android.content.Context; import android.telephony.TelephonyManager; public final class TelephonyInfo { private static TelephonyInfo telephonyInfo; private String imeiSIM1; private String imeiSIM2; private boolean isSIM1Ready; private boolean isSIM2Ready; public String getImsiSIM1() { return imeiSIM1; } /*public static void setImsiSIM1(String imeiSIM1) { TelephonyInfo.imeiSIM1 = imeiSIM1; }*/ public String getImsiSIM2() { return imeiSIM2; } /*public static void setImsiSIM2(String imeiSIM2) { TelephonyInfo.imeiSIM2 = imeiSIM2; }*/ public boolean isSIM1Ready() { return isSIM1Ready; } /*public static void setSIM1Ready(boolean isSIM1Ready) { TelephonyInfo.isSIM1Ready = isSIM1Ready; }*/ public boolean isSIM2Ready() { return isSIM2Ready; } /*public static void setSIM2Ready(boolean isSIM2Ready) { TelephonyInfo.isSIM2Ready = isSIM2Ready; }*/ public boolean isDualSIM() { return imeiSIM2 != null; } private TelephonyInfo() { } public static TelephonyInfo getInstance(Context context){ if(telephonyInfo == null) { telephonyInfo = new TelephonyInfo(); TelephonyManager telephonyManager = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)); telephonyInfo.imeiSIM1 = telephonyManager.getDeviceId();; telephonyInfo.imeiSIM2 = null; try { telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getDeviceIdGemini", 0); telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getDeviceIdGemini", 1); } catch (GeminiMethodNotFoundException e) { e.printStackTrace(); try { telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getDeviceId", 0); telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getDeviceId", 1); } catch (GeminiMethodNotFoundException e1) { //Call here for next manufacturer's predicted method name if you wish e1.printStackTrace(); } } telephonyInfo.isSIM1Ready = telephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY; telephonyInfo.isSIM2Ready = false; try { telephonyInfo.isSIM1Ready = getSIMStateBySlot(context, "getSimStateGemini", 0); telephonyInfo.isSIM2Ready = getSIMStateBySlot(context, "getSimStateGemini", 1); } catch (GeminiMethodNotFoundException e) { e.printStackTrace(); try { telephonyInfo.isSIM1Ready = getSIMStateBySlot(context, "getSimState", 0); telephonyInfo.isSIM2Ready = getSIMStateBySlot(context, "getSimState", 1); } catch (GeminiMethodNotFoundException e1) { //Call here for next manufacturer's predicted method name if you wish e1.printStackTrace(); } } } return telephonyInfo; } private static String getDeviceIdBySlot(Context context, String predictedMethodName, int slotID) throws GeminiMethodNotFoundException { String imei = null; TelephonyManager telephony = (TelephonyManager) context.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); Object[] obParameter = new Object[1]; obParameter[0] = slotID; Object ob_phone = getSimID.invoke(telephony, obParameter); if(ob_phone != null){ imei = ob_phone.toString(); } } catch (Exception e) { e.printStackTrace(); throw new GeminiMethodNotFoundException(predictedMethodName); } return imei; } private static boolean getSIMStateBySlot(Context context, String predictedMethodName, int slotID) throws GeminiMethodNotFoundException { boolean isReady = false; TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); try{ Class<?> telephonyClass = Class.forName(telephony.getClass().getName()); Class<?>[] parameter = new Class[1]; parameter[0] = int.class; Method getSimStateGemini = telephonyClass.getMethod(predictedMethodName, parameter); Object[] obParameter = new Object[1]; obParameter[0] = slotID; Object ob_phone = getSimStateGemini.invoke(telephony, obParameter); if(ob_phone != null){ int simState = Integer.parseInt(ob_phone.toString()); if(simState == TelephonyManager.SIM_STATE_READY){ isReady = true; } } } catch (Exception e) { e.printStackTrace(); throw new GeminiMethodNotFoundException(predictedMethodName); } return isReady; } private static class GeminiMethodNotFoundException extends Exception { private static final long serialVersionUID = -996812356902545308L; public GeminiMethodNotFoundException(String info) { super(info); } } }
编辑:
获取像“getDeviceIdGemini”方法访问其他SIM插槽的细节已经预测,该方法存在。
如果该方法的名称与设备制造商给出的名称不匹配,则不起作用。 您必须为这些设备find相应的方法名称。
查找其他制造商的方法名称可以使用Javareflection完成,如下所示:
public static void printTelephonyManagerMethodNamesForThisDevice(Context context) { TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); Class<?> telephonyClass; try { telephonyClass = Class.forName(telephony.getClass().getName()); Method[] methods = telephonyClass.getMethods(); for (int idx = 0; idx < methods.length; idx++) { System.out.println("\n" + methods[idx] + " declared by " + methods[idx].getDeclaringClass()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } }
编辑:
Seetha在她的评论中指出:
telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getDeviceIdDs", 0); telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getDeviceIdDs", 1);
它正在为她工作。 她在Samsung Duos设备中获得了两个IMEI号码。
添加<uses-permission android:name="android.permission.READ_PHONE_STATE" />
编辑2:
用于检索数据的方法适用于Lenovo A319和该制造商的其他电话(Credit Maher Abuthraa ):
telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 0); telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 1);
我有一个Android 4.4.4的三星双核设备和Seetha在接受的答案(即调用getDeviceIdDs)build议的方法不适用于我,因为该方法不存在。 我能够通过调用方法“getDefault(int slotID)”来恢复所需的所有信息,如下所示:
public static void samsungTwoSims(Context context) { TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); try{ Class<?> telephonyClass = Class.forName(telephony.getClass().getName()); Class<?>[] parameter = new Class[1]; parameter[0] = int.class; Method getFirstMethod = telephonyClass.getMethod("getDefault", parameter); Log.d(TAG, getFirstMethod.toString()); Object[] obParameter = new Object[1]; obParameter[0] = 0; TelephonyManager first = (TelephonyManager) getFirstMethod.invoke(null, obParameter); Log.d(TAG, "Device Id: " + first.getDeviceId() + ", device status: " + first.getSimState() + ", operator: " + first.getNetworkOperator() + "/" + first.getNetworkOperatorName()); obParameter[0] = 1; TelephonyManager second = (TelephonyManager) getFirstMethod.invoke(null, obParameter); Log.d(TAG, "Device Id: " + second.getDeviceId() + ", device status: " + second.getSimState()+ ", operator: " + second.getNetworkOperator() + "/" + second.getNetworkOperatorName()); } catch (Exception e) { e.printStackTrace(); } }
另外,我重写了迭代testing方法的代码来恢复这些信息,以便它使用方法名称数组而不是try / catch序列。 例如,要确定是否有两个有效的SIM卡,我们可以这样做:
private static String[] simStatusMethodNames = {"getSimStateGemini", "getSimState"}; public static boolean hasTwoActiveSims(Context context) { boolean first = false, second = false; for (String methodName: simStatusMethodNames) { // try with sim 0 first try { first = getSIMStateBySlot(context, methodName, 0); // no exception thrown, means method exists second = getSIMStateBySlot(context, methodName, 1); return first && second; } catch (GeminiMethodNotFoundException e) { // method does not exist, nothing to do but test the next } } return false; }
这样,如果为某个设备build议一个新的方法名称,您可以简单地将其添加到数组,它应该工作。
我能够从OnePlus 2手机上读取两个IMEI
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Call some material design APIs here TelephonyManager manager = (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE); Log.i(TAG, "Single or Dula Sim " + manager.getPhoneCount()); Log.i(TAG, "Default device ID " + manager.getDeviceId()); Log.i(TAG, "Single 1 " + manager.getDeviceId(0)); Log.i(TAG, "Single 2 " + manager.getDeviceId(1)); }
在searchnetworking运营商的方法时,我find了几种本地解决scheme。
对于API> = 17:
TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); // Get information about all radio modules on device board // and check what you need by calling #getCellIdentity. final List<CellInfo> allCellInfo = manager.getAllCellInfo(); for (CellInfo cellInfo : allCellInfo) { if (cellInfo instanceof CellInfoGsm) { CellIdentityGsm cellIdentity = ((CellInfoGsm) cellInfo).getCellIdentity(); //TODO Use cellIdentity to check MCC/MNC code, for instance. } else if (cellInfo instanceof CellInfoWcdma) { CellIdentityWcdma cellIdentity = ((CellInfoWcdma) cellInfo).getCellIdentity(); } else if (cellInfo instanceof CellInfoLte) { CellIdentityLte cellIdentity = ((CellInfoLte) cellInfo).getCellIdentity(); } else if (cellInfo instanceof CellInfoCdma) { CellIdentityCdma cellIdentity = ((CellInfoCdma) cellInfo).getCellIdentity(); } }
在AndroidManifest中添加权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> </manifest>
要获得networking运营商,您可以检查mcc和mnc代码:
- https://en.wikipedia.org/wiki/Mobile_country_code (一般信息)。
- https://clients.txtnation.com/hc/en-us/articles/218719768-MCCMNC-mobile-country-code-and-mobile-network-code-list- (相当充分和最新的运营商名单)。
对于API> = 22:
final SubscriptionManager subscriptionManager = SubscriptionManager.from(context); final List<SubscriptionInfo> activeSubscriptionInfoList = subscriptionManager.getActiveSubscriptionInfoList(); for (SubscriptionInfo subscriptionInfo : activeSubscriptionInfoList) { final CharSequence carrierName = subscriptionInfo.getCarrierName(); final CharSequence displayName = subscriptionInfo.getDisplayName(); final int mcc = subscriptionInfo.getMcc(); final int mnc = subscriptionInfo.getMnc(); final String subscriptionInfoNumber = subscriptionInfo.getNumber(); }
对于API> = 23。 要检查手机是双/三/多SIM卡:
TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); if (manager.getPhoneCount() == 2) { // Dual sim }
我正在看看通话logging,我注意到,除了managedCursor内容中的通常字段,我们在双SIM卡电话(我选中了Xolo A500s Lite)上有一个“simid”列,以标记每个呼叫在SIM卡的通话logging中。 这个值是1或2,最可能表示SIM1 / SIM2。
managedCursor = context.getContentResolver().query(contacts, null, null, null, null); managedCursor.moveToNext(); for(int i=0;i<managedCursor.getColumnCount();i++) {//for dual sim phones if(managedCursor.getColumnName(i).toLowerCase().equals("simid")) indexSIMID=i; }
我没有在一个SIM卡手机上find这个专栏(我查了一下Xperia L)。
所以,尽pipe我不认为这是检查双卡性质的一种万无一失的方法,但是我在这里发布它是因为它可能对某人有用。
Commonsware说这是不可能的。 请看下面的内容:
使用Android SDK检测双卡是不可能的。
这是关于这个主题的进一步对话:
谷歌开发团队的人说,使用Android SDK检测双卡是不可能的。
提示:
你可以尝试使用
ctx.getSystemService("phone_msim")
代替
ctx.getSystemService(Context.TELEPHONY_SERVICE)
如果您已经尝试过Vaibhav的答案,并且telephony.getClass().getMethod()
失败,那么以上是适用于我的Qualcomm移动版的。
我已经在Samsung S8上find了这些系统属性
SystemProperties.getInt("ro.multisim.simslotcount", 1) > 1
另外,根据来源: https : //android.googlesource.com/platform/frameworks/base/+/master/telephony/java/com/android/internal/telephony/TelephonyProperties.java
getprop persist.radio.multisim.config
在多个sim上返回“ dsds
”或“ dsda
”。
我已经在三星S8上testing过了,它工作