権限と実行時リクエスト
ActivityResultContractsを使用して危険な権限を実行時に宣言・要求し、理由説明ダイアログを表示して、恒久的な拒否にも対応します。
「権限と実行時リクエスト」はCoddyKit上の無料Android Academyレッスンです。 これはレッスン7/7です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAndroid Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Android Academyコースには全7レッスンが含まれています。
Androidの権限の概要
Androidアプリでは、必要なデバイス機能を宣言する必要があります。権限はユーザーのプライバシーを保護します。
- 通常権限 — リスクが低く、自動的に許可されます(INTERNET、VIBRATE)
- 危険な権限 — 機密データにアクセスするため、実行時にリクエストする必要があります(CAMERA、LOCATION、READ_CONTACTS)
- 署名権限 — 同じ証明書で署名されたアプリだけが使用できます
マニフェストでの宣言
すべての権限は、まず AndroidManifest.xml で宣言する必要があります。
<!-- AndroidManifest.xml -->
<manifest ...>
<!-- Normal: granted automatically -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- Dangerous: must request at runtime -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application ...>
...
</application>
</manifest>権限が許可されているかの確認
危険な機能を使用する前に、権限がすでに許可されているか必ず確認してください。
import androidx.core.content.ContextCompat
import android.content.pm.PackageManager
fun isCameraPermissionGranted(): Boolean {
return ContextCompat.checkSelfPermission(
this, // Context
android.Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
}ActivityResultLauncher による権限リクエスト
ActivityResultContracts.RequestPermission() を使用します。これは非推奨の onRequestPermissionsResult を使わない最新の方法です。
class CameraActivity : AppCompatActivity() {
private val requestCameraPermission = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
openCamera()
} else {
showPermissionDeniedMessage()
}
}
fun onTakePhotoClick(view: View) {
if (isCameraPermissionGranted()) {
openCamera()
} else {
requestCameraPermission.launch(android.Manifest.permission.CAMERA)
}
}
}複数の権限を同時にリクエストする
RequestMultiplePermissions を使用して、複数の権限をリクエストします。
private val requestMultiple = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val cameraGranted = permissions[android.Manifest.permission.CAMERA] ?: false
val locationGranted = permissions[android.Manifest.permission.ACCESS_FINE_LOCATION] ?: false
if (cameraGranted && locationGranted) {
startFeature()
} else {
showWhichPermissionsDenied(cameraGranted, locationGranted)
}
}
fun requestPermissions() {
requestMultiple.launch(arrayOf(
android.Manifest.permission.CAMERA,
android.Manifest.permission.ACCESS_FINE_LOCATION
))
}理由の説明:説明が必要なタイミング
shouldShowRequestPermissionRationale() は、ユーザーが以前に権限を拒否している場合に true を返します。もう一度リクエストする前に、理由を説明してください。
fun requestCameraWithRationale() {
when {
isCameraPermissionGranted() -> {
openCamera()
}
shouldShowRequestPermissionRationale(android.Manifest.permission.CAMERA) -> {
// Explain why we need it, then request
AlertDialog.Builder(this)
.setTitle("Camera needed")
.setMessage("We use the camera to take profile photos.")
.setPositiveButton("OK") { _, _ ->
requestCameraPermission.launch(android.Manifest.permission.CAMERA)
}
.show()
}
else -> {
requestCameraPermission.launch(android.Manifest.permission.CAMERA)
}
}
}恒久的に拒否された場合 — 設定画面へ誘導する
ユーザーが「今後表示しない」をタップすると、shouldShowRequestPermissionRationale は false を返し、再度リクエストできなくなります。アプリの設定画面へ誘導してください。
fun openAppSettings() {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", packageName, null)
}
startActivity(intent)
}位置情報の権限
位置情報には2つの精度レベルがあります。用途に合ったものを選択してください。
ACCESS_COARSE_LOCATION— 都市レベルの精度(Wi-Fi/携帯電話基地局)ACCESS_FINE_LOCATION— GPSレベルの精度ACCESS_BACKGROUND_LOCATION— Android 10以降でバックグラウンドから位置情報にアクセスするために別途必要
カメラ権限の完全な例
確認 → 理由の説明 → リクエストを組み合わせた一連の処理です。
class PhotoActivity : AppCompatActivity() {
private val cameraLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) openCamera() else showDenied()
}
private fun handleCameraClick() {
val permission = android.Manifest.permission.CAMERA
when {
ContextCompat.checkSelfPermission(this, permission) ==
PackageManager.PERMISSION_GRANTED -> openCamera()
shouldShowRequestPermissionRationale(permission) ->
showRationaleDialog()
else -> cameraLauncher.launch(permission)
}
}
private fun showDenied() {
Snackbar.make(binding.root, "Camera permission required", Snackbar.LENGTH_LONG)
.setAction("Settings") { openAppSettings() }.show()
}
}権限に関するベストプラクティス
権限リクエストをスムーズに行うための主なルールです。
- 必要になったときだけ権限をリクエストする(アプリ起動時には行わない)
- 必要最小限の権限だけをリクエストする
- 拒否された場合も必ず適切に処理する
- 「今後表示しない」の後に繰り返しリクエストしない
- 拒否された後ではなく、システムダイアログを表示する前に理由を説明する
Android 13以降の細分化されたメディア権限
Android 13(API 33)以降では、READ_EXTERNAL_STORAGE が細分化された権限に分割されています。
READ_MEDIA_IMAGESREAD_MEDIA_VIDEOREAD_MEDIA_AUDIO
必ず Build.VERSION.SDK_INT を確認し、OSのバージョンに合った権限をリクエストしてください。
クイックチェック
危険な権限をリクエストする前に、理由を説明するダイアログを表示するのはいつですか?
まとめ:権限
ランタイム権限を正しく扱う方法:
AndroidManifest.xmlで宣言するContextCompat.checkSelfPermission()で確認するregisterForActivityResult(RequestPermission())を使ってリクエストするshouldShowRequestPermissionRationale()が true の場合は理由を説明する- 恒久的に拒否された場合は、ユーザーを設定画面へ誘導する
- ユーザーが必要とする前に権限をリクエストしない
次は、DataStore を使ってデータをローカルに保存します。
よくある質問
「権限と実行時リクエスト」レッスンは無料ですか?
はい。「権限と実行時リクエスト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Android Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Android Academyコースには全7レッスンが含まれています。
「権限と実行時リクエスト」で何を学びますか?
ActivityResultContractsを使用して危険な権限を実行時に宣言・要求し、理由説明ダイアログを表示して、恒久的な拒否にも対応します。 ブラウザで直接実行するハンズオンコードでAndroid Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Android Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAndroid Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン7/7です。
「権限と実行時リクエスト」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAndroid Academyレッスンでコードを書いて実行できますか?
はい。すべてのAndroid Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。