android中雙卡雙待的那些代碼(增加當前sim卡網(wǎng)絡處理)

這陣子忙著整理項目了魔慷,所以就沒怎么出新的文章了只锭,不過下面寫的這篇文章對大家很有幫助。關于雙卡雙待的信息獲取盖彭,包含了imei纹烹、phonenumberoperatorName(sim卡生產(chǎn)商召边,國內就主要指三大運營商了)铺呵、NetworkType(這里就主要是4G、3G等了)隧熙。

前言:

睡著國內的雙卡手機出現(xiàn)片挂,導致獲取雙卡的信息也是成了一個頭痛的事了贞盯。google給開發(fā)者暴露的api還是停留在單卡上音念,所以在這里我就整理出相關的代碼,讓更多的猿友少走彎路躏敢。

首先從phonenumber的獲取著手吧闷愤,順便帶著大家一起去看下相關的源碼,以前獲取phonenumber我是這么獲取的:

((TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE))
                    .getLine1Number();

這里就調用了TelephonyManagergetLine1Number方法件余,這里順道去源碼看看getLine1Number是怎么獲取的:

/**
     * Returns the phone number string for line 1, for example, the MSISDN
     * for a GSM phone. Return null if it is unavailable.
     * <p>
     * Requires Permission:
     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
     *   OR
     *   {@link android.Manifest.permission#READ_SMS}
     * <p>
     * The default SMS app can also use this.
     */
    public String getLine1Number() {
        return getLine1Number(getSubId());
    }

注:我這里源碼都是android-25下面的讥脐,剛看了下android-23下面的源碼是這么調用的:

/**
     * Returns the phone number string for line 1, for example, the MSISDN
     * for a GSM phone. Return null if it is unavailable.
     * <p>
     * Requires Permission:
     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
     *   OR
     *   {@link android.Manifest.permission#READ_SMS}
     * <p>
     * The default SMS app can also use this.
     */
    public String getLine1Number() {
        return getLine1NumberForSubscriber(getDefaultSubscription());
    }

還是有些區(qū)別的遭居,起碼方法的調用是不一樣的,所以建議你在看該篇文章的時候還是把compileSdk升到25
compileSdkVersion 25
可以看到25的api是繼續(xù)調了:getLine1Number(getSubId())該方法旬渠,那就繼續(xù)往下走吧:

/**
     * Returns the phone number string for line 1, for example, the MSISDN
     * for a GSM phone for a particular subscription. Return null if it is unavailable.
     * <p>
     * Requires Permission:
     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
     *   OR
     *   {@link android.Manifest.permission#READ_SMS}
     * <p>
     * The default SMS app can also use this.
     *
     * @param subId whose phone number for line 1 is returned
     * @hide
     */
    public String getLine1Number(int subId) {
        String number = null;
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                number = telephony.getLine1NumberForDisplay(subId, mContext.getOpPackageName());
        } catch (RemoteException ex) {
        } catch (NullPointerException ex) {
        }
        if (number != null) {
            return number;
        }
        try {
            IPhoneSubInfo info = getSubscriberInfo();
            if (info == null)
                return null;
            return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName());
        } catch (RemoteException ex) {
            return null;
        } catch (NullPointerException ex) {
            // This could happen before phone restarts due to crashing
            return null;
        }
    }

看到這的時候真的是心灰意冷啊俱萍,為什么這么說,該方法竟然是hide類型的方法告丢,對于這種方法咋們就用到反射了枪蘑,后面會詳細介紹的,看看它的參數(shù)是如何解釋的:
@param subId whose phone number for line 1 is returned反正我是英語不好的哈岖免,接著我就去查了查相關的說法岳颇,這里去看看這篇文章是如何解釋的(subid指的是什么),簡單來說subid指的就是sim卡的索引了颅湘,當有一個sim卡的時候subid=1赦役,有兩個的時候subid=2。依次類推就可以知道有幾個卡subid就是多少了栅炒。不過這里的subid還是可以通過反射來獲取subid,后面也會講到如何獲取我們的subid:

private static final String SIM_LINE_NUMBER = "getLine1Number";
private static final String SIM_STATE = "getSimState";

