Android 6.0 上的双卡相关开发

在 Android 5.0 以前,各芯片厂商上的双卡开发没有一个统一的标准,以至于做起双卡适配来十分麻烦。
Android 5.0 之后,Google 官方统一了双卡平台的适配,并在 Framework 中添加了双卡相关的 API,这对于需要处理双卡的应用来说提供了很大的便利。

因为 Android 5 上的双卡 API 还不是很完善
所以本文是介绍在 Android 6.0 平台上的双卡相关开发
后续还会有一篇文章来介绍在双卡处理 Android N 上的实现

言归正题
在 API 层面上,自 Android 5.0 开始,加入了 SubscriptionManager。双卡相关的处理主要是依赖这个 API,你可以通过 Context 类里面的 getSystemService 方法和 SubscriptionManager.from(Context) 来取得它的对象,当然它内部也是调用的 getSystemService。

在数据库方面,TelephonyProvider 的 telephony.db 中新增了 siminfo 表来管理双卡的信息
1.png

Screenshot_20170607-171729.png

由于字段太多,我这里只截图了几个关键的字段
需要注意的是 _idsim_id 这两个字段
_id: 这个不用多说,系统要求,自增长,从 0 开始
sim_id:该行的卡所在的卡槽值,有 0,1,-1 三个值
| 数值 | 描述 |
| :–: |:—————————:|
| 0 | 该卡插在卡槽 1 中(主卡槽) |
| 1 | 该卡插在卡槽 2 中(副卡槽) |
| -1 | 手机内曾经插入过该卡 |
Ps. 在 Android 6.0+,-1 值已经被移除

每插入一张新的 SIM 卡,siminfo 表中就会插入一行新的数据,然后 _id 会自增长加 1

详细的各个 API 可以去查阅 API 文档。我这里仅以获取双卡手机两个卡的 IMSI 为例,介绍一下各平台所使用的方法
SubId 这个值对于双卡相关的操作来说是必要的

Android 6.0:

1
2
3
4
5
6
7
8
9
10
11
// 返回当前手机所插入 SIM 卡的个数
TelePhonyManager.getPhoneCount()
SubscriptionManager subManager = SubscriptionManager.from(this);
// 这个方法传进手机的卡槽序号,返回对应所插 SIM 卡的信息
SubscriptionInfo info = subManager.getActiveSubscriptionInfoForSimSlotIndex(1);
int subId = info.getSubscriptionId();
// 该方法在 Android 6.0 中还是 @hide 状态,可以反射调用
TelephonyManager teleManager = getSystemService(TelephonyManager.class);
String imsi = teleManager.getSubscriberId(subId);

MTK:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try {
TelephonyManager teleManager = getSystemService(TelephonyManager.class);
Class<?> phoneClass = Class.forName("com.android.internal.telephony.Phone");
Field gemni1Field = phoneClass.getField("GEMINI_SIM_1");
Field gemni2Field = phoneClass.getField("GEMINI_SIM_2");
gemni1Field.setAccessible(true);
gemni2Field.setAccessible(true);
int simId1 = (int) gemni1Field.get(null);
int simId2 = (int) gemni2Field.get(null);
Method method = TelephonyManager.class.getDeclaredMethod("getSubscriberIdGemini", int.class);
String imsi1 = (String) method.invoke(teleManager, simId1);
String imsi2 = (String) method.invoke(teleManager, simId2);
} catch (Exception e) {
e.printStackTrace();
}

高通:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
try {
Class<?> msmTeleManager = Class.forName("android.telephony.MSimTelephonyManager");
Method method = msmTeleManager.getMethod("getSubscriberId", int.class);
int simId1 = 0;
int simId2 = 1;
Object phoneMsim = getSystemService("phone_msim");
String imsi1 = (String) method.invoke(phoneMsim, simId1);
String imsi2 = (String) method.invoke(phoneMsim, simId2);
} catch (Exception e) {
e.printStackTrace();
}

对比三种获取双卡 IMSI 的方式,可以看出 Android 原生支持的双卡 API 更加的规范标准。目前新出的 Android 5+ 的新机上基本都采用了原生 API,Android 的碎片化又缩小了一步