Before 2022/Android

USIM 관리 클래스 총정리(유심 체크, 번호 가져오기, 번호 포맷 통일)

Eljoe 2019. 6. 17. 11:03

안드로이드 현재 단말기가 더블 유심일 경우 전화번호를 가져오는 메소드

 

안드로이드 현재 단말기가 더블 유심일 경우 전화번호를 가져오는 메소드

public void setPhoneNumSpinner() { // API LEVEL 22 이상에서 가능 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { // 단말기 정보를 가져오는 클래스 SubscriptionManager subscriptionMan..

gooners0304.tistory.com

와 같은 글을 예전에 업로드한 적이 있었다.

 

하지만, 코드를 작성하던 중 아래와 같은 문제가 있었고 이 글은 그 모든 상황에 대비한 유틸 클래스에 대한 내용이다.

 

1. 통신사마다 전화번호 포맷이 동일하지않다.

-> google의 libphonenumber 라이브러리를 이용하여 포맷 통일하였음.

 

2. 특정 장치에서 유심 체크 시 문제 발생

-> 유심 상태에 대한 모든 예외상황을 두어 NPE를 패스하였다.

 

총정리한 USIMUtil 클래스 내용은 아래와 같다.

 

Manifest

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

전화번호 포맷 통일을 위해 해당 라이브러리를 implementation한다.

implementation 'com.googlecode.libphonenumber:libphonenumber:8.2.0'

유심 관리 클래스(코틀린 object 클래스 적용)

object UsimUtil {
    private const val TAG = "UsimUtil"

    // 유심 상태 체크 메소드
    fun USimCheck(context: Context): Boolean {
        val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        return when (telephonyManager.simState) {
            TelephonyManager.SIM_STATE_UNKNOWN, // 유심 상태를 알 수 없는 경우
            TelephonyManager.SIM_STATE_ABSENT, // 유심이 없는 경우
            TelephonyManager.SIM_STATE_PERM_DISABLED, // 유심이 존재하지만, 사용중지 상태인 경우
            TelephonyManager.SIM_STATE_CARD_IO_ERROR, // 유심이 존재하지만, 오류 상태인 경우
            TelephonyManager.SIM_STATE_CARD_RESTRICTED // 유심이 존재하지만 통신사 제한으로 사용 불가 상태인 경우
            -> {
                Toast.makeText(context, "해당 단말기의 유심이 존재하지 않거나, 오류가 있습니다.", Toast.LENGTH_SHORT).show()
                false
            }
            else -> {
                true
            }
        }
    }

    // 단말기 전화번호 포맷 통일 메소드
    private fun toNationalFormat(phoneNumber: String): String {
        val phoneNumberUtil = PhoneNumberUtil.getInstance()
        // 단말기의 해당 국가 코드를 가져온다.
        val locale = Locale.getDefault().country
        val toNationalNum = phoneNumberUtil.parse(phoneNumber, locale)
        return phoneNumberUtil.format(toNationalNum, PhoneNumberUtil.PhoneNumberFormat.NATIONAL).replace("-", "")
    }

    // 단말기의 전화번호를 가져오는 메소드
    @SuppressLint("HardwareIds")
    @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
    fun getPhoneNumber(context: Context): ArrayList {
        val phoneNumberArr = ArrayList()
        val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

        // 22 레벨부터는 더블 유심 지원 제공
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            val subscriptionManager =
                context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
            val subInfoList = subscriptionManager.activeSubscriptionInfoList
            for (subInfo in subInfoList) {
                Log.d(TAG, subInfo.number)
                if (!TextUtils.isEmpty(subInfo.number)) {
                    phoneNumberArr.add(toNationalFormat(subInfo.number))
                } else {
                    if (!TextUtils.isEmpty(telephonyManager.line1Number)) {
                      Log.d(TAG, telephonyManager.line1Number)
                      phoneNumberArr.add(toNationalFormat(telephonyManager.line1Number))
                      break
            	    }
                }
            }
        } else {
            if (telephonyManager.line1Number) {
                Log.d(TAG, telephonyManager.line1Number)
                phoneNumberArr.add(toNationalFormat(telephonyManager.line1Number))
            }
        }
        return phoneNumberArr
    }
    
    // 단말기 전화번호 정규식 변환
    fun hyphenFormat(number: String): String {
    	return number.replaceFirst("(^[0-9]{3})([0-9]{3,4})([0-9]{4})$".toRegex(), "$1-$2-$3")
    }
}

 

2020.08.11 수정사항

minSdkVersion가 23 이상인 경우 아래와 같이 간결하게 작성 가능

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import androidx.core.content.ContextCompat
import kotlin.collections.ArrayList

class DeviceNumberUtil(private val context: Context) {
    fun enabledUSIM(): Boolean {
        val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        return when (telephonyManager.simState) {
            TelephonyManager.SIM_STATE_READY -> true
            else -> false
        }
    }

    fun getSubInfoList(): List<SubscriptionInfo>? =
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
            (context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager).activeSubscriptionInfoList
        else null

    fun getPhoneNumberList(subInfoList: List<SubscriptionInfo>?): ArrayList<String> {
        val phoneNumbers = ArrayList<String>()

        if (subInfoList != null)
            for (subInfo in subInfoList) {
                phoneNumbers.add(subInfo.number)
            }

        return phoneNumbers
    }
}
class TestActivity : Activity(){
    private val deviceNumberUtil by lazy { DeviceNumberUtil(this) }
  	
    override fun onCreate(savedInstanceState: Bundle?) {
        ....
        // List<String>
        val phoneNumbers = deviceNumberUtil.getPhoneNumberList(phoneNumberUtil.getSubInfoList()).map { it.toNationalPhoneNumber() }
        
        if(phoneNumbers.size > 0) ...
    }
  
    fun String.toNationalPhoneNumber(): String {
        val phoneNumberUtil = PhoneNumberUtil.getInstance()
        val locale = Locale.getDefault().country
        val toNationalNum = phoneNumberUtil.parse(this, locale)
        return phoneNumberUtil.format(toNationalNum, PhoneNumberUtil.PhoneNumberFormat.NATIONAL)
    }
}