はじめに
Android 10から、端末からIMEIなどのSIM情報を取得するためには、「READ_PRIVILEGED_PHONE_STATE」という権限をAndroidManifest.xmlに追加する必要が出てきました。
Android 10 以降で IMEI とシリアル番号の両方を含む再設定不可能なデバイス ID にアクセスするには、アプリに READ_PRIVILEGED_PHONE_STATE 特権が必要です。
注意: Google Play ストアからインストールされたサードパーティ製アプリでは特権を宣言できません。
Privacy changes in Android 10 | Android デベロッパー | Android Developersより引用
追加するにあたって、以下のようにtools:ignore="ProtectedPermissions"
を追加することで、Android Studioから警告されることなく追加できます。(tools:ignore="ProtectedPermissions"
を追加しなくても一応ビルドはできます)
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
しかし、サードパーティ製アプリ(Google Playに公開されているアプリ)では宣言していても、特権を利用することはできません。該当メソッド呼び出し時にSecurityExceptionがスローされます。
上記の宣言に加えて、主に以下の対応が必要になります。
- プリインアプリ化する
- 「READ_PRIVILEGED_PHONE_STATE」をホワイトリストに追加する
プリインアプリ化する
「READ_PRIVILEGED_PHONE_STATE」を有効にするには、まずアプリをプリインアプリ化する必要があります。
プリインアプリとは、主に/system/app
や/system/priv-app
配下にあるアプリのことです。出荷時にあらかじめインストールされているアプリのことですね。
その中でも、/system/priv-app
配下にある、「システム権限を必要とする特権アプリ」である必要があります。
「READ_PRIVILEGED_PHONE_STATE」をホワイトリストに追加する
「READ_PRIVILEGED_PHONE_STATE」をAndroidManifest.xmlに追加し、プリインアプリ化したのち、さらに以下のような感じで権限をホワイトリストに追加する必要があります。
<permissions>
<privapp-permissions package="アプリのパッケージ名">
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
</privapp-permissions>
</permissions>
この辺りはおそらく手動で追加するものではなく、端末によっても格納先が異なると思われるので、あくまで参考程度にしてください。当然ながら、追加するには端末をroot化しないとできません。
注意
- プリインアプリがショートカットアプリ(起動するとGoogle Playのアプリページに飛ばすだけのもの)の場合、ショートカットアプリに対しても「READ_PRIVILEGED_PHONE_STATE」を宣言しないと無効になってしまうので注意!
- プリインアプリ更新時、APKファイルの格納先が移動されるようですが、どうやら仕様のようです。
- アプリ更新時にAndroidManifestがまるまる上書きされるものかと思っていたのですが、まるまる上書きはされず、以前に宣言した内容は残るらしいです。AndroidManifestの仕組みについて勉強しておかないとまずいと実感しました。
- 複数のマニフェスト ファイルをマージする | Android デベロッパー | Android Developersの内容を理解すると良いのかもしれないと感じました。(まだちゃんと読めてませんが)
コマンドメモ
この対応を行うにあたって使用したコマンドを下記にまとめます。
対象のアプリ(APKファイル)が端末内のどこにあるのかを調べる
adb shell pm list packages -f | grep -i "アプリのパッケージ名"
プリインアプリの上書き(root権限必須)
adb root
adb remount
adb push "APKファイルのパス" /system/app/
adb shell chmod 644 /system/app/"APKファイル名"
adb reboot
端末のシャットダウン(再起動を繰り返すようになってしまった場合に使用)
adb shell reboot -p
ホワイトリストを端末内にプッシュ
adb push "ホワイトリストのパス" /etc/permissions/