android中雙卡雙待的那些程式碼
這陣子忙著整理專案了,所以就沒怎麼出新的文章了,不過下面寫的這篇文章對大家很有幫助。關於雙卡雙待的資訊獲取,包含了imei、phonenumber、operatorName(sim卡生產商,國內就主要指三大運營商了)、NetworkType(這裡就主要是4G、3G等了)。
前言:
睡著國內的雙卡手機出現,導致獲取雙卡的資訊也是成了一個頭痛的事了。google給開發者暴露的api還是停留在單卡上,所以在這裡我就整理出相關的程式碼,讓更多的猿友少走彎路。
首先從phonenumber的獲取著手吧,順便帶著大家一起去看下相關的原始碼,以前獲取phonenumber我是這麼獲取的:
((TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE)) .getLine1Number();
這裡就呼叫了TelephonyManager的getLine1Number方法,這裡順道去原始碼看看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());
}
還是有些區別的,起碼方法的呼叫是不一樣的,所以建議你在看該篇文章的時候還是把compileSdk升到25:
compileSdkVersion 25
可以看到25的api是繼續調了:getLine1Number(getSubId())
該方法,那就繼續往下走吧:
/**
* 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型別的方法,對於這種方法咋們就用到反射了,後面會詳細介紹的,看看它的引數是如何解釋的:
@param subId whose phone number for line 1 is returned
反正我是英語不好的哈,接著我就去查了查相關的說法,這裡去看看這篇文章是如何解釋的(subid指的是什麼),簡單來說subbed
指的就是sim卡的索引了,當有一個sim卡的時候subid=1,有兩個的時候subid=2。依次類推就可以知道有幾個卡subid就是多少了。不過這裡的subid還是可以通過反射來獲取subid,後面也會講到如何獲取我們的subbed:
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;
}
}
/**
*獲取相應卡的狀態
* @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
引數,這裡還是去這篇文章看看slotldx
是咋回事(slotldx到底是啥玩意),通過了解後,slotldx指的是那個卡槽了,如果當前要獲取卡1,slotldx=0;如果是卡2,slotldx=1;到此知道為啥getSimPhonenumber
方法需要定義這麼個引數了吧。至於說getSimState
方法,還是一樣通過反射去獲取每個卡的狀態的,這裡就不贅述原始碼了。上面可以看到獲取subId的程式碼了吧,就是getSubidBySlotId
方法了,這裡通過反射呼叫了SubscriptionManager
類中的getSubId
方法,需要的引數也是我們的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;
}
還有imei
、operatorName
、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) {
//這裡的引數傳的是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
檢視相關的原始碼。還有一個就是插卡和拔卡的監聽、網路變化的監聽:
//網路變化的監聽
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());
}
}
}
//插卡和拔卡的監聽
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" />
對於6.0的動態許可權處理也是新增該許可權的判斷。
最後貼上該功能的程式碼:
github傳送門
thanks:DualSIMCard
有什麼問題可以email我:[email protected]
相關推薦
android中雙卡雙待的那些程式碼
這陣子忙著整理專案了,所以就沒怎麼出新的文章了,不過下面寫的這篇文章對大家很有幫助。關於雙卡雙待的資訊獲取,包含了imei、phonenumber、operatorName(sim卡生產商,國內就主要指三大運營商了)、NetworkType(這裡就主要是4G、3
android實現異網雙卡雙待識別運營商網路
檢測的程式碼 private void checkIMSi() { boolean simStateBySlotIdx = SimUtils.getSimStateBySlotIdx(this, 0); &n
android-手機登入介面嘗試獲取手機號碼,並可選擇雙卡雙待subscriptionId
LogonActivity.java public class LogonActivity extends Activity { private EditText nickET; private EditText passwordET; private E
android sim 卡雙卡雙待
Android的RIL驅動模組,在hardware/ril目錄下,一共分rild,libril.so以及librefrence_ril.so三個部分,另有一 radiooptions可供自動或手動除錯使用。都依賴於include目錄中ril.h標頭檔案。目前cupcake分支上帶的是gsm的支援,另有
Android獲取本機號碼(雙卡雙待無法獲取兩個號碼)
搞了一個想獲取Android手機的本機號碼的功能,但是發現雙卡雙待的手機是無法獲取到兩個號碼 的。在Android的官方文件是沒有提供相應的Api的,因為標準的Andoird是沒有雙卡的,好像也只有國內才會搞雙卡雙待的神器吧。以下記錄一下做這個功能所學習到的
Android 雙卡雙待
轉自這裡 一、雙卡雙待背景分析 使用者為了兼顧運營商優勢,使用雙卡雙待手機: 雙卡雙待這項技術在發展中國家使用很普遍,因為在發展中國家電信運營商發展不夠成熟,相關管理制度不完善。從使用者的角度出發,主要考慮資費問題,比如:移動通話訊號好,聯通3G上網流暢、流量費相
Android 雙卡雙待識別
簡介Android雙卡雙待已經越來越普及了,解決雙卡雙待管理是廣大手機開發人員必須得面對的問題,為實現Android平臺的雙卡雙待操作,筆者研究了Android 應用層操作雙卡雙待的機制。機制獲取基於ITelephony介面實現phone應用中的“phone服務”,通過Tel
Android 解決雙卡雙待的問題 mtk,展訊,高通
目前國內對於雙卡智慧手機的需求還是很大的,各種複雜的業務會涉及到雙卡模組;而android標準的api又不提供對雙卡的支援。導致國內雙卡模組標準混亂,各個廠商各玩各的。目前我知道的雙卡解決方案就有:mtk,展訊,高通,broadcom等。 由於公司業務需要,必須要對雙
聚焦鏈改,雙卡雙待
在北京 cdd 北京時間 投資 們的 生態 整合 term ces “為了你我用了半年的積蓄,熬著夜來看你……”這說的大概就是蘋果發布會吧 蘋果的新產品發布會在北京時間9月13日淩晨一點舉行相信果粉們應該都沒有錯過這場盛會 然鵝....窮人才看發布會,土豪都是睡醒直接買這次
華為雙卡雙待手機聯通3G上網慢的解決辦法
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
AI技術的蘋果iPhone XS Max雙卡雙待7納米6.5寸512GB頂配12799元(公號回覆“蘋果AI”下載PDF資料)
AI技術的蘋果iPhone XS Max雙卡雙待7納米6.5寸512GB頂配12799元(公號回覆“蘋果AI”下載PDF資料) 原創: 秦隴紀 科學Sciences 今天 科學Sciences導讀:北京時間9月13日凌晨1點、美國時間9月12日上午10點,蘋果2018秋季新品釋出會召
雙卡雙待 getDeviceId unique device ID IMEI 不唯一 會變問題
最近接到使用者反饋無法登入的情況越來越多,因為我們的app設計上是不能換手機用,也就是綁定了唯一的裝置ID。從反饋上來看,有一個線索是大部分是雙卡雙待的使用者出現這個問題,並且切換過SIM卡。看來getDeviceId這個方法在雙卡雙待手機上獲取IMEI還是有問題的。 ge
雙卡雙待(一)
前言: 關於雙卡雙待這個問題,調研了幾個月終於有所進展,通過收集各方面的資料,整理出了這個文件。~~╭(╯^╰)╮ 1.獲取雙卡的subId 方法1: /** * @param slotId:卡槽的序號:0代表卡槽1,1代表卡槽2
Android中 view的雙緩衝技術
view實現雙緩衝技術 當要繪製的資料量比較大,繪圖時間比較長時,重複繪圖會出現閃爍現象,引起閃爍現象的主要原因是視覺反差比較大。 使用雙緩衝技術可以解決這個問題,Surfaceview預設是使用雙緩衝技術的。 在Android上實現雙緩衝技術的步驟是: 建立一個螢幕大小(實際繪圖區域)的緩衝區(
智慧手機之雙卡雙待的實現方案
雙卡雙待的出現背景: 手機通訊發展到一定程度之後,很多使用者希望擁有或已經擁用多個手機電話號碼,特別是針對那些經常需要出差,需要經常切換SIM卡的商務人士而言,其迫切希望能將自己的手機承載多個電話號碼, 根據市場上的這一需求,能同時支援兩張SIM卡的
Android中判斷網路是否可用的程式碼_大企鵝
這篇文章主要介紹了Android中判斷網路是否可用的程式碼分享, 本文直接給出實現程式碼,需要的朋友可以參考下 獲取網路資訊需要在AndroidManifest.xml檔案中加入相應的許可權: <uses-permission android:nam
如何有效的清除Android中無用的資源(靜態程式碼分析)
最近公司要做這個,簡單調研了一下,現有的大多數部落格也比較舊了,不太合適,總結了這麼幾個方式吧,一起來學習下。 為什麼要清除Android中這些資源呢 是這樣的,今天收到的郵件裡,有這麼一條任務: 資源優化 軟體中無用的圖片和佈局檔案,找到並驗證是否無用. 這個需要設計一套工具進行分析(自
Android中NFC功能流程圖解析及程式碼演示『轉』
在Android4.0推出的時候,一個非常引人注目的功能就是NFC(Near Field Communication). Near Field Communication (NFC) is a set of short-range wireless tech
cocos2dx對於android中sd卡的訪問方式
今天在弄專案的時候涉及到cocos2dx引擎需要訪問sdcard上的資源,目前發現兩種比較簡單的方法: 1、直接使用硬編碼的方式來進行訪問,例如“/storage/sdcard0/NetAnswer/questions%d.xml”的方式來確定檔案路徑,但是這種方式是正確的
Android中實現雙擊點贊動畫效果
iv_easy_like.getBackground().setAlpha(0); rlLike.setOnTouchListener(new OnDoubleClickListener(new OnDoubleClickListener.DoubleClickCallb