You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

安卓双卡手机如何通过代码判断来电归属SIM1还是SIM2?

安卓双卡手机识别来电归属SIM卡的通用解决方案

嘿,我来帮你搞定安卓双卡手机识别来电归属SIM卡的问题!你已经能获取到来电号码,但要确定对应SIM卡确实需要分版本处理——毕竟安卓官方的双卡API是逐步完善的。下面是分版本的通用方案,还有代码示例和注意事项:

核心思路

安卓从5.1(API 22)开始才提供官方双卡支持,不同版本的API差异很大,我们需要分版本适配:

  • Android 10+(API 29及以上):用TelecomManager获取来电详情,直接拿到对应SIM的订阅ID
  • Android 5.1~9(API 22~28):结合SubscriptionManager匹配号码,或依赖厂商自定义的Intent参数
  • Android 5.0及以下:无官方API,只能依赖厂商自定义字段,兼容性较差

代码实现(更新你的BroadcastReceiver)

下面是修改后的PhoneCallReceiver,集成了分版本的SIM卡识别逻辑:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.telecom.Call;
import android.telecom.TelecomManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.widget.Toast;

import java.util.List;

public class PhoneCallReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
            String incomingNumber = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);

            // 空号码直接返回
            if (TextUtils.isEmpty(incomingNumber)) {
                return;
            }

            if (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)) {
                String simInfo = getSimCardInfoForIncomingCall(context, incomingNumber, intent);
                Toast.makeText(context, "来电来自 " + simInfo + ":" + incomingNumber, Toast.LENGTH_LONG).show();
            }

            if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK)){
                String simInfo = getSimCardInfoForIncomingCall(context, incomingNumber, intent);
                Toast.makeText(context, "已接听来自 " + simInfo + " 的电话", Toast.LENGTH_SHORT).show();
            }

            if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)){
                Toast.makeText(context, "通话结束:" + incomingNumber, Toast.LENGTH_SHORT).show();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getSimCardInfoForIncomingCall(Context context, String incomingNumber, Intent intent) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // Android 10+ 官方方案:通过TelecomManager获取来电详情
            TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
            if (telecomManager != null) {
                try {
                    List<Call> calls = telecomManager.getCalls();
                    for (Call call : calls) {
                        // 匹配正在响铃的来电
                        if (call.getState() == Call.STATE_RINGING) {
                            String callNumber = call.getDetails().getHandle().getSchemeSpecificPart();
                            if (incomingNumber.equals(callNumber)) {
                                int subscriptionId = call.getDetails().getSubscriptionId();
                                return getSimLabelBySubscriptionId(context, subscriptionId);
                            }
                        }
                    }
                } catch (SecurityException e) {
                    e.printStackTrace();
                    return "权限不足,请检查权限配置";
                }
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            // Android 5.1~9:用SubscriptionManager匹配SIM号码
            SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
            if (subscriptionManager != null) {
                List<SubscriptionInfo> activeSubs = subscriptionManager.getActiveSubscriptionInfoList();
                if (activeSubs != null) {
                    for (SubscriptionInfo info : activeSubs) {
                        String simNumber = info.getNumber();
                        // 匹配号码(注意部分SIM可能未存储号码)
                        if (!TextUtils.isEmpty(simNumber) && incomingNumber.contains(simNumber)) {
                            return "SIM" + (info.getSimSlotIndex() + 1) + "(" + info.getDisplayName() + ")";
                        }
                    }
                }

                // 适配厂商自定义Intent参数(小米、华为等)
                Integer slotId = intent.getIntExtra("android.intent.extra.slot", -1);
                if (slotId != -1) {
                    return "SIM" + (slotId + 1);
                }
                slotId = intent.getIntExtra("slot_id", -1);
                if (slotId != -1) {
                    return "SIM" + (slotId + 1);
                }
            }
        } else {
            // Android 5.0及以下:依赖厂商自定义字段
            Integer slotId = intent.getIntExtra("android.intent.extra.slot", -1);
            if (slotId == -1) {
                slotId = intent.getIntExtra("slot_id", -1);
            }
            return slotId != -1 ? "SIM" + (slotId + 1) : "未知SIM卡";
        }
        return "未知SIM卡";
    }

    private String getSimLabelBySubscriptionId(Context context, int subscriptionId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
            if (subscriptionManager != null) {
                SubscriptionInfo info = subscriptionManager.getActiveSubscriptionInfo(subscriptionId);
                if (info != null) {
                    return "SIM" + (info.getSimSlotIndex() + 1) + "(" + info.getDisplayName() + ")";
                }
            }
        }
        return "SIM" + subscriptionId;
    }
}

权限配置(更新Manifest)

除了你已申请的权限,还需要添加高版本所需的权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<!-- Android 10+ 读取电话号码权限 -->
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<!-- Android 12+ 读取来电详情权限 -->
<uses-permission android:name="android.permission.READ_CALL_SCREENING" />

注意:动态权限申请

从Android 6.0(API 23)开始,READ_PHONE_STATEREAD_PHONE_NUMBERS等属于危险权限,需要在代码中动态申请,否则会触发权限异常。

关键注意事项

  1. SIM卡无号码的情况:部分SIM卡未存储本机号码,这时候通过号码匹配的方式会失效,优先使用Android 10+的TelecomManager方案,它不依赖SIM号码。
  2. 厂商适配:不同厂商可能有自定义的Intent参数,比如小米用android.intent.extra.slot,华为用slot_id,需要针对主流厂商做适配测试。
  3. 测试环境:建议用真实双卡手机测试,模拟器大多不支持双卡来电模拟。
  4. 权限限制:Android 10+的TelecomManager.getCalls()需要READ_CALL_SCREENINGREAD_PHONE_STATE权限,务必确保权限已授予。

内容的提问来源于stack exchange,提问作者Amrut Nandedkar

火山引擎 最新活动