Android - アプリの権限を確認(Permission check)

Appがどのような権限を持っているかどうかを確認する方法を紹介します。

  • 自分のアプリがどのような権限を持っていることを確認
  • 他のアプリがどのようなパーミッションを持っていることを確認

Sample App

Sample Appを作成し、このアプリの権限を確認するためのコードを実装することです。

次のようにSample appのManifestに二つのパーミッションを要求しました。

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

そしてアプリは INTERNETパーミッションは持っており、READ_EXTERNAL_STORAGEパーミッションは持っていない状態です。

Context.checkSelfPermission()で許可を確認

checkSelfPermission()は引数としてpermisison名前を受け取ります。

public abstract int checkSelfPermission(@NonNull String permission);

ContextのAppが引数として渡されたパーミッションを持っている場合、 PackageManager.PERMISSION_GRANTEDを返します。 そうでなければ PackageManager.PERMISSION_DENIEDを返します。つまり、このAPIは、自分のアプリのパーミッションの状態のみを確認することができます。

PackageManager.PERMISSION_GRANTED = 0;
PackageManager.PERMISSION_DENIED = -1;

Activityから次のように使用することができます。

if (checkSelfPermission(Manifest.permission.INTERNET)
        == PackageManager.PERMISSION_GRANTED) {
    Log.d("Test", "Has INTERNET permission")
}

if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
        == PackageManager.PERMISSION_DENIED) {
    Log.d("Test", "Doesn't have READ_EXTERNAL_STORAGE permission")
}

Output:

11-14 22:27:15.014  5483  5483 D Test    : Has INTERNET permission
11-14 22:27:15.014  5483  5483 D Test    : Doesn't have READ_EXTERNAL_STORAGE permission

ActivityCompat API

Compatibility APIを使用したい場合は、 ActivityCompat.checkSelfPermission(Context, Permission)を使用してください。 戻り値は、上記と同じです。

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.INTERNET)
        == PackageManager.PERMISSION_GRANTED) {
    Log.d("Test", "Has INTERNET permission")
}

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
        == PackageManager.PERMISSION_DENIED) {
    Log.d("Test", "Doesn't have READ_EXTERNAL_STORAGE")
}

PackageManager.checkPermisison()でパーミッションチェック

checkPermisison()は、次のようにパーミッションの名前とパッケージ名を引数として受け取ります。

public abstract int checkPermission(@NonNull String permName, NonNull String packageName);

引数として受け取ったパッケージに引数として受け取ったパーミッションを持っていることを確認し、その結果を返します。 つまり、このAPIは、他のパッケージのパーミッションの状態を確認することができます。

次のようにAppで使用することができます。

if (packageManager.checkPermission(Manifest.permission.INTERNET, packageName)
        == PackageManager.PERMISSION_GRANTED) {
    Log.d("Test", "Has INTERNET permission")
}
if (packageManager.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, packageName)
        == PackageManager.PERMISSION_DENIED) {
    Log.d("Test", "Doesn't have READ_EXTERNAL_STORAGE permission")
}

Output:

11-14 22:30:54.999  6407  6407 D Test    : Has INTERNET permission
11-14 22:30:55.000  6407  6407 D Test    : Doesn't have READ_EXTERNAL_STORAGE permission

他のパッケージのパーミッションを確認

次のように他のアプリが特定のパーミッションを持っているかどうかを確認することができます。次の例では、YoutubeがNFCパーミッションを持っていることを確認する例を示します。

if (packageManager.checkPermission(Manifest.permission.NFC,
        "com.google.android.youtube") == PackageManager.PERMISSION_DENIED) {
    Log.d("Test", "Youtube has NFC permission")
}

checkSelfPermission()とcheckPermisison()の違い

アンドロイドの権限は大幅にPackageManagerのPermissionとAppOpsの権限に分けることができます。 PackageManagerのPermissionはManifestに宣言するパーミッションで、ユーザーに権限を要求し、受けるパーミッションを指します。 AppOpsはAppliction Operationの意味で、Appの動作を制限または許可するなどの権限を設定することを意味します。

Context.checkSelfPermission()はAppOpsの権限とPackageManagerのPermissionをすべて確認して戻します。 つまり、PackageManagerのPermissionを持っていてもAppOpsから制限された場合 PERMISSION_DENIEDが返されることがあります。

一方、 PackageManager.checkPermisison()はAppがPackageManagerのPermissionを持っているかどうかだけを確認します。 AppOpsから許可された制限されたがわかりません。

adb shellでパーミッションの状態を確認する方法

Settingsアプリでマイアプリの情報でパーミッションの状態を確認することができます。

しかし、 adb shellを使用すると、開発中より簡単にパーミッションの状態を確認することができます。

次のコマンドを入力すると、端末にパッケージ情報が出力されます。

$ adb shell dumpsys package [package name]

たとえば、次のようにyoutubeのパッケージ情報を出力することができます。そして、その情報からパーミッションの状態を確認することができます。

$ adb shell dumpsys package com.google.android.youtube

Packages:
  Package [com.google.android.youtube] (79c836a):
    userId=10121
    pkg=Package{baa705b com.google.android.youtube}
    declared permissions:
      com.google.android.youtube.permission.C2D_MESSAGE: prot=signature, INSTALLED
    requested permissions:
      android.permission.INTERNET
      android.permission.ACCESS_NETWORK_STATE
      android.permission.ACCESS_WIFI_STATE
      android.permission.WRITE_EXTERNAL_STORAGE: restricted=true
      ....
    install permissions:
      com.google.android.c2dm.permission.RECEIVE: granted=true
      android.permission.USE_CREDENTIALS: granted=true
      com.google.android.providers.gsf.permission.READ_GSERVICES: granted=true
      ....
    User 0: ceDataInode=122890 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=1 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.ACCESS_FINE_LOCATION: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
        android.permission.READ_EXTERNAL_STORAGE: granted=false, flags=[ REVOKE_WHEN_REQUESTED|USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED|RESTRICTION_UPGRADE_EXEMPT]
        android.permission.ACCESS_COARSE_LOCATION: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
        ....

それぞれの項目の意味は次のとおりです。

  • declared permissions:アプリから直接定義パーミッションを意味します
  • requested permissions:アプリで要求しているパーミッションを意味します。 (Manifestからuses-permissionで宣言したパーミッション
  • install permissions:アプリが持っているパーミッションです。 install permissionはインストール時に付与されるパーミッションの種類を意味します
  • runtime permissions:アプリが持っているパーミッションです。 rumtime permissionは、インストールされる際に付与されず、アプリがユーザーに権限を要請して与えられるパーミッションを意味します

次のように grepを利用して、granted状態を簡単に確認することができます。

$ adb shell dumpsys package com.google.android.youtube | grep READ_CONTACTS
      android.permission.READ_CONTACTS
        android.permission.READ_CONTACTS: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
codechachaCopyright ©2019 codechacha