Flutter の permission_handler の学習

概要
Flutter でカメラを使った機能を開発するにあたり、その前提となる実行時の権限について学習する。
Android エンジニアなので Android については厚めに書いている一方、iOS については記述が薄め。
実行時の権限とは
Android
権限の種類
種類 | 解説 | 例 |
---|---|---|
インストール時の権限 | ユーザーのプライバシーや他のアプリのオペレーションへのリスクはほとんど無い。 | インターネット接続 |
実行時の権限 | プライバシーにアクセスする権限 | カメラ |
特別な権限 | プライバシーに関係しないが、システムに対して特別なアクセスを行う | アラーム、他のアプリの上に重ねて表示 |
インストール時の権限
インストールしたときに許可されたことになっている。Google Play でインストール前に確認することができる。
※ スクリーンショットは前々職で担当していたアプリ「CODE」
実行時の権限
実行時の権限をシステムにリクエストすると、このようなダイアログが表示される。
- ユーザが「アプリ使用時のみ」または「今回のみ」をクリックすれば権限を取得できる。
- 「今回のみ」で得た権限は一度アプリのプロセスが終了すると失効する。
iOS
Android のような権限の種類は無い。カメラなど、プライバシーにアクセスする場合は、システムに許可を求めて、表示されたダイアログでユーザが「許可」をクリックする必要がある。

permission_handler パッケージ
Flutter のクロスプラットフォームな実行時の権限を得るためのパッケージ。非公式なパッケージだが ChatGPT 情報では公式のものは無く、事実上のデファクトスタンダードとして扱われていそう。

実装方法
permission_handler パッケージを追加
flutter pub add permission_handler
Android
android/app/src/main/AndroidManifest.xml
ファイルにカメラ権限を追加
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 略 -->
<uses-permission android:name="android.permission.CAMERA"/>
</manifest>
実行時の権限を取得する Dart コード
await Permission.camera
.onGrantedCallback(() {
// 権限取得できた、または、すでにしている。
})
.onDeniedCallback(() {
// 今回は拒否された
})
.onPermanentlyDeniedCallback(() {
// 永久に拒否されている
})
.request();
onRestrictedCallback, onLimitedCallback, onProvisionalCallback もあるが、今回は割愛
iOS
公式ドキュメントの Setup > iOS (click to expand) に従い設定する。
Info.plist
Podfile
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
# 追記
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
'PERMISSION_CAMERA=1',
]
end
end
end
app/ios
ディレクトリで pod install
コマンドを実行する。

各コールバックが呼ばれる条件
Android
onGrantedCallback
- 「アプリ使用時のみ」または「今回のみ」が選択されたときに呼ばれる。
- 一度、選択された場合は、次回以降、ダイアログ無しで、こちらのコールバックが呼ばれる。
onDenitedCallback
- 初めて「許可しない」が選択されたときに呼ばれる。
onPermanentlyDeniedCallback
- 「許可しない」が2度が選択されたときに呼ばれる。
- 3回目以降は「許可しますか?」ダイアログは表示されず、すぐにこちらのコールバックが呼ばれる。
iOS
onGrantedCallback
- 「許可」が選択されたときに呼ばれる。
- 一度、選択された場合は、次回以降、ダイアログ無しで、こちらのコールバックが呼ばれる。
onPermanentlyDeniedCallback
- 「許可しない」が選択されたときに呼ばれる。
- 一度許可した後、本体設定で許可を OFF にしても呼ばれる。
- 本体設定 - アプリ設定の「カメラ」項目は1度「カメラへのアクセスを求めています」ダイアログを出さないと表示されない。

onPermanentlyDeniedCallback が呼ばれてしまうときの対処方法
ユーザに本体設定のアプリ情報画面で権限を付与することを案内した上で、その画面を呼び出す。
Flutter では permission_handler パッケージの openAppSettings()
メソッドで呼び出すことができる。

参考・Android ネイティブの場合の実装方法
結果受け取り可能な Launcher を作成する。
class SomeActivity : AppCompatActivity() {
val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// 権限取得できた、または、すでにしている。
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.CAMERA
)
) {
// 永久に拒否されている
} else {
// 今回は拒否された
}
}
}
権限要求
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
アプリ設定画面を開く
// アプリ設定画面を開く
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:$packageName")
startActivity(intent)