10

I'm building my first Flutter application and I've run into a bit of an async issue.

When my application executes I'd like it to ask for permissions and wait until they are granted. My main() function looks like this:

import 'permission_manager.dart' as Perm_Manager;

void main() async
{
  //Ensure valid permissions
  Perm_Manager.Permission_Manager pm = Perm_Manager.Permission_Manager();
  var res = await pm.get_permissions();
  print(res);

  return runApp(MyApp());
} 

The Permission Manager class' get_permissions() function uses the Flutter Simple Permissions package to check and ask for permissions.

import 'package:simple_permissions/simple_permissions.dart';
import 'dart:io' as IO;
import 'dart:async';

class Permission_Manager {
  /* Get user permissions */

  Future<bool> get_permissions() async
  {
    //Android handler
    if (IO.Platform.isAndroid)
    {
        //Check for read permissions
        SimplePermissions.checkPermission(Permission.ReadExternalStorage).then((result)
        {
          //If granted
          if (result)
            return true;

          //Otherwise request them
          else
          {
            SimplePermissions.requestPermission(Permission.ReadExternalStorage)
            .then((result)
            {
              // Determine if they were granted
              if (result == PermissionStatus.authorized)
                return true;
              else
                IO.exit(0); //TODO - display a message
            });
          }
        });
    }

    else
      return true;
  }
}

When I run the application it does not wait for the function to complete as intended and prints the value of "res" before the Future is updated.

Launching lib\main.dart on Android SDK built for x86 in debug mode...
Built build\app\outputs\apk\debug\app-debug.apk.
I/SimplePermission(15066): Checking permission : android.permission.READ_EXTERNAL_STORAGE
I/flutter (15066): null
I/SimplePermission(15066): Requesting permission : android.permission.READ_EXTERNAL_STORAGE

The Future returns a value midway through the function! Does anyone know what I'm doing wrong?

2 Answers 2

15

To await something you have to call the await keyword on a future instead of .then

final result = await future;
// do something

instead of

future.then((result) {
  // do something
});

If you really want to use .then then you can await the generated future:

await future.then((result) {
  // do something
});

Just ensure that when using nested asynchronous calls that the async keyword is used on each:

await future.then((result) async{
    // do something
    await future.then((result_2) {
       // do something else
    });
});
Sign up to request clarification or add additional context in comments.

10 Comments

"await" is used in the main() function which calls the asynchronous function. Notwithstanding I was under the impression that "then" and "await" while syntactically different (with "then" running a function after completion) they operated the same way.
No they don't. You really have to use await
From the Dart documentation (dartlang.org/tutorials/language/futures): "To suspend execution until a future completes, use await in an async function (or use then())." But despite this I did use await in my main() function to no avail.
Once is not enough. you need more then just one await in your example
I don't think you can await the generated future. The generated future is local to the callback function run by then() and doing something like "await SimplePermissions.checkPermission(Permission.ReadExternalStorage).then((result) { ..." generates an error. It's true that you could return the generated future from the callback, but since the plugin doesn't return boolean values you'd need to rewrite most of the function in main()
|
-1

Got it working. The issue seems to be resolved using a Completer:

import 'package:simple_permissions/simple_permissions.dart';
import 'dart:io' as IO;
import 'dart:async';

class Permission_Manager {
  /* Get user permissions */

  final Completer c = new Completer();

  Future get_permissions() async
  {

    //Android handler
    if (IO.Platform.isAndroid)
    {
        //Check for read permissions
        SimplePermissions.checkPermission(Permission.ReadExternalStorage).then((result)
        {
          //If granted
          if (result)
          {
            c.complete(true);
          }
          //Otherwise request them
          else
          {
            SimplePermissions.requestPermission(Permission.ReadExternalStorage).then((result)
            {
              // Determine if they were granted
              if (result == PermissionStatus.authorized)
              {
                c.complete(true);
              }
              else
              {
                IO.exit(0); //TODO - display a message
              }
            });
          }
        });
    }

    else
    {
      c.complete(true);
    }

    return c.future;
  }

}

4 Comments

that makes your async flag on get_permissions useless.
The application requires read permissions for any functionality but the Simple Permissions plugin operates asynchronously. Specifically, when opening the application reads all files in the Downloads directory. This solution stops the application from reading the directory until permissions are granted. If there's a way to use the plugin synchronously that would be ideal, but I don't think it's possible.
I'm not saying the code doesn't work, but that the syntax is not the right one.
The docs for reference (pub.dartlang.org/packages/simple_permissions#-readme-tab-). Running the code without the async flag and returning a non-Future bool produces the same results as seen in the initial question (due to the plugin code running asynchronously). Is there another way to do it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.