AndroidManifest Permissions は、AndroidManifest.xml ファイル内の権限宣言であり、アプリケーションがアクセスできるシステムリソースとデータを決定します。Androidでは、対応するAPIを使用する前に、マニフェストで各権限を宣言する必要があります。カメラや位置情報からSMS送信や連絡先へのアクセスまで、すべての権限が対象です。Android Developer Documentation によると、各権限は4つの保護レベルのいずれかに分類されます:normal、dangerous、signature、specialです。
重要なポイント
AndroidManifest Permissions は、保護されたデータやシステム機能へのアプリケーションのアクセスを制御するAndroidのセキュリティメカニズムです。すべてのアプリケーションは、
Androidの権限モデルはいくつかの進化段階を経てきました。Android 6.0(API 23)より前は、すべての権限がインストール時に付与されていました。ユーザーは完全なリストを確認し、アプリケーションのインストールに同意するか拒否していました。Android 6.0以降、dangerousレベルの権限は実行時に(Runtime Permissions)要求されるようになり、ユーザーにより柔軟な制御を提供しています。
権限は4つの保護レベルに分かれています:normal(インストール時に自動付与)、dangerous(実行時の要求が必要)、signature(同じ証明書で署名されたアプリケーションのみ利用可能)、special(設定で個別に有効化が必要)。各レベルには独自の付与と取り消しのメカニズムがあります。
Google I/O 2024 によると、Android 15ではより細かい権限が導入される予定です。ユーザーはメディアライブラリ全体ではなく、特定のファイルのみへのアクセスを許可できるようになります。これは、デフォルトで提供されるデータ量を最小限に抑えるというAndroidのトレンドを継続するものです。
すべての権限が実行時に要求されるiOSとは異なり、Androidは権限をインストール時と実行時に分割しています。normalレベルはユーザーに通知することなくインストール時に自動的に付与されます。dangerousレベルはiOSと同様に明示的なダイアログが必要です。
もう1つの違い:Androidでは、権限は権限グループにグループ化されています。ユーザーがカメラへのアクセスに同意すると、アプリケーションは自動的にマイクへのアクセスも取得します。これらは同じMICROPHONEグループに属しているためです。iOSでは、各権限はグループに関係なく個別に要求されます。
| Androidバージョン | 権限モデルの変更 |
|---|---|
| Android 1.0~5.x | すべての権限がインストール時に付与 |
| Android 6.0(API 23) | dangerousレベル向けRuntime Permissionsの導入 |
| Android 10(API 29) | Scoped Storage — ファイルシステムへのアクセス制限 |
| Android 11(API 30) | 自動リセット権限 — 未使用の権限がリセット |
| Android 14(API 34) | メディアアクセス(写真、動画、音声)の実行時権限 |
Androidは権限に対して4つの保護レベルを定義しており、それぞれに独自の付与ルールがあります。各レベルを詳しく見ていきましょう。
Normal権限は、ユーザーへの通知や要求なしにアプリケーションのインストール時に自動的に付与されます。これらはユーザーのプライバシーを脅かさない低リスクの機能をカバーします:INTERNET、ACCESS_NETWORK_STATE、VIBRATE、BLUETOOTH。ユーザーは同意ダイアログを表示されません。権限はインストール時に付与されたものと見なされます。
開発者はnormal権限のためにコード内で要求を処理する必要はありません。マニフェストで宣言するだけで十分です。ただし、Android 12+では、Google Playからインストールする際に、ユーザーはすべてのnormal権限を一覧表示する「権限」タブを表示し、透明性が向上しています。Statista(2024) によると、Google Playの90%以上のアプリケーションが最も一般的なnormal権限としてINTERNETを使用しています。
Dangerous権限は、プライバシーを侵害する可能性のあるデータや機能へのアクセスをカバーします:カメラ、マイク、位置情報、連絡先、SMS、電話、カレンダー、身体センサー。これらの権限には2段階のメカニズムが必要です:マニフェストでの宣言 + ActivityCompat.requestPermissions() による実行時の要求。
ユーザーはdangerous権限を拒否でき、アプリケーションはこのシナリオを適切に処理する必要があります。Android 11+では、ユーザーが2回拒否すると、以降の要求はシステムダイアログを表示せず、システムは自動的にDENIEDを返します。この場合、アプリケーションはユーザーを設定に誘導する必要があります。
signatureレベル — アプリケーションがシステムまたは権限を定義した別のアプリケーションと同じ証明書で署名されている場合、権限は自動的に付与されます。システムアプリやエンタープライズアプリで使用されます。例:BIND_ACCESSIBILITY_SERVICE — システムアプリのみ利用可能。
specialレベル(SYSTEM_ALERT_WINDOW、WRITE_SETTINGS、REQUEST_INSTALL_PACKAGES、MANAGE_EXTERNAL_STORAGE) — システム設定を通じてユーザーの明示的な操作が必要です。アプリケーションは Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION) を使用して設定ページを開くことができます。Google Playではspecial権限の使用が制限されており、公開時にフォームでの正当性の説明が必要です。
Android 6.0以降、すべてのdangerous権限は実行時に要求する必要があります。Kotlinでのruntime permissionsの完全なワークフローを見ていきましょう。
dangerous権限を必要とするAPIを呼び出す前に、常に ContextCompat.checkSelfPermission() で現在のステータスを確認してください。ステータスが PERMISSION_GRANTED の場合はAPIを呼び出せます。PERMISSION_DENIED の場合は、ActivityResultContract RequestPermission(AndroidX)または非推奨の requestPermissions() を使用して権限を要求する必要があります。
複数の権限を同時に要求するには、ActivityResultContracts.RequestMultiplePermissions を使用することを推奨します。Googleは、関連する権限(例:動画撮影用のカメラ+マイク)を1つのダイアログにグループ化し、ユーザーが要求の全体的なコンテキストを理解できるようにすることを推奨しています。
import android.Manifest
import android.content.pm.PackageManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
class CameraActivity : AppCompatActivity() {
private val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
openCamera()
} else {
explainWhyPermissionNeeded()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
checkCameraPermission()
}
private fun checkCameraPermission() {
when {
ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
shouldShowRequestPermissionRationale(
Manifest.permission.CAMERA
) -> {
showRationale()
}
else -> {
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
}
}
ユーザーが2回拒否すると、Androidは要求を「Never ask again」状態に移行します。この場合、shouldShowRequestPermissionRationale() は false を返し、システムダイアログは表示されません。アプリケーションは Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) を使用してユーザーをシステム設定に誘導する必要があります。
重要:最初の拒否の直後に設定を開くダイアログを表示しないでください。これは攻撃的な動作と見なされます。shouldShowRequestPermissionRationale() を使用して、説明を表示する必要があるかどうかを判断してください。Material Design Guidelines は、単なる「設定を開く」ボタンではなく、アクセスの価値を説明する画面を表示することを推奨しています。
private fun openAppSettings() {
Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null)
).also { intent ->
startActivity(intent)
}
}
private fun showPermissionSettings() {
AlertDialog.Builder(this)
.setTitle("カメラへのアクセス")
.setMessage("設定でカメラへのアクセスを許可、"
+ "プロフィール写真を撮影するため")
.setPositiveButton("設定を開く") { _, _ ->
openAppSettings()
}
.setNegativeButton("キャンセル", null)
.show()
}
AndroidManifest.xmlファイルには、アプリケーションが使用する各権限の
各権限は、android:name 属性を使用して完全な権限名を指定する個別の
たとえば、WRITE_EXTERNAL_STORAGE 権限は Android 10+(Scoped Storage)では不要なため、maxSdkVersion="28"(Android 9)を指定します。これにより、新しいバージョンでのユーザーからの不要な質問を防げます。Android Studio はLintを通じて推奨される maxSdkVersion について警告します。
<!-- AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Normal permissions (install-time) -->
<uses-permission
android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Dangerous permissions (runtime) -->
<uses-permission
android:name="android.permission.CAMERA" />
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Legacy storage permission limited to API 28 and below -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<application>
<!-- ... -->
</application>
</manifest>
すべてのハードウェア機能について required="false" を設定し、PackageManager.hasSystemFeature() でプログラム的に可用性を確認することをお勧めします。これにより、アプリケーションの対象ユーザーが広がります。唯一の例外は、その機能がアプリケーションの動作に不可欠な場合です(GPSなしのタクシー配車アプリは意味がありません)。
適切な権限管理はAndroidアプリケーションの品質における重要な側面です。主な推奨事項と典型的なエラーを見ていきましょう。
アプリケーションの動作に本当に必要な権限のみを要求してください。余分な権限はインストール率を低下させ、拒否数を増やします。Google Play Console は、権限セットが原因でインストールを拒否したユーザー数を表示します。AppBrain(2024) によると、10個以上のdangerous権限を持つアプリケーションはインストール数が35%少なくなっています。
定期的に権限リストを見直してください。特に、一部の権限がオプションになる新しいAndroidバージョンに移行する際は、未使用の権限を削除してください。たとえば、Android 13+のフォトピッカー(ActivityResultContracts.PickVisualMedia)では、dangerousな READ_MEDIA_IMAGES 権限なしでメディアライブラリにアクセスできます。
dangerous権限を要求する前に、その権限が必要な理由と提供する価値を説明する画面をユーザーに表示してください。Material Design は、アイコン、簡潔なテキスト、「続行」ボタンを備えたボトムシートまたはダイアログの使用を推奨しています。説明を表示することで、直接要求する場合と比較して同意率が20~30%向上します。
launch() を呼び出す前に shouldShowRequestPermissionRationale() を確認してください。true の場合は説明を表示します。false の場合は、権限が既に付与されているか、ユーザーが永続的に拒否しています(今後は確認しない)。後者の場合は、要求を繰り返す代わりに「設定を開く」ボタンを表示してください。
すべての可能なシナリオをテストしてください:権限の付与、拒否、永続的な拒否、設定での権限取り消し、権限のリセット(Android 11+の自動リセット)。各シナリオはクラッシュやデータ損失なしで処理される必要があります。Android Testing Guide は、テストを自動化するために TestPermission ライブラリの使用を推奨しています。
アプリケーションの実行中にユーザーが権限を取り消すシナリオ(アプリを最小化 → 設定 → 取り消し)には特に注意してください。アプリケーションに戻ったら、onResume() ですべての権限を再確認してください。権限ステータスのキャッシュに依存しないでください。ユーザーはいつでも変更できます。
よくある質問
はい。SDKがそのマニフェストに権限を含める場合、ビルド時にアプリケーションのマニフェストとマージされます。AndroidManifest.xml で tools:node="remove" を使用して、不要なSDK権限を削除できます。
権限なしでAPIを呼び出すと SecurityException が発生し、アプリケーションがクラッシュします。対応するAPIを使用する前に常に権限ステータスを確認し、拒否を適切に処理してください。
デバイスの設定:設定 → アプリ → [アプリ名] → 権限。すべての権限をリセットするには、adbコマンドを使用します:adb shell pm reset-permissions。
はい。FragmentやServiceで ActivityResultLauncher を使用して可能です。ただし、要求ダイアログには常にActivityのUIコンテキストが必要です。Serviceの場合は、要求Activityを開くIntentを含むNotificationを表示できます。
たとえば、WRITE_EXTERNAL_STORAGE は Android 10+(Scoped Storage)では不要です。android:maxSdkVersion="28" を指定することで、新しいバージョンでの権限宣言を除外し、互換性を向上させ、要求する権限リストを削減できます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。