Android:双卡检测、SIM路径获取及指定SIM保存联系人实现
双卡设备下保存联系人到指定SIM卡的实现方案
我来帮你搞定这个双卡SIM卡保存联系人的问题,一步步拆解解决方案:
一、判断设备是否支持双卡并获取SIM卡信息
要识别双卡状态,我们需要借助Android的TelephonyManager和SubscriptionInfo类,具体步骤如下:
申请必要权限
先在AndroidManifest.xml中声明所需权限(注意不同Android版本的权限差异):<uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- Android 12及以上版本需要这个权限获取SIM卡详细信息 --> <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />这些都是危险权限,代码里一定要做动态权限申请,否则会直接抛出异常。
获取可用SIM卡列表
通过TelephonyManager获取所有有效的SIM卡信息:private fun getAvailableSimCards(): List<SubscriptionInfo> { val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { // Android 5.1及以上版本支持双卡API telephonyManager.subscriptionInfoList ?: emptyList() } else { // 低于5.1的设备基本不支持双卡,返回空列表 emptyList() } }返回的
SubscriptionInfo列表里,每个对象包含了SIM卡的subscriptionId(唯一标识)、displayName(比如“SIM1”“中国电信”)等关键信息,我们可以用这些来判断双卡状态和展示选择选项。
二、构造对应SIM卡的联系人URI
你原来使用的content://icc/adn是默认SIM卡的存储路径,双卡设备下每个SIM卡有专属的URI,标准构造方式如下:
private fun getSimContactUri(subId: Int): Uri { // 通过subId构造指定SIM卡的联系人URI return Uri.parse("content://icc/adn/subId/$subId") }
部分国产厂商可能有自定义URI格式(比如content://icc/sim${slotIndex}/adn,slotIndex从0开始对应SIM1/SIM2),如果标准路径不生效,可以尝试替换成这种格式。
三、实现SIM选择弹窗并保存联系人
当用户点击“保存联系人”按钮时,先检查SIM卡数量,再根据情况展示选择弹窗,最后执行保存操作:
fun showSimSelectionDialog(number: String, name: String) { val simCards = getAvailableSimCards() when { simCards.isEmpty() -> { Toast.makeText(context, "未检测到可用SIM卡", Toast.LENGTH_SHORT).show() } simCards.size == 1 -> { // 单卡设备,直接保存到唯一的SIM卡 addContactToSpecificSim(number, name, simCards[0].subscriptionId) } else -> { // 双卡设备,弹出选择对话框 val simNames = simCards.map { it.displayName ?: "SIM${it.slotIndex + 1}" }.toTypedArray() AlertDialog.Builder(context) .setTitle("选择保存的SIM卡") .setItems(simNames) { _, which -> val selectedSubId = simCards[which].subscriptionId addContactToSpecificSim(number, name, selectedSubId) } .show() } } } // 修改你原来的方法,支持指定SIM卡保存 private fun addContactToSpecificSim(number: String, name: String, subId: Int) { try { val simUri = getSimContactUri(subId) val values = ContentValues().apply { put("number", number) put("tag", name) // 部分设备需要额外传入sub_id参数,保险起见加上 put("sub_id", subId) } context.contentResolver.insert(simUri, values) Toast.makeText(context, "联系人已保存到指定SIM卡", Toast.LENGTH_SHORT).show() } catch (e: Exception) { e.printStackTrace() Toast.makeText(context, "保存失败:${e.message}", Toast.LENGTH_SHORT).show() } }
四、额外注意事项
- 权限校验:调用任何涉及SIM卡或联系人操作的方法前,一定要确保已经获取到对应的动态权限,否则会抛出
SecurityException。 - 兼容性:少数厂商的定制系统可能对SIM卡联系人存储路径做了修改,如果标准URI不生效,可以尝试搜索对应厂商的适配方案。
- 版本限制:双卡相关API从Android 5.1(API 22)开始正式支持,低于该版本的设备无需处理双卡逻辑。
内容的提问来源于stack exchange,提问作者Manoj Kumar




