Android应用:如何识别通讯录中无国家码联系人的国家/地区代码
检测Android通讯录号码的国家/地区代码方案
嘿,这个需求我在做通讯类App的时候刚好实现过,给你分享几个靠谱的方法,从官方工具到第三方库都有,足够覆盖你的场景:
一、Google官方推荐:Libphonenumber库
这是处理电话号码最权威的工具,由Google维护,能完美识别各种格式的号码(带+、00前缀或者本地号),还能处理全球几乎所有国家的号码规则。
1. 引入依赖
在你的App模块的build.gradle(或者build.gradle.kts)里添加:
dependencies { implementation 'com.googlecode.libphonenumber:libphonenumber:8.13.27' implementation 'com.googlecode.libphonenumber:geocoder:8.13.27' // 可选,用来获取国家名称 }
2. 核心代码示例
首先要获取设备默认的国家代码(用来解析本地号,比如以0开头的号码),然后遍历通讯录号码逐个解析:
import com.google.i18n.phonenumbers.PhoneNumberUtil import com.google.i18n.phonenumbers.Phonenumber import android.telephony.TelephonyManager import android.content.Context // 获取设备默认国家代码(ISO 3166-1 alpha-2格式,比如"AE"代表阿联酋) fun getDefaultCountryCode(context: Context): String { val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager // 优先取SIM卡的国家代码,没有的话取网络的 return telephonyManager.simCountryIso.ifEmpty { telephonyManager.networkCountryIso } } // 解析单个号码,返回国家代码(比如"+971") fun parsePhoneNumberCountryCode(phoneNumber: String, defaultCountry: String): String? { val phoneNumberUtil = PhoneNumberUtil.getInstance() return try { val number = phoneNumberUtil.parse(phoneNumber, defaultCountry) // 获取E.164格式的国家代码前缀 "+${number.countryCode}" } catch (e: Exception) { // 解析失败(比如无效号码),返回null或者根据需求处理 null } }
3. 遍历通讯录的逻辑
记得先申请READ_CONTACTS权限(动态申请,Android 6.0+必须),然后通过ContentResolver读取通讯录:
import android.content.ContentResolver import android.provider.ContactsContract import android.database.Cursor fun fetchContactsAndParseCountryCodes(context: Context) { val contentResolver: ContentResolver = context.contentResolver val projection = arrayOf( ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER ) contentResolver.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null, null )?.use { cursor: Cursor -> val nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME) val numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER) val defaultCountry = getDefaultCountryCode(context) while (cursor.moveToNext()) { val contactName = cursor.getString(nameIndex) val rawNumber = cursor.getString(numberIndex) // 先去除号码里的空格、括号等非数字字符 val cleanedNumber = rawNumber.replace(Regex("[^0-9+]"), "") val countryCode = parsePhoneNumberCountryCode(cleanedNumber, defaultCountry) // 这里处理结果,比如打印或者存入列表 println("联系人:$contactName,号码:$rawNumber,国家代码:$countryCode") } } }
二、Android原生工具:PhoneNumberUtils(局限性较大)
如果不想引入第三方库,可以用系统自带的PhoneNumberUtils,但它的识别能力远不如Libphonenumber,只能处理简单的场景:
import android.telephony.PhoneNumberUtils fun getCountryCodeFromRawNumber(number: String, defaultCountry: String): String? { // 尝试提取国家代码,本地号需要传入默认国家 val normalizedNumber = PhoneNumberUtils.normalizeNumber(number) val countryCode = PhoneNumberUtils.getCountryCodeForRegion(defaultCountry) return if (normalizedNumber.startsWith("+") || normalizedNumber.startsWith("00")) { // 带前缀的号码,提取前几位 PhoneNumberUtils.extractCountryCode(normalizedNumber, defaultCountry)?.let { "+$it" } } else { // 本地号,用默认国家代码 "+$countryCode" } }
注意:这个方法对非标准格式的号码识别容易出错,比如不同国家的本地号规则差异大,所以只推荐简单场景使用。
三、手动处理(不推荐)
如果你想自己写逻辑,需要维护一个国家代码映射表,然后判断号码前缀,但这种方法非常繁琐,而且容易遗漏国家/地区的规则,比如:
- 带+的号码:直接提取+后面的数字直到第一个非国家代码部分
- 带00的号码:把00替换成+,然后按上面的逻辑处理
- 本地号:用设备默认国家代码
但这种方法维护成本极高,不建议使用,除非你的App只针对特定几个国家。
内容的提问来源于stack exchange,提问作者Usman Khan




