轉(zhuǎn)載自:【騰訊優(yōu)測(cè)干貨分享】Android5.0-6.0雙卡適配指南
原作者:騰訊優(yōu)測(cè)開發(fā)工程師 于長(zhǎng)敏
這里僅以獲取sim卡的IMSI接口(getSubscriberId)和發(fā)短信接口(sendTextMessage)為例來(lái)詳細(xì)講解一下Android5.0-6.0雙卡適配的策略器躏,其他方面的雙卡適配方案跟4.4以前相比并無(wú)特別大的區(qū)別,之前我們已有專家對(duì)此進(jìn)行過(guò)詳細(xì)的總結(jié)志于,這里就不重復(fù)說(shuō)明了。
從Android5.0開始禽篱,加入了對(duì)雙卡的管理:
首先從數(shù)據(jù)庫(kù)方面來(lái)看寝志,其設(shè)計(jì)思路跟以前某平臺(tái)是一樣的忘分,加入一個(gè)siminfo數(shù)據(jù)表到telephony.db來(lái)管理雙卡的信息爵川。數(shù)據(jù)表URL:content://telephony/siminfo
所有插入過(guò)的SIM卡的相關(guān)信息都會(huì)存儲(chǔ)在這個(gè)表里敷鸦,再看看表里的字段,這里截圖只截了前面的幾個(gè)比較關(guān)鍵的字段
從截圖中可以看到我用紅框所框的字段寝贡,這兩個(gè)是尤為關(guān)鍵的字段扒披,也是對(duì)我們?cè)诠δ荛_發(fā)的極其關(guān)鍵的兩個(gè)字段。下面簡(jiǎn)單說(shuō)一下這兩個(gè)字段的含義:
_id是表的主鍵兔甘,代表sim卡數(shù)據(jù)的索引值谎碍,從1開始鳞滨,每次新插入的一張sim卡洞焙,數(shù)據(jù)表都會(huì)插入一行新數(shù)據(jù),該行數(shù)據(jù)的_id值每次遞增1(1拯啦,2澡匪,3,4矮台,5……n這樣遞增)兼雄,而不是更換一張卡更新一下對(duì)應(yīng)卡槽的數(shù)據(jù)行的sim卡數(shù)據(jù)辈灼。
sim_id代表當(dāng)前卡所在的卡槽值,只有0甸鸟,1惦费,-1三個(gè)值,0代表當(dāng)前卡插在卡槽1當(dāng)中(主卡槽)抢韭,1代表當(dāng)前卡插在卡槽2當(dāng)中(副卡槽)薪贫,-1代表曾經(jīng)手機(jī)插入過(guò)此卡,現(xiàn)在已經(jīng)移除刻恭。
其次從加入的API來(lái)看瞧省,Google加入了一系列管理雙卡信息的類,其主要框架如下圖所示:
這些API中除了SubscriptionManager之外主要都是供手機(jī)系統(tǒng)內(nèi)部管理雙卡信息使用鳍贾,對(duì)上層功能開發(fā)的用途并不大鞍匾,這里只供參考,不做詳細(xì)講解骑科。
而SubscriptionManager這個(gè)類提供了一個(gè)關(guān)鍵的方法給上層開發(fā)來(lái)查詢使用橡淑,這里只對(duì)它的這個(gè)關(guān)鍵方法進(jìn)行一下簡(jiǎn)單分析。
方法名是:getSubId咆爽,獲取指定卡槽sim卡的subId梳码,對(duì)應(yīng)的就是前面所講的數(shù)據(jù)表中的_id值。 為什么說(shuō)這個(gè)方法對(duì)上層開發(fā)來(lái)說(shuō)非常關(guān)鍵伍掀,咱們先來(lái)看一下5.0-6.0的前面提到的要適配的兩個(gè)接口是怎么設(shè)計(jì)的掰茶,大家就知道它為什么關(guān)鍵了,在這里先賣個(gè)關(guān)子蜜笤。
Android5.0開始濒蒋,不單加入了上面這些一系列管理雙卡信息的API,也加入了獲取各sim卡信息狀態(tài)以及調(diào)用不同sim卡發(fā)短信的接口把兔。
發(fā)送短信的方案
大家都知道平時(shí)咱們開發(fā)的發(fā)短信功能大多數(shù)是調(diào)用SmsManager類提供的sendTextMessage方法來(lái)發(fā)短信的沪伙,但是對(duì)于雙卡手機(jī)來(lái)講,按照之前常規(guī)的方式县好,只能是通過(guò)默認(rèn)卡發(fā)出短信围橡,那該怎么辦呢?先來(lái)看一段代碼截圖:
這段代碼的截圖是SDK5.1中的SmsManager代碼片段缕贡,英文注釋就不詳細(xì)翻譯了翁授,相信英文大神無(wú)處不在,我就不獻(xiàn)丑了晾咪,大家自己翻譯一下就好收擦。
大家看到了什么?沒(méi)錯(cuò):
@param subId an SMS subscription id, typically accessed using
{@link android.telephony.SubscriptionManager}
@return the instance of the SmsManager associated with subId
這兩行關(guān)鍵注釋谍倦,進(jìn)一步提煉一下塞赂,subId,subId昼蛀,subId啊啊啊宴猾,關(guān)鍵詞重復(fù)三遍圆存。
到這里大家是不是豁然開朗,一目了然前面所賣的關(guān)子的原因:通過(guò)subId可以獲取到對(duì)應(yīng)sim卡的SmsManager實(shí)例仇哆,而subId正是通過(guò)SubscriptionManager的getSubId方法來(lái)獲取的辽剧,有了對(duì)應(yīng)sim卡的SmsManager實(shí)例之后,按照以前的方法通過(guò)調(diào)用該實(shí)例的sendTextMessage方法就可以實(shí)現(xiàn)通過(guò)不同卡發(fā)短信的需求了税产。
以上是雙卡發(fā)短信適配的常規(guī)方式怕轿,先說(shuō)到這里,但并沒(méi)有完辟拷。
下面再說(shuō)一下獲取IMSI的適配方案:
理解了發(fā)短信的方案之后撞羽,下面這個(gè)方案也很好理解,直接看代碼:
也是在TelephonyManager類里面新增了一個(gè)帶參數(shù)的getSubscriberId方法衫冻,大家應(yīng)該早已發(fā)現(xiàn)诀紊,參數(shù)也是subId,沒(méi)錯(cuò)就是它隅俘。再一次證明了SubscriptionManager的getSubId方法的關(guān)鍵性邻奠。
適配方案就是通過(guò)phone服務(wù)獲取TelephonyManager的實(shí)例,從而調(diào)用這個(gè)帶參數(shù)的getSubscriberId方法來(lái)獲取對(duì)應(yīng)sim卡的IMSI为居,OK搞定碌宴。
說(shuō)到這里,既然getSubId方法這么關(guān)鍵蒙畴,咱們?cè)俜祷貋?lái)一睹SubscriptionManager的getSubId方法代碼的風(fēng)采:
由代碼可見(jiàn)贰镣,getSubId方法也需要一個(gè)int類型的參數(shù),通過(guò)參數(shù)名不難理解到膳凝,它需要的就是對(duì)應(yīng)sim卡所在的卡槽值碑隆,也就是對(duì)應(yīng)前面數(shù)據(jù)表中的sim_id,傳入的合法有效值為0和1蹬音,就可以獲取到對(duì)應(yīng)的subId上煤。 到目前為止該方法還是一個(gè)隱藏方法,外部不能直接調(diào)用著淆,如果需要使用劫狠,可以通過(guò)反射的方式調(diào)用。另外還有一點(diǎn)需要注意的是牧抽,該方法返回的是一個(gè)int數(shù)組嘉熊,使用的時(shí)候取它的第一個(gè)值就OK了遥赚,其實(shí)它里面也只有一個(gè)值扬舒,至于為什么要以數(shù)組形式返回而不是直接返回int,我也不是非常清楚凫佛,并表示不理解讲坎,有興趣的朋友可以研究研究為什么要這樣孕惜。
適配第三方 ROM
講到這里,方案看上去貌似挺完美晨炕,但是真的是這樣嗎衫画?甚至細(xì)心的朋友會(huì)懷疑:你這只是官方新增的標(biāo)準(zhǔn)API,稱不上適配吧瓮栗?
沒(méi)錯(cuò)削罩,事情并沒(méi)有這么簡(jiǎn)單,這些只能算是5.0以后實(shí)現(xiàn)雙卡需求的一個(gè)標(biāo)準(zhǔn)解決方案费奸,只能應(yīng)對(duì)極其少數(shù)幾個(gè)有節(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é)操的大廠辛孵,那么針對(duì)那些大多數(shù)沒(méi)節(jié)操的廠商該怎么辦丛肮?
別急,方案還是有的魄缚,做到目前為止腾供,發(fā)現(xiàn)會(huì)出現(xiàn)適配性問(wèn)題的地方都是發(fā)生在SubscriptionManager和SmsManager身上,比如有的ROM沒(méi)有了SubscriptionManager類鲜滩,有的改名了伴鳖,有點(diǎn)改方法名了等等。
那么怎么應(yīng)對(duì)subId這個(gè)問(wèn)題徙硅?
仔細(xì)想想榜聂,前面我說(shuō)過(guò)subId就是數(shù)據(jù)表中_id的值,其實(shí)SubscriptionManager底層的實(shí)現(xiàn)也是通過(guò)查詢這個(gè)表得到的嗓蘑。那么我們就管你改成什么了须肆,果斷通過(guò)傳入卡槽值(sim_id)來(lái)查詢sim卡的_id值不就OK了么。事實(shí)也證明此方案可行桩皿,具體代碼如下:
通過(guò)這個(gè)方法來(lái)獲取到subId值來(lái)提供給發(fā)短信和獲取IMSI接口使用豌汇,完美解決了以上存在是適配性問(wèn)題。
然而SmsManager如果也被修改了怎么辦泄隔,繼續(xù)看一下下面的代碼截圖:
通過(guò)這段代碼拒贱,我們聯(lián)想到是不是可以越過(guò)SmsManager,直接通過(guò)isms服務(wù)獲取ISms接口的實(shí)例,通過(guò)調(diào)用ISms接口的sendTextForSubscriber方法來(lái)實(shí)現(xiàn)雙卡發(fā)短信逻澳?答案是肯定的闸天,我們看到方法的第一個(gè)參數(shù)是通過(guò)getSubscriptionId()方法獲取到的一個(gè)值,沒(méi)錯(cuò)斜做,它也是我們前面提到的subId苞氮,都可以通過(guò)我們查詢DB的方法來(lái)獲取。
好在做到現(xiàn)在瓤逼,ISms接口的sendTextForSubscriber方法還沒(méi)有發(fā)現(xiàn)被修改的笼吟,相信也不會(huì)有廠商無(wú)節(jié)操到這種地步吧。估計(jì)他們也做不到霸旗。
最后補(bǔ)充一點(diǎn)赞厕,前面所用示例代碼都是通過(guò)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ù)列表末尾多出一個(gè)boolean類型的參數(shù)。
針對(duì)這幾個(gè)小差別很好辦箱蟆,就是將查詢到的subId給轉(zhuǎn)換成對(duì)應(yīng)的類型沟绪,6.0發(fā)短信方法的多傳的boolean類型的參數(shù)傳true值就OK了。
OK空猜,講到這里绽慈,真正的雙卡適配才算講完,如有更完美的方案辈毯,歡迎大家與我交流坝疼。
————————-
騰訊優(yōu)測(cè)是備受客戶信賴的移動(dòng)云測(cè)試平臺(tái),為應(yīng)用谆沃、游戲钝凶、H5混合應(yīng)用的研發(fā)團(tuán)隊(duì)提供產(chǎn)品質(zhì)量檢測(cè)與問(wèn)題解決服務(wù)。
不僅在線上平臺(tái)提供app自動(dòng)化測(cè)試唁影、云真機(jī)遠(yuǎn)程操控與調(diào)試等多種質(zhì)量檢測(cè)工具耕陷,更為VIP客戶配備了專家團(tuán)隊(duì)提供定制化綜合測(cè)試解決方案。