Flutter: How do I listen to permissions real time

6,291

Solution 1

I'm in the same boat and have found that this works

You need to extend your class with WidgetsBindingObserver

class _AppState extends State<App> with WidgetsBindingObserver {
  PermissionStatus _status;
  ...
  ...

then add these methods to your class

@override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  // check permissions when app is resumed
  // this is when permissions are changed in app settings outside of app
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      PermissionHandler()
          .checkPermissionStatus(PermissionGroup.locationWhenInUse)
          .then(_updateStatus);
    }
  }

My full code is below, but I've not included the build widget to keep it brief

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(App());

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> with WidgetsBindingObserver {
  PermissionStatus _status;

  // check permissions
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    PermissionHandler() // Check location permission has been granted
        .checkPermissionStatus(PermissionGroup
            .locationWhenInUse) //check permission returns a Future
        .then(_updateStatus); // handling in callback to prevent blocking UI
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  // check permissions when app is resumed
  // this is when permissions are changed in app settings outside of app
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      PermissionHandler()
          .checkPermissionStatus(PermissionGroup.locationWhenInUse)
          .then(_updateStatus);
    }
  }

override
  Widget build(BuildContext context) {
    return MaterialApp(  
    ...
    ...
}

void _updateStatus(PermissionStatus status) {
    if (status != _status) {
      // check status has changed
      setState(() {
        _status = status; // update
      });
    } else {
      if (status != PermissionStatus.granted) {
        PermissionHandler().requestPermissions(
            [PermissionGroup.locationWhenInUse]).then(_onStatusRequested);
      }
      }
    }
  }

  void _askPermission() {
    PermissionHandler().requestPermissions(
        [PermissionGroup.locationWhenInUse]).then(_onStatusRequested);
  }

  void _onStatusRequested(Map<PermissionGroup, PermissionStatus> statuses) {
    final status = statuses[PermissionGroup.locationWhenInUse];
    if (status != PermissionStatus.granted) {
      // On iOS if "deny" is pressed, open App Settings
      PermissionHandler().openAppSettings();
    } else {
      _updateStatus(status);
    }
  }

I hope this helps

Solution 2

Null safe code:

permission_handler: ^8.0.0+2

The idea is to check for the permission in the app's lifecycle callback when the state is resumed. Here's the minimal code to get you going.

class _FooPageState extends State<FooPage> with WidgetsBindingObserver {
  final Permission _permission = Permission.location;
  bool _checkingPermission = false;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance!.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance!.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.resumed && !_checkingPermission) {
      _checkingPermission = true;
      _checkPermission(_permission).then((_) => _checkingPermission = false);
    }
  }

  Future<void> _checkPermission(Permission permission) async {
    final status = await permission.request();
    if (status == PermissionStatus.granted) {
      print('Permission granted');
    } else if (status == PermissionStatus.denied) {
      print('Permission denied. Show a dialog and again ask for the permission');
    } else if (status == PermissionStatus.permanentlyDenied) {
      print('Take the user to the settings page.');
    }
  }

  @override
  Widget build(BuildContext context) => Scaffold();
}
Share:
6,291
iprateekk
Author by

iprateekk

Updated on December 10, 2022

Comments

  • iprateekk
    iprateekk over 1 year

    I am working on an app in which I want to continuously listen to location and battery permissions.

    Sample scenario:

    1. The user opens the app
    2. Grants permission access
    3. Goes to settings and revokes the permissions
    4. Opens the app again
    5. The app displays a snackbar that informs the user that permission has been revoked.

    I am a beginner and I am using the flutter-permissions-handler and the piece of code below shows my usage.

        _listenForLocationPermission() {
        Future<PermissionStatus> status = PermissionHandler()
            .checkPermissionStatus(PermissionGroup.locationWhenInUse);
        status.then((PermissionStatus status) {
          setState(() {
            _permissionStatus = status;
            if (_permissionStatus != PermissionStatus.granted) {
              _renderOfflineSnackbar('Offline');
            }
          });
        });
      }
    

    Any advice on the above is appreciated.

  • iprateekk
    iprateekk over 4 years
    Many thanks for your answer. I will try this and report back.
  • Abiud Orina
    Abiud Orina almost 4 years
    Do you know how many days of headaches you have saved me??? Bless you!
  • Haidar
    Haidar over 2 years
    is there a way to check for the permanently denied without requesting the permission?
  • CopsOnRoad
    CopsOnRoad over 2 years
    @HaidarMehsen No, that's not possible.