You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动