[Android]sim内の情報取得

Android端末のSIMカード内の情報にアクセスする方法をまとめておきます。

※追記2020年2月
どうやらAndroid10(API29)からREAD_PRIVILEGED_PHONE_STATEのパーミッションも必要らしい。

Android 10で、端末からIMEIなどのSIM情報を取得する方法
https://qiita.com/hiesiea/items/6a2deb479958a3b44707

詳細は、別途調査します。。。
以下は、それ以前の情報です。

必要パーミッション

READ_PHONE_STATE

確かAndroid M(6.0、API23)から必要になったはず。

ACCESS_NETWORK_STATE

simState(SIM状態)を取得するのに必要だった。
これは、エラーで怒られてから気づいた。

java.lang.SecurityException: ConnectivityService: Neither user 10214 nor current process has android.permission.ACCESS_NETWORK_STATE.

パーミッション許可の実装例

Kotlinで、targetSDKVersion 24以上を想定
今回のケースでは、READ_PHONE_STATEのみ。ACCESS_NETWORK_STATEはManifestに追加するのみでOK

TelephonyManagerの公式リファレンスにいろいろ書いてある。

AndroidManifest.xmlに以下を追加

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

Ktファイル内に以下のように実装

    private val PERMISSIONS_REQUEST_CODE = 100

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Logger.debug(javaClass.simpleName, "onCreate")

        if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
            // 許可済みの処理
            getDisplay()
        } else {
            // 許可されていないので許可ダイアログを表示する
            requestPermissions(arrayOf(Manifest.permission.READ_PHONE_STATE), PERMISSIONS_REQUEST_CODE)
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        when (requestCode) {
            PERMISSIONS_REQUEST_CODE -> {
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //許可された場合の処理
                    getDisplay()
                } else {
                    //拒否された場合の処理
                    })
                }
            }
        }
    }

TelephonyManagerのよく使いそうなgetメソッド

メソッド名 情報
getLine1Number 電話番号
getDeviceId デバイスID
getSimCountryIso SIMの国コード
getSimOperator MCC+MNC (mobile country code + mobile network code)
getSimOperatorName サービスプロバイダの名前
getSimSerialNumber SIMのシリアル番号
getSimState SIMの状態(通信可能か、PINロックされているかなど)
getVoiceMailNumber ボイスメールナンバー

もっといろいろとgetメソッドがある。getはあるけどsetはない。

例:電話番号を取得する場合は、以下のようにする

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
String line1Number = telephonyManager.getLine1Number();

なお、マニフェストにandroid.permission.READ_PHONE_STATE パーミッションの許可を記載する必要があります。

AndroidManifest.xml

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

取得できる情報の意味について

名称説明格納先
UDIDデバイス識別子
(Unique Device IDentifier)
デバイスffc1ded6f4570d557ad6
5f986684fc10c7f8d51f
シリアル番号シリアル番号デバイス12345ABCDEF
Wi-Fiアドレス無線LANデバイスのMACアドレスデバイス00:12:08:23:7D:A2
ICCID携帯電話に付与される番号SIMカード1234 5678 1234 5678 123
IMEI携帯電話に付与される番号デバイス12 123456 123456 0
IMSI携帯電話ユーザーに付与される番号SIMカード12 123456 123456 0
ECIDデバイス識別に使われる16桁数値(16進)
Exclusive Chip Identification
デバイス9999902578999

※例のうち、UDIDの値だけ表記上の理由により途中で改行入れています

ICCIDの取得方法について(リンクのコピペでないと見れない?)

日本Androidの会 › ICCIDの取得方法について

ICCIDは,皆様ご指摘のとおり,SIM固有の番号です。
IMSはI (International Mobile Subscriber Identity)であり,ドコモなどの携帯事業者がSIMに割り当てた識別コードです。
したがってICCIDがIMSIを特定できれば,SIMを特定できます。

携帯電話の通信では,IMSIが電話番号の代わりをします。
SIMがないと,電話番号がなくなることになるため,通信できなくなります。

それ以外の識別コードとして,IMEIがあります。
IMEI(International Mobile Equipment Identifier)は,国際移動体装置識別番号(端末識別番号)であり端末に割り当てられた番号です。
これはSIMに割り当てられた番号ではないので,SIMがなくても取得できます。
余談ですが,欧州の規格であるGSMは,SIMがなくても警察などの緊急呼ができるようになっています。
SIMがない場合,IMSIがない(つまり電話番号を持っていない)ので,本来,通常通信できないのですが,緊急呼の場合は,IMSIがなければIMEIを使用することになっています。

ICCIDやIMSIではSIMの識別ができ,IMEIを使用すると端末の識別ができます。

おまけ
android.telephony.TelephonyManagerクラスに,getSimSerialNumber()があります。
実機を持っていないので,これでICCIDの取得が可能であるかは確認しておりませんが,エミュレータでは使用できました。
使用するときには,READ_PHONE_STATEパーミッションが必要です。

同様に,getDeviceId()でIMEIを取得できます。

コメント

タイトルとURLをコピーしました