public static String getSimPhonenumber(Context context, int slotIdx) {
    if (PermissionUtil.hasSelfPermission(context, Manifest.permission.READ_PHONE_STATE) ||
            PermissionUtil.hasSelfPermission(context, "android.permission.READ_PRIVILEGED_PHONE_STATE")) {
        Log.d(TAG, "READ_PHONE_STATE permission has BEEN granted to getSimPhonenumber().");
        if (getSimStateBySlotIdx(context, slotIdx)) {
            return (String) getSimByMethod(context, SIM_LINE_NUMBER, getSubidBySlotId(context, slotIdx));
        }
        return null;
    } else {
        Log.d(TAG, "READ_PHONE_STATE permission has NOT been granted to getSimPhonenumber().");
        return null;
    }
}

/**
 *獲取相應卡的狀態(tài)
 * @param slotIdx:0(sim1),1(sim2)
 * @return true:使用中术羔;false:未使用中
 */
public static boolean getSimStateBySlotIdx(Context context, int slotIdx) {
    boolean isReady = false;
    Object getSimState = getSimByMethod(context, SIM_STATE, slotIdx);
    if (getSimState != null) {
        int simState = Integer.parseInt(getSimState.toString());
        if ((simState != TelephonyManager.SIM_STATE_ABSENT) && (simState != TelephonyManager.SIM_STATE_UNKNOWN)) {
            isReady = true;
        }
    }
    return isReady;
}

/**
 * 通過slotid獲取相應卡的subid
 * @param context
 * @param slotId
 * @return
 */
public static int getSubidBySlotId(Context context, int slotId) {
    SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(
            Context.TELEPHONY_SUBSCRIPTION_SERVICE);
    try {
        Class<?> telephonyClass = Class.forName(subscriptionManager.getClass().getName());
        Class<?>[] parameter = new Class[1];
        parameter[0] = int.class;
        Method getSimState = telephonyClass.getMethod("getSubId", parameter);
        Object[] obParameter = new Object[1];
        obParameter[0] = slotId;
        Object ob_phone = getSimState.invoke(subscriptionManager, obParameter);
        if (ob_phone != null) {
            Log.d(TAG, "slotId:" + slotId + ";" + ((int[]) ob_phone)[0]);
            return ((int[]) ob_phone)[0];
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return -1;
}

/**
*通過反射調用相應的方法
*
*/
public static Object getSimByMethod(Context context, String method, int param) {
    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 getSimState = telephonyClass.getMethod(method, parameter);
        Object[] obParameter = new Object[1];
        obParameter[0] = param;
        Object ob_phone = getSimState.invoke(telephony, obParameter);
        if (ob_phone != null) {
            return ob_phone;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

可以看到getSimPhonenumber方法需要slotIdx參數(shù)赢赊,這里還是去這篇文章看看slotldx是咋回事(slotldx到底是啥玩意),通過了解后级历,slotldx指的是那個卡槽了释移,如果當前要獲取卡1,slotldx=0寥殖;如果是卡2玩讳,slotldx=1;到此知道為啥getSimPhonenumber方法需要定義這么個參數(shù)了吧嚼贡。至于說getSimState方法熏纯,還是一樣通過反射去獲取每個卡的狀態(tài)的,這里就不贅述源碼了粤策。上面可以看到獲取subId的代碼了吧樟澜,就是getSubidBySlotId方法了,這里通過反射調用了SubscriptionManager類中的getSubId方法叮盘,需要的參數(shù)也是我們的slotId秩贰。源碼如下:

/** @hide */
public static int[] getSubId(int slotId) {
    if (!isValidSlotId(slotId)) {
        logd("[getSubId]- fail");
        return null;
    }
    int[] subId = null;
    try {
        ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
        if (iSub != null) {
            subId = iSub.getSubId(slotId);
        }
    } catch (RemoteException ex) {
        // ignore it
    }
    return subId;
}

還有imeioperatorName柔吼、NetworkType都可以通過相應的方法獲取了:

private static final String SIM_OPERATOR_NAME = "getNetworkOperatorName";
private static final String SIM_NETWORK_TYPE = "getNetworkType";
private static final String SIM_IMEI = "getImei";

//獲取相應卡的imei
public static String getSimImei(Context context, int slotIdx) {
    if (PermissionUtil.hasSelfPermission(context, Manifest.permission.READ_PHONE_STATE) ||
            PermissionUtil.hasSelfPermission(context, "android.permission.READ_PRIVILEGED_PHONE_STATE")) {
        Log.d(TAG, "READ_PHONE_STATE permission has BEEN granted to getSimImei().");
        if (getSimStateBySlotIdx(context, slotIdx)) {
            //sim1
            if (slotIdx == 0) {
                //這里的參數(shù)傳的是slotldx
                return (String) getSimByMethod(context, SIM_IMEI, 0);
            } else if (slotIdx == 1) {
                return (String) getSimByMethod(context, SIM_IMEI, 1);
            }
        }
        return null;
    } else {
        Log.d(TAG, "READ_PHONE_STATE permission has NOT been granted to getSimImei().");
        return null;
    }
}

public static String getSimNetworkName(Context context, int slotIdx) {
    if (getSimStateBySlotIdx(context, slotIdx)) {
        return getNetworkName((int)
                getSimByMethod(context, SIM_NETWORK_TYPE, getSubidBySlotId(context, slotIdx)));
    }
    return "UNKNOWN";
}

public static String getSimOperatorName(Context context, int slotIdx) {
    if (getSimStateBySlotIdx(context, slotIdx)) {
        return (String) getSimByMethod(context, SIM_OPERATOR_NAME, getSubidBySlotId(context, slotIdx));
    }
    return null;
}

到此相關的屬性獲取基本ok了毒费,大家如果還需要獲取什么屬性,直接去TelephonyManager查看相關的源碼愈魏。還有一個就是插卡和拔卡的監(jiān)聽觅玻、網(wǎng)絡變化的監(jiān)聽:

//網(wǎng)絡變化的監(jiān)聽
public class SimConnectReceive extends BroadcastReceiver {
    private static final String TAG = SimConnectReceive.class.getSimpleName();
    public final static String ACTION_SIM_STATE_CHANGED = ConnectivityManager.CONNECTIVITY_ACTION;

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(ACTION_SIM_STATE_CHANGED)) {
            Log.d(TAG, "onReceive");
            EventBus.getDefault().post(new SimConnectChange());
        }
    }
}

//插卡和拔卡的監(jiān)聽
public class SimStateReceive extends BroadcastReceiver {
    private static final String TAG = SimStateReceive.class.getSimpleName();
    public final static String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(ACTION_SIM_STATE_CHANGED)) {
            Log.d(TAG, "onReceive");
            EventBus.getDefault().post(new SimStateChange());
        }
    }
}

