comodoro
comodoro

Reputation: 1566

How to request permissions in a Flutter plugin?

I am trying to use a simple Flutter plugin (speech recognition wrapper) and have no idea how to request the appropriate permissions on Android 23 or newer. In the Dart part I have:

  Future requestPermissions() => 
  _channel.invokeMethod("speech.requestPermissions");

In the Android part:

  public class SpeechRecognitionPlugin implements MethodCallHandler, RecognitionListener,
    PluginRegistry.RequestPermissionResultListener {

Plugin registration:

  public static void registerWith(Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "speech_recognition");
    SpeechRecognitionPlugin speechRecognitionPlugin = new 
    SpeechRecognitionPlugin(registrar.activity(), channel);
    channel.setMethodCallHandler(speechRecognitionPlugin);
    registrar.addRequestPermissionResultListener(speechRecognitionPlugin);
  }

Method call:

else if (call.method.equals("speech.requestPermissions")) {
        Log.d(LOG_TAG, "speech.requestPermissions");
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
                Manifest.permission.RECORD_AUDIO)) {
            Toast.makeText(activity.getApplicationContext(), "This application needs the Record Audio permission for recognition to work", Toast.LENGTH_LONG).show();
        } else {
            Log.d(LOG_TAG, "Requesting permissions");
            ActivityCompat.requestPermissions(activity,
                    new String[]{Manifest.permission.RECORD_AUDIO},
                    1);
        }
        result.success(hasRecordAudioPermission());

Result callback:

@Override                                                                                            
public boolean onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
    boolean granted = false;
    switch (requestCode) {
        case 1: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                granted = true;
            }
            speechChannel.invokeMethod("speech.onPermission", granted);
            return true;
        }
    }
    return false;
}

From logcat I see that the "speech.requestPermissions" call happens, but standard Android system permission request is not shown, just this in the logcat may be related:

D/ViewRootImpl(21171): #1 mView = android.widget.LinearLayout{64f050b 
V.E...... ......I. 0,0-0,0 #102039d android:id/toast_layout_root}
D/ViewRootImpl(21171): MSG_RESIZED_REPORT: ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=1
D/ViewRootImpl(21171): #3 mView = null

What is the correct way to request permissions for Flutter plugins?

EDIT: This does not apply to the first run, when the dialog shows correctly, but to subsequent runs when the user did not grant the permission at first or revoked it via settings. I realize that changes the question significantly (making it appear as edge case), but Android permissions are not supposed to work that way.

EDIT: The permissions are present in AndroidManifest.xml

Upvotes: 6

Views: 17876

Answers (3)

CopsOnRoad
CopsOnRoad

Reputation: 267624

Let's say you want to request camera permission using permission_handler package.

  1. In pubspec.yaml file:

    permission_handler: ^8.0.0+2
    
  2. (For Android) Add the permission to android/app/src/main/AndroidManifest.xml file

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 
      ...
     </manifest>
    
  3. (For iOS),

    (i) Add this to your info.plist file

    <key>NSCameraUsageDescription</key>
    <string>App needs camera permission to work</string>
    

    (ii) Add 'PERMISSION_CAMERA=1' to your 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)',
    
            ## Add the following line.
             'PERMISSION_CAMERA=1'
          ]
    
        end
      end
    end
    
  4. Request the permission:

    final status = await Permission.camera.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.');
      await openAppSettings();
    }
    

Upvotes: -1

Kevin Caicedo
Kevin Caicedo

Reputation: 161

Use Permission plugin for flutter

Request permission
import 'package:permissions_plugin/permissions_plugin.dart';

Map<Permission, PermissionState> permission = await PermissionsPlugin
    .requestPermissions([
        Permission.ACCESS_FINE_LOCATION,
        Permission.ACCESS_COARSE_LOCATION,
        Permission.READ_PHONE_STATE
    ]);
Check status permission
import 'package:permissions_plugin/permissions_plugin.dart';

Map<Permission, PermissionState> permission = await PermissionsPlugin
    .checkPermissions([
      Permission.ACCESS_FINE_LOCATION,
      Permission.ACCESS_COARSE_LOCATION,
      Permission.READ_PHONE_STATE
    ]);

Upvotes: 5

AdaJane
AdaJane

Reputation: 97

I have this working for location permissions. The only thing I'm doing differently is in your method call here:

ActivityCompat.requestPermissions(activity,
                new String[]{Manifest.permission.RECORD_AUDIO},
                1);

Instead of using 'ActivityCompat' I store the registrar in a local final variable and I'm doing the following :

registrar.activity().requestPermissions(activity,
                new String[]{Manifest.permission.RECORD_AUDIO},
                1);

EDIT: Also make sure that you have included the relevant permissions in your AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Add this -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <!-- Flutter stuff --->
</manifest>

Upvotes: 0

Related Questions