经过对论坛的大量研究后,现在我知道双SIM卡手机中的SIM卡无法找到IMSI或SIM序列号(联系制造商除外)。现在我改变的问题是,我们可以检测到手机有两个SIM吗?我相信它可以用一些智慧来检测。我能想到的几个方法是:
拨打USSD代码并跟踪IMEI号码的日志(我在印度尝试使用* 139#。它运行了。)这将为我提供我拨打USSD代码的SIM的IMEI号码。 (假设手机遵循Android指南并且有两个IMEI号码。)
存储SIM的SIM序列号和/或IMSI。并且在检测到任何其他IMSI /序列号后,即使手机没有重新启动(即SIM卡已被切换),也可以通过跟踪某些日志或某些广播事件处理。
通过拨打* 06#,您将看到两个IMEI号码。通过某种方式,获得这两个数字。 (类似于屏幕捕获和文本图像解析。)
如果有人能想到其他方式,我们非常欢迎。我真的很感激这方面的任何帮助。此外,如果任何人有任何制造商API的信息或联系他们的链接,请与社区人员分享。
答案 0 :(得分:179)
15年3月23日更新:
Official multiple SIM API is available now from Android 5.1 onwards
其他可能选项:
您可以使用 Java反射来获取两个IMEI号码。
使用这些IMEI号码,您可以检查手机是否为双卡。
尝试以下活动:
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);
}
}
}
修改:
获取其他SIM插槽细节的“getDeviceIdGemini”等方法可以预测该方法存在。
如果该方法的名称与设备制造商给出的名称不匹配,则该名称不起作用。您必须为这些设备找到相应的方法名称。
可以使用Java反射查找其他制造商的方法名称,如下所示:
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设备中的两个SIM卡获取了两个IMEI号码。
添加<uses-permission android:name="android.permission.READ_PHONE_STATE" />
编辑2:
用于检索数据的方法适用于联想A319和该制造商生产的其他手机(信用Maher Abuthraa):
telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 0);
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 1);
答案 1 :(得分:5)
我有一台安卓4.4.4的三星Duos设备,Seetha在接受的答案(即调用getDeviceIdDs)中建议的方法对我不起作用,因为该方法不存在。通过调用方法&#34; getDefault(int slotID)&#34;,我能够恢复所需的所有信息,如下所示:
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();
}
}
此外,我重写了迭代测试方法的代码,以恢复此信息,以便它使用方法名称数组而不是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;
}
这样,如果为某些设备建议了一个新的方法名称,你可以简单地将它添加到数组中,它应该可以工作。
答案 2 :(得分:4)
我在搜索网络运营商的方式时发现了几种原生解决方案。
对于API&gt; = 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>
要获得网络运营商,您可以查看mcc和mnc代码:
对于API&gt; = 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&gt; = 23。要检查手机是双/三/多SIM卡:
TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (manager.getPhoneCount() == 2) {
// Dual sim
}
答案 3 :(得分:3)
我可以从OnePlus 2手机中读取两个IMEI
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
TelephonyManager manager = (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
Log.i(TAG, "Single or Dual 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));
}
答案 4 :(得分:2)
我正在查看通话记录,我注意到除了managedCursor内容中的常用字段外,我们在双SIM卡手机中有一个“simid”列(我在Xolo A500s Lite上查看过),以便使用SIM标记呼叫日志中的每个呼叫。该值为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卡手机中找到此列(我在Xperia L上查看过)。
所以虽然我不认为这是检查双SIM卡性质的万无一失的方法,但我在这里发布它是因为它对某人有用。
答案 5 :(得分:1)
提示:
您可以尝试使用
ctx.getSystemService("phone_msim")
而不是
ctx.getSystemService(Context.TELEPHONY_SERVICE)
如果您已经尝试过Vaibhav的回答并且telephony.getClass().getMethod()
失败,则上述内容适用于我的 Qualcomm 移动设备。
答案 6 :(得分:0)
Commonsware说这是不可能的。请参阅以下内容:
Detecting Dual SIM using Android SDK is not possible.
这是关于这个主题的进一步对话:
Google dev team guy says detecting Dual SIM using Android SDK is not possible.
答案 7 :(得分:0)
我在Samsung S8上找到了这些系统属性
SystemProperties.getInt("ro.multisim.simslotcount", 1) > 1
getprop persist.radio.multisim.config
在多个SIM卡上返回“dsds
”或“dsda
”。
我在三星S8上测试了它,它可以正常工作