還有就是不要忘了manifest中權限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

demo.png

歡迎客官到本店光臨:184793647(qq群)

最后貼上該功能的代碼:
[github傳送門]
(https://github.com/1002326270xc/DoubleSimCard-master)
thanks:DualSIMCard
csdn傳送門
有什么問題可以email我:a1002326270@163.com

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末想际,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子串塑,更是在濱河造成了極大的恐慌沼琉,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桩匪,死亡現(xiàn)場離奇詭異打瘪,居然都是意外死亡,警方通過查閱死者的電腦和手機傻昙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門闺骚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妆档,你說我怎么就攤上這事僻爽。” “怎么了贾惦?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵胸梆,是天一觀的道長。 經(jīng)常有香客問我须板,道長碰镜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任习瑰,我火速辦了婚禮绪颖,結果婚禮上,老公的妹妹穿的比我還像新娘甜奄。我一直安慰自己柠横,他們只是感情好,可當我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布课兄。 她就那樣靜靜地躺著牍氛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪第喳。 梳的紋絲不亂的頭發(fā)上糜俗,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天,我揣著相機與錄音曲饱,去河邊找鬼悠抹。 笑死,一個胖子當著我的面吹牛扩淀,可吹牛的內容都是我干的楔敌。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼驻谆,長吁一口氣:“原來是場噩夢啊……” “哼卵凑!你這毒婦竟也來了庆聘?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤勺卢,失蹤者是張志新(化名)和其女友劉穎伙判,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體黑忱,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡宴抚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了甫煞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菇曲。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抚吠,靈堂內的尸體忽然破棺而出常潮,到底是詐尸還是另有隱情,我是刑警寧澤楷力,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布喊式,位于F島的核電站,受9級特大地震影響萧朝,放射性物質發(fā)生泄漏垃帅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一剪勿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧方庭,春花似錦厕吉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至龄减,卻和暖如春项钮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背希停。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工烁巫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宠能。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓亚隙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親违崇。 傳聞我的和親對象是個殘疾皇子阿弃,可洞房花燭夜當晚...
    茶點故事閱讀 43,658評論 2 350