3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

カメラ機能においてのpermission_handlerを理解する

Posted at

スクリーンショット 2024-06-03 20.58.32(2).png

久しぶりの投稿です。
色々あって疲れていますが、なんとか余裕ができたので記事を書いていきます。なぜなら温泉に入って元気いっぱいだったからです🙌

やりたいこと

  • カメラ権限を許可するかどうかによって画面出し分けをしたい
  • 初期状態はローディング画面を表示させておきたい

必要なセットアップ

  • flutter_hooks・・・カメラ権限周りの状態管理
  • permission_handler・・・カメラ権限に必要なPackages
 dependencies:
  flutter_hooks: ^0.20.5
  permission_handler: ^11.3.1

iOSのセットアップ

ios/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)',
	
        ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
        'PERMISSION_LOCATION=1',
	
	## dart: PermissionGroup.microphone
        'PERMISSION_MICROPHONE=1',
	
	## dart: PermissionGroup.camera
        'PERMISSION_CAMERA=1'
	
	## dart: PermissionGroup.photos
        'PERMISSION_PHOTOS=1',
      ]
    end
  end
end
ios/Runner/Info.plist
<key>NSCameraUsageDescription</key>
<string>camera</string>

Androidのセットアップ

gradle.properties
android.useAndroidX=true
android.enableJetifier=true
android/app/build.gradle
android {
  compileSdkVersion 33
  ...
}
android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />

実装までの道のり

AppLifecycleListenerを定義

こちらは株式会社ゆめみで作成しているflutter-mobile-project-templateから引用しました。
詳しくはこちらを閲覧いただけると幸いです。

import 'dart:ui';

import 'package:flutter/material.dart';

/// A widget that listens to the lifecycle of the app.
/// Surround the widget you want to listen to with [CustomAppLifecycleListener].
class CustomAppLifecycleListener extends StatefulWidget {
  const CustomAppLifecycleListener({
    required Widget child,
    VoidCallback? onResume,
    VoidCallback? onInactive,
    VoidCallback? onHide,
    VoidCallback? onShow,
    VoidCallback? onPause,
    VoidCallback? onRestart,
    VoidCallback? onDetach,
    Future<AppExitResponse> Function()? onExitRequested,
    void Function(AppLifecycleState state)? onStateChange,
    super.key,
  })  : _child = child,
        _onResume = onResume,
        _onInactive = onInactive,
        _onHide = onHide,
        _onShow = onShow,
        _onPause = onPause,
        _onRestart = onRestart,
        _onDetach = onDetach,
        _onExitRequested = onExitRequested,
        _onStateChange = onStateChange;

  final Widget _child;
  final VoidCallback? _onResume;
  final VoidCallback? _onInactive;
  final VoidCallback? _onHide;
  final VoidCallback? _onShow;
  final VoidCallback? _onPause;
  final VoidCallback? _onRestart;
  final VoidCallback? _onDetach;
  final Future<AppExitResponse> Function()? _onExitRequested;
  final void Function(AppLifecycleState state)? _onStateChange;

  @override
  State<CustomAppLifecycleListener> createState() =>
      _CustomAppLifecycleListenerState();
}

class _CustomAppLifecycleListenerState
    extends State<CustomAppLifecycleListener> {
  late final AppLifecycleListener _appLifecycleListener;

  @override
  void initState() {
    _appLifecycleListener = AppLifecycleListener(
      onResume: widget._onResume,
      onInactive: widget._onInactive,
      onHide: widget._onHide,
      onShow: widget._onShow,
      onPause: widget._onPause,
      onRestart: widget._onRestart,
      onDetach: widget._onDetach,
      onExitRequested: widget._onExitRequested,
      onStateChange: widget._onStateChange,
    );
    super.initState();
  }

  @override
  void dispose() {
    _appLifecycleListener.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return widget._child;
  }
}

実装

import 'package:cores_core/util.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:permission_handler/permission_handler.dart';

class CameraPermissionScreen extends HookWidget {
  const CameraPermissionScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final isInitialized = useState(false);
    final isCameraPermissionGranted = useState(false);

    useEffect(
      () {
        WidgetsBinding.instance.addPostFrameCallback((_) async {
          final currentPermissionStatus = await Permission.camera.status;
          if (currentPermissionStatus.isGranted) {
            isCameraPermissionGranted.value = true;
            isInitialized.value = true;
            return;
          }

          final newPermissionStatus = await Permission.camera.request();
          isCameraPermissionGranted.value = newPermissionStatus.isGranted;
          isInitialized.value = true;
        });
        return;
      },
      [],
    );

    return CustomAppLifecycleListener(
      onResume: () async {
        if (!isInitialized.value) {
          // Note: カメラ使用権限の初回チェックが完了していない場合は何もしない
          return;
        }

        final newPermissionStatus = await Permission.camera.status;
        isCameraPermissionGranted.value = newPermissionStatus.isGranted;
      },
      child: Scaffold(
        body: isInitialized.value
            ? isCameraPermissionGranted.value
                ? Text('カメラ権限オン')
                : Text('カメラ権限オフ')
            : Text('初期状態'),
      ),
    );
  }
}

最後に

少しでもお役に立てれば嬉しいです🙌

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?