前言
某天谴餐,QA給我提了一個(gè)Bug妙蔗,說(shuō)是包裹物流追蹤的電話不能自動(dòng)識(shí)別了蚕冬。正常情況如下圖所示:
在8.1的機(jī)器上免猾,TextView突然不能自動(dòng)識(shí)別電話號(hào)碼了。
1.電話號(hào)碼識(shí)別
Android SDK中囤热,TextView提供了一個(gè)autoLink屬性來(lái)幫助我們識(shí)別各種各樣的鏈接猎提,我們只需要將autoLink屬性設(shè)置為"phone",就能輕易識(shí)別出電話號(hào)碼。
這個(gè)屬性在8.1之前的機(jī)器上是可以正常工作的旁蔼,然而在8.1的機(jī)器上突然不可以了锨苏。那么原因是為何呢?
2.原因探究
通過(guò)查看TextView的源碼棺聊,我們可以知道伞租,系統(tǒng)是借助了一個(gè)名叫Linkify的類(lèi)來(lái)識(shí)別電話號(hào)碼的,具體可以查看文章——autoLink實(shí)現(xiàn)原理
在stackOverFlow上查找關(guān)于autolink無(wú)效的問(wèn)題限佩,android:autoLink for phone numbers doesn't always work
第一個(gè)回答中解釋了為何autoLink會(huì)無(wú)效葵诈,我們可以了解到,autoLink跟手機(jī)的語(yǔ)言有關(guān)(英文或中文)祟同。
首先看下Linkify的關(guān)鍵代碼在8.1之前的實(shí)現(xiàn):
private static final void gatherTelLinks(ArrayList<LinkSpec> links, Spannable s) {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
Locale.getDefault().getCountry(), Leniency.POSSIBLE, Long.MAX_VALUE);
for (PhoneNumberMatch match : matches) {
LinkSpec spec = new LinkSpec();
spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
spec.start = match.start();
spec.end = match.end();
links.add(spec);
}
}
從上面代碼我們可以看到作喘,phoneUtil.findNumbers函數(shù)中傳入了Locale.getDefault().getCountry(),即國(guó)家碼,所以如果當(dāng)前手機(jī)的地區(qū)變動(dòng)晕城,那么可能某些電話號(hào)碼就不會(huì)被正確識(shí)別了泞坦。
然后再看下8.1上Linkify代碼的實(shí)現(xiàn):
private static void gatherTelLinks(ArrayList<LinkSpec> links, Spannable s,
@Nullable Context context) {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
final TelephonyManager tm = (context == null)
? TelephonyManager.getDefault()
: TelephonyManager.from(context);
Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
tm.getSimCountryIso().toUpperCase(Locale.US),
Leniency.POSSIBLE, Long.MAX_VALUE);
for (PhoneNumberMatch match : matches) {
LinkSpec spec = new LinkSpec();
spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
spec.start = match.start();
spec.end = match.end();
links.add(spec);
}
}
以上代碼可以看到,原本傳入地區(qū)碼的地方广辰,變成了getSimCountryIso()暇矫。那么看下這個(gè)函數(shù)的注解:
/**
* Returns the ISO country code equivalent of the current registered
* operator's MCC (Mobile Country Code).
* <p>
* Availability: Only when user is registered to a network. Result may be
* unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
* on a CDMA network).
*/
public String getNetworkCountryIso() {
return getNetworkCountryIsoForPhone(getDefaultPhone());
}
翻譯過(guò)來(lái)就是獲取當(dāng)前運(yùn)營(yíng)商注冊(cè)的國(guó)家碼。而QA的測(cè)試機(jī)是沒(méi)有插入sim卡的择吊,那么這個(gè)函數(shù)返回的CountryCode絕對(duì)不是CN(具體返回啥由底層ROM決定)
在測(cè)試機(jī)插入sim卡之后李根,TextView的autolink又正確工作了,所以可以確定問(wèn)題是出在這里几睛。
3.總結(jié)
8.1之前的手機(jī)房轿,TextView的電話號(hào)碼匹配和當(dāng)前手機(jī)的地區(qū)有關(guān),切換語(yǔ)言時(shí)有可能導(dǎo)致號(hào)碼匹配失效所森。
大于等于8.1的手機(jī)上囱持,號(hào)碼匹配和當(dāng)前手機(jī)插入的sim卡有關(guān),當(dāng)使用國(guó)外的SIM卡或者不插入SIM卡時(shí)焕济,有可能會(huì)導(dǎo)致號(hào)碼匹配失效纷妆。