轉(zhuǎn)載自:【騰訊優(yōu)測干貨分享】Android5.0-6.0雙卡適配指南
原作者:騰訊優(yōu)測開發(fā)工程師 于長敏
這里僅以獲取sim卡的IMSI接口(getSubscriberId)和發(fā)短信接口(sendTextMessage)為例來詳細講解一下Android5.0-6.0雙卡適配的策略,其他方面的雙卡適配方案跟4.4以前相比并無特別大的區(qū)別,之前我們已有專家對此進行過詳細的總結(jié),這里就不重復(fù)說明了。
從Android5.0開始,加入了對雙卡的管理:
首先從數(shù)據(jù)庫方面來看,其設(shè)計思路跟以前某平臺是一樣的,加入一個siminfo數(shù)據(jù)表到telephony.db來管理雙卡的信息。數(shù)據(jù)表URL:content://telephony/siminfo
所有插入過的SIM卡的相關(guān)信息都會存儲在這個表里,再看看表里的字段,這里截圖只截了前面的幾個比較關(guān)鍵的字段
從截圖中可以看到我用紅框所框的字段,這兩個是尤為關(guān)鍵的字段,也是對我們在功能開發(fā)的極其關(guān)鍵的兩個字段。下面簡單說一下這兩個字段的含義:
_id是表的主鍵,代表sim卡數(shù)據(jù)的索引值,從1開始,每次新插入的一張sim卡,數(shù)據(jù)表都會插入一行新數(shù)據(jù),該行數(shù)據(jù)的_id值每次遞增1(1,2,3,4,5……n這樣遞增),而不是更換一張卡更新一下對應(yīng)卡槽的數(shù)據(jù)行的sim卡數(shù)據(jù)。
sim_id代表當(dāng)前卡所在的卡槽值,只有0,1,-1三個值,0代表當(dāng)前卡插在卡槽1當(dāng)中(主卡槽),1代表當(dāng)前卡插在卡槽2當(dāng)中(副卡槽),-1代表曾經(jīng)手機插入過此卡,現(xiàn)在已經(jīng)移除。
其次從加入的API來看,Google加入了一系列管理雙卡信息的類,其主要框架如下圖所示:
這些API中除了SubscriptionManager之外主要都是供手機系統(tǒng)內(nèi)部管理雙卡信息使用,對上層功能開發(fā)的用途并不大,這里只供參考,不做詳細講解。
而SubscriptionManager這個類提供了一個關(guān)鍵的方法給上層開發(fā)來查詢使用,這里只對它的這個關(guān)鍵方法進行一下簡單分析。
方法名是:getSubId,獲取指定卡槽sim卡的subId,對應(yīng)的就是前面所講的數(shù)據(jù)表中的_id值。 為什么說這個方法對上層開發(fā)來說非常關(guān)鍵,咱們先來看一下5.0-6.0的前面提到的要適配的兩個接口是怎么設(shè)計的,大家就知道它為什么關(guān)鍵了,在這里先賣個關(guān)子。
Android5.0開始,不單加入了上面這些一系列管理雙卡信息的API,也加入了獲取各sim卡信息狀態(tài)以及調(diào)用不同sim卡發(fā)短信的接口。
發(fā)送短信的方案
大家都知道平時咱們開發(fā)的發(fā)短信功能大多數(shù)是調(diào)用SmsManager類提供的sendTextMessage方法來發(fā)短信的,但是對于雙卡手機來講,按照之前常規(guī)的方式,只能是通過默認(rèn)卡發(fā)出短信,那該怎么辦呢?先來看一段代碼截圖:
這段代碼的截圖是SDK5.1中的SmsManager代碼片段,英文注釋就不詳細翻譯了,相信英文大神無處不在,我就不獻丑了,大家自己翻譯一下就好。
大家看到了什么?沒錯:
@param subId an SMS subscription id, typically accessed using
{@link android.telephony.SubscriptionManager}
@return the instance of the SmsManager associated with subId
這兩行關(guān)鍵注釋,進一步提煉一下,subId,subId,subId啊啊啊,關(guān)鍵詞重復(fù)三遍。
到這里大家是不是豁然開朗,一目了然前面所賣的關(guān)子的原因:通過subId可以獲取到對應(yīng)sim卡的SmsManager實例,而subId正是通過SubscriptionManager的getSubId方法來獲取的,有了對應(yīng)sim卡的SmsManager實例之后,按照以前的方法通過調(diào)用該實例的sendTextMessage方法就可以實現(xiàn)通過不同卡發(fā)短信的需求了。
以上是雙卡發(fā)短信適配的常規(guī)方式,先說到這里,但并沒有完。
下面再說一下獲取IMSI的適配方案:
理解了發(fā)短信的方案之后,下面這個方案也很好理解,直接看代碼:
也是在TelephonyManager類里面新增了一個帶參數(shù)的getSubscriberId方法,大家應(yīng)該早已發(fā)現(xiàn),參數(shù)也是subId,沒錯就是它。再一次證明了SubscriptionManager的getSubId方法的關(guān)鍵性。
適配方案就是通過phone服務(wù)獲取TelephonyManager的實例,從而調(diào)用這個帶參數(shù)的getSubscriberId方法來獲取對應(yīng)sim卡的IMSI,OK搞定。
說到這里,既然getSubId方法這么關(guān)鍵,咱們再返回來一睹SubscriptionManager的getSubId方法代碼的風(fēng)采:
由代碼可見,getSubId方法也需要一個int類型的參數(shù),通過參數(shù)名不難理解到,它需要的就是對應(yīng)sim卡所在的卡槽值,也就是對應(yīng)前面數(shù)據(jù)表中的sim_id,傳入的合法有效值為0和1,就可以獲取到對應(yīng)的subId。 到目前為止該方法還是一個隱藏方法,外部不能直接調(diào)用,如果需要使用,可以通過反射的方式調(diào)用。另外還有一點需要注意的是,該方法返回的是一個int數(shù)組,使用的時候取它的第一個值就OK了,其實它里面也只有一個值,至于為什么要以數(shù)組形式返回而不是直接返回int,我也不是非常清楚,并表示不理解,有興趣的朋友可以研究研究為什么要這樣。
適配第三方 ROM
講到這里,方案看上去貌似挺完美,但是真的是這樣嗎?甚至細心的朋友會懷疑:你這只是官方新增的標(biāo)準(zhǔn)API,稱不上適配吧?
沒錯,事情并沒有這么簡單,這些只能算是5.0以后實現(xiàn)雙卡需求的一個標(biāo)準(zhǔn)解決方案,只能應(yīng)對極其少數(shù)幾個有節(jié)操的大廠的ROM還可以,比如三星,做到現(xiàn)在發(fā)現(xiàn)5.0以后的三星ROM都很規(guī)矩(題外話)。
標(biāo)準(zhǔn)!標(biāo)準(zhǔn)!標(biāo)準(zhǔn)!有節(jié)操!有節(jié)操!有節(jié)操的大廠,那么針對那些大多數(shù)沒節(jié)操的廠商該怎么辦?
別急,方案還是有的,做到目前為止,發(fā)現(xiàn)會出現(xiàn)適配性問題的地方都是發(fā)生在SubscriptionManager和SmsManager身上,比如有的ROM沒有了SubscriptionManager類,有的改名了,有點改方法名了等等。
那么怎么應(yīng)對subId這個問題?
仔細想想,前面我說過subId就是數(shù)據(jù)表中_id的值,其實SubscriptionManager底層的實現(xiàn)也是通過查詢這個表得到的。那么我們就管你改成什么了,果斷通過傳入卡槽值(sim_id)來查詢sim卡的_id值不就OK了么。事實也證明此方案可行,具體代碼如下:
通過這個方法來獲取到subId值來提供給發(fā)短信和獲取IMSI接口使用,完美解決了以上存在是適配性問題。
然而SmsManager如果也被修改了怎么辦,繼續(xù)看一下下面的代碼截圖:
通過這段代碼,我們聯(lián)想到是不是可以越過SmsManager,直接通過isms服務(wù)獲取ISms接口的實例,通過調(diào)用ISms接口的sendTextForSubscriber方法來實現(xiàn)雙卡發(fā)短信?答案是肯定的,我們看到方法的第一個參數(shù)是通過getSubscriptionId()方法獲取到的一個值,沒錯,它也是我們前面提到的subId,都可以通過我們查詢DB的方法來獲取。
好在做到現(xiàn)在,ISms接口的sendTextForSubscriber方法還沒有發(fā)現(xiàn)被修改的,相信也不會有廠商無節(jié)操到這種地步吧。估計他們也做不到。
最后補充一點,前面所用示例代碼都是通過Android5.1獲取的,其中5.0-6.0不同版本是有區(qū)別的:
- getSubscriberId各版本的區(qū)別:
subId在5.0傳入的是long類型的參數(shù),而5.1-6.0傳入的是int類型的參數(shù)。 - sendTextForSubscriber各版本的區(qū)別:
subId在5.0傳入的是long類型的參數(shù),而5.1-6.0傳入的是int類型的參數(shù),并且6.0與5.1還有區(qū)別,就是方法參數(shù)列表末尾多出一個boolean類型的參數(shù)。
針對這幾個小差別很好辦,就是將查詢到的subId給轉(zhuǎn)換成對應(yīng)的類型,6.0發(fā)短信方法的多傳的boolean類型的參數(shù)傳true值就OK了。
OK,講到這里,真正的雙卡適配才算講完,如有更完美的方案,歡迎大家與我交流。
————————-
騰訊優(yōu)測是備受客戶信賴的移動云測試平臺,為應(yīng)用、游戲、H5混合應(yīng)用的研發(fā)團隊提供產(chǎn)品質(zhì)量檢測與問題解決服務(wù)。
不僅在線上平臺提供app自動化測試、云真機遠程操控與調(diào)試等多種質(zhì)量檢測工具,更為VIP客戶配備了專家團隊提供定制化綜合測試解決方案。