iprateekk
iprateekk

Reputation: 616

Flutter: How do I listen to permissions real time

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.

Upvotes: 14

Views: 17750

Answers (4)

MohKoma
MohKoma

Reputation: 1452

You can also use the geolocator simply like this:

import 'package:geolocator/geolocator.dart';

StreamSubscription<ServiceStatus> serviceStatusStream = Geolocator.getServiceStatusStream().listen(
    (ServiceStatus status) {
        print(status);
    });

Upvotes: -1

Ben Butterworth
Ben Butterworth

Reputation: 28512

If you use flutter_hooks, you can do:

class ExampleWidget extends HookWidget {
  ...
  @override
  Widget build(BuildContext context) {
    final appLifecycleState = useAppLifecycleState();
    useEffect(() {
      checkPermissions();
    }, [appLifecycleState]);

    // Build your widget as normal
    return ...
  }
}

checkPermissions(); is a function I wrote to actually check permissions, depending on the library. For location, they have it documented in Usage.

Thanks to Flutter hooks, the impact on the existing class is very small.

Upvotes: 2

CopsOnRoad
CopsOnRoad

Reputation: 267534

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();
}

Upvotes: 3

Andrew Stevenson
Andrew Stevenson

Reputation: 658

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

Upvotes: 36

Related Questions