Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting PermanentlyDenied when I request bluetooth permission #830

Closed
thormj opened this issue Apr 8, 2022 · 26 comments
Closed

Getting PermanentlyDenied when I request bluetooth permission #830

thormj opened this issue Apr 8, 2022 · 26 comments
Labels
P2 Important issues not at the top of the work list. platform: ios Issue is related to the iOS platform status: closed (missing info) Indicates the issue was automatically closed due to a lack of information. status: needs more info We need more information before we can continue work on this issue. type: bug Something isn't working

Comments

@thormj
Copy link

thormj commented Apr 8, 2022

Only seems to happen on iOS;
When I do a Permission.bluetooth.request(), I'm getting back "PermantentlyDenied" with no dialog...
I have this in my info.plist:

        <key>NSBluetoothAlwaysUsageDescription</key>
	<string>We need BT access because it's a BT App.</string>
	<key>NSBluetoothPeripheralUsageDescription</key>
	<string>We need BT access because it's a BT App.</string>
	<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
	<string>Location required for BLE devices</string>
	<key>NSLocationAlwaysUsageDescription</key>
	<string>Location required for BLE devices</string>
	<key>NSLocationWhenInUseUsageDescription</key>
	<string>Location required for BLE devices</string>

And I do the following in main.dart:

  void bleScan() async {
    print("bleScan");
    bluetoothok = false;

    //Ask for runtime permissions if necessary.
    var status = await Permission.bluetooth.request();
    if (status.isPermanentlyDenied) {
    setState(() {
      title = "foto-captor No Bluetooth";
    	print("BLEpermdisabled");
	    });
    	return;
    	}

    status = await Permission.bluetoothConnect.request();
    if (status.isPermanentlyDenied) {
    setState(() {
      title = "foto-captor Bluetooth NoConnect";
    	print("ConnectPermdisabled");
	    });
    	return;
    	}

    status = await Permission.bluetoothScan.request();
    if (status.isPermanentlyDenied) {
    	setState(() {
      		title = "foto-captor Can't Scan";
    	print("ScanPermdisabled");
	    });
    	return;
    	}

    myFlutterBlue.flutterBlue.setLogLevel(LogLevel.notice);

I've heard that Apple says you need to request permissions after the UI --- so is the request() only done once, and where should I put it in the code (I put it in the DoScan because that's what kicks everything off for me, but that fires before the UI appears)...

@mvanbeusekom
Copy link
Member

Hi @thormj,

Did you enable the permission macros in your ios/Podfile as mentioned in the iOS section of the README.md?

This is required to ensure the code for requesting the permissions you need are compiled into the source code.

@mvanbeusekom mvanbeusekom added platform: ios Issue is related to the iOS platform status: needs more info We need more information before we can continue work on this issue. labels Apr 9, 2022
@Yahllil
Copy link

Yahllil commented Apr 10, 2022

Any update on this one? I'm experiencing the same issue

@mvanbeusekom
Copy link
Member

Hi @Yahllil,

Did you have a look at my previous comment?

@thormj
Copy link
Author

thormj commented Apr 11, 2022

@mvanbeusekom trying that... I think this is correct for BLE; I'll post an update when I get back to the iPhone:

# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

def flutter_root
  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
  unless File.exist?(generated_xcode_build_settings_path)
    raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
  end

  File.foreach(generated_xcode_build_settings_path) do |line|
    matches = line.match(/FLUTTER_ROOT\=(.*)/)
    return matches[1].strip if matches
  end
  raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
  use_frameworks!
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    target.build_configurations.each do |config|
    # You can enable the permissions needed here. For example to enable camera
      # permission, just remove the `#` character in front so it looks like this:
      #
      # ## dart: PermissionGroup.camera
      # 'PERMISSION_CAMERA=1'
      #
      #  Preprocessor definitions can be found in: https://github.com/Baseflow/flutter-permission-handler/blob/master/permission_handler/ios/Classes/PermissionHandlerEnums.h
      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
        '$(inherited)',

        ## dart: PermissionGroup.calendar
        # 'PERMISSION_EVENTS=1',

        ## dart: PermissionGroup.reminders
        # 'PERMISSION_REMINDERS=1',

        ## dart: PermissionGroup.contacts
        # 'PERMISSION_CONTACTS=1',

        ## dart: PermissionGroup.camera
        # 'PERMISSION_CAMERA=1',

        ## dart: PermissionGroup.microphone
        # 'PERMISSION_MICROPHONE=1',

        ## dart: PermissionGroup.speech
        # 'PERMISSION_SPEECH_RECOGNIZER=1',

        ## dart: PermissionGroup.photos
        # 'PERMISSION_PHOTOS=1',

        ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
        'PERMISSION_LOCATION=1',

        ## dart: PermissionGroup.notification
        # 'PERMISSION_NOTIFICATIONS=1',

        ## dart: PermissionGroup.mediaLibrary
        # 'PERMISSION_MEDIA_LIBRARY=1',

        ## dart: PermissionGroup.sensors
        # 'PERMISSION_SENSORS=1',   

        ## dart: PermissionGroup.bluetooth
        'PERMISSION_BLUETOOTH=1',

        ## dart: PermissionGroup.appTrackingTransparency
        # 'PERMISSION_APP_TRACKING_TRANSPARENCY=1',

        ## dart: PermissionGroup.criticalAlerts
        # 'PERMISSION_CRITICAL_ALERTS=1'
      ]
    end
  end
end

@no-response no-response bot removed the status: needs more info We need more information before we can continue work on this issue. label Apr 11, 2022
@thormj
Copy link
Author

thormj commented Apr 12, 2022

It reliably asks for the "Use Bluetooth Connection," but it just quits with Permission.bluetoothConnect.request returning PermanentlyDenied...

My Code

    //Ask for runtime permissions if necessary.
    var status = await Permission.bluetooth.request();
    if (status.isPermanentlyDenied) {
    setState(() {
      title = "foto-captor No Bluetooth";
    	print("BLEpermdisabled");
	    });
    	return;
    	}

    status = await Permission.bluetoothConnect.request();
    if (status.isPermanentlyDenied) {
    setState(() {
      title = "foto-captor Bluetooth NoConnect";
    	print("ConnectPermdisabled");
	    });
    	return;
    	}

    status = await Permission.bluetoothScan.request();
    if (status.isPermanentlyDenied) {
    	setState(() {
      		title = "foto-captor Can't Scan";
    	print("ScanPermdisabled");
	    });
    	return;
    	}

    myFlutterBlue.flutterBlue.setLogLevel(LogLevel.notice);
    setState(() {
      title = "foto-captor " + indBLE;
    });

    bluetoothok = true;
    doingthis=false;
    print("GoTime... startscan.");
    myFlutterBlue.delScanStatusHandler();
    myFlutterBlue.addScanStatusHandler(scanStatusHandler);
    if (!myFlutterBlue.scanactive)
      await myFlutterBlue.startScan((sr) {
        scanResult(sr);
      }, allowDuplicates: true);

@thormj
Copy link
Author

thormj commented Apr 12, 2022

At one point it said "you can ask for multiple permissions at the same time" -- how do you do that when it's Permission.XXX.request -- Permission.(Bluetooth | Connection | Location).Request?

@thormj
Copy link
Author

thormj commented Apr 12, 2022

Oh, and can I do this as part of initstate? It seems odd to put it someplace else..

@libindstme
Copy link

Any update on this ?

Me also Failed to request Permission in IOS .

@mvanbeusekom
Copy link
Member

@libindstme are you also requesting Bluetooth permissions?

@mvanbeusekom mvanbeusekom changed the title Getting PermanentlyDenied when I request Getting PermanentlyDenied when I request bluetooth permission Apr 13, 2022
@mvanbeusekom
Copy link
Member

@thormj, thank you for supplying the example code and detailed reproduction steps, I will be looking into the behavior and get back to you a.s.a.p.

Regarding your other questions:

At one point it said "you can ask for multiple permissions at the same time" -- how do you do that when it's Permission.XXX.request -- Permission.(Bluetooth | Connection | Location).Request?

Requesting multiple permissions can be done using an array of permissions (p.s. note the the Connection permission in your example doesn't exists):

Map<Permission, PermissionStatus> statuses = await [
  Permission.bluetooth,
  Permission.location,
].request();

Oh, and can I do this as part of initstate? It seems odd to put it someplace else..

Yes the initState would be a good place to request / handle permissions. Most important part is to not request permissions as part of your build method as this could result in multiple calls.

@thormj
Copy link
Author

thormj commented Apr 13, 2022

A-ha! I'm getting PermanentlyDenied on things that "aren't in iOS"--
Can we have things that aren't necessary in one platform or another return "granted" or "not used" or something?
eg, on IOS: bluetoothConnect, bluetoothScan

If it's permanently denied, it makes sense to open the app settings for "yes, I need Bluetooth," but if there isn't a permission for that (I'm assuming it will just work)... presenting the user with an app settings dialogue doesn't make much sense.

I'm kinda assuming I do need those permissions... maybe I don't? -- on my Android, it appears I don't but I wrapped them in a Platform.isAndroid just to fix it for certain.

Should I make this post into a bug?

@karabanovbs
Copy link

have the same problem, permissions (bluetoothScan, bluetoothConnect) always PermanentlyDenied but bluetooth scan working.

@itsJoKr
Copy link

itsJoKr commented Aug 29, 2022

What could be the issue here is the line:

        CBManagerAuthorization blePermission = [_centralManager authorization];
        return [BluetoothPermissionStrategy parsePermission:blePermission];

at https://github.com/Baseflow/flutter-permission-handler/blob/master/permission_handler_apple/ios/Classes/strategies/BluetoothPermissionStrategy.m

I don't think this is the way how you listen for bluetooth permission result. Basically, when you construct CBCentralManager that will invoke the permission prompt. BUT, the user didn't yet click anything, and calling authorization right on the next line is not helpful as it will always return notDetermined.

The proper way would be to use a delegate and listen for a change:

    @objc func centralManagerDidUpdateState(_ central: CBCentralManager) {
       // This has to be called, as user cannot dismiss prompt. He will either clic:
       //  - allow -> _central.state == .poweredOn or .poweredOff
       //  - don't allow -> _central.state == .unathorized
    }

But that requires a bit of refactoring inside strategy as it should work async.

@andrepura
Copy link

i also experience this problem with ios and bluetooth permissions
will there be an update or any other suggestions (e.g. workarounds).

    final Map<Permission, PermissionStatus> statuses = await <Permission>[
      if(Platform.isAndroid)Permission.bluetoothConnect,
      if(Platform.isAndroid)Permission.bluetoothScan,
      if(Platform.isIOS)Permission.bluetooth
      //Permission.location,
    ].request();

@hm122
Copy link

hm122 commented Feb 4, 2023

Same issue here, on iOS 16.

{Permission.bluetooth: PermissionStatus.permanentlyDenied}

Bluetooth is enabled in the app settings.

@electricmonk
Copy link

Same issue here

@yahacom
Copy link

yahacom commented Apr 26, 2023

same issue here. permanently denied on iOS 13

  • macros to podfile was added
  • keys to Info.plist was added

any clue?

@JeroenWeener JeroenWeener added type: bug Something isn't working P2 Important issues not at the top of the work list. labels Jul 11, 2023
@JeroenWeener
Copy link
Contributor

Hi everyone!

I recently looked into a similar issue and believe @itsJoKr might be right. This would basically come down to a race condition in the Objective-C code.

I will investigate and (hopefully) come back with a PR that resolves this issue.

@JeroenWeener
Copy link
Contributor

Hi everyone!

We just landed some changes to the code relevant for this issue. As a by-product, this issue might be solved.
Can anyone verify whether the issue still exists on the latest version of the plugin? Make sure that the latest version of permission_handler_apple (9.1.4) is being used by checking the pubspec.lock file. If it is not, you can pull it in by running flutter pub upgrade.

@JeroenWeener JeroenWeener added the status: needs more info We need more information before we can continue work on this issue. label Jul 13, 2023
@github-actions
Copy link

Without additional information, we are unfortunately not able to resolve this issue. Therefore, we reluctantly closed this issue for now. If you run into this issue later, feel free to file a new issue with a reference to this issue. Add a description of detailed steps to reproduce, expected and current behaviour, logs and the output of 'flutter doctor -v'. Thanks for your contribution.

@github-actions github-actions bot added the status: closed (missing info) Indicates the issue was automatically closed due to a lack of information. label Jul 27, 2023
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 27, 2023
@cl0v
Copy link

cl0v commented Aug 14, 2023

Updating to the latest version in pubs.yml didnt solve.

Podfile and info.plist permissions are OK.

.lock:
permission_handler: dependency: "direct main" description: name: permission_handler sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81" url: "https://pub.dev" source: hosted version: "10.4.3" permission_handler_android: dependency: transitive description: name: permission_handler_android sha256: "2ffaf52a21f64ac9b35fe7369bb9533edbd4f698e5604db8645b1064ff4cf221" url: "https://pub.dev" source: hosted version: "10.3.3" permission_handler_apple: dependency: transitive description: name: permission_handler_apple sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5" url: "https://pub.dev" source: hosted version: "9.1.4"

@JeroenWeener JeroenWeener reopened this Aug 15, 2023
@JeroenWeener JeroenWeener removed status: needs more info We need more information before we can continue work on this issue. status: closed (missing info) Indicates the issue was automatically closed due to a lack of information. labels Aug 15, 2023
@nasawz
Copy link

nasawz commented Sep 11, 2023

Hello everyone, ios and android are different solutions.

void requestBluetoothPermission() async {
    if (Platform.isAndroid) {
      [Permission.bluetoothScan, Permission.bluetoothConnect]
          .request()
          .then((status) {
        if (status[Permission.bluetoothScan] == PermissionStatus.granted &&
            status[Permission.bluetoothConnect] == PermissionStatus.granted) {
          bluetoothIsGranted.value = true;
        } else {
          bluetoothIsGranted.value = false;
        }
      });
    }
    if (Platform.isIOS) {
      [Permission.bluetooth].request().then((status) {
        if (status[Permission.bluetooth] == PermissionStatus.granted) {
          bluetoothIsGranted.value = true;
        } else {
          bluetoothIsGranted.value = false;
        }
      });
    }
  }

@JeroenWeener
Copy link
Contributor

Hi everyone,

I have been unable to reproduce this issue on a physical iPhone running iOS 16. I have used the code provided in the original post, combined with the code in this comment.

For me, the code works as expected on the latest version of the plugin (11.0.0). The call to Permission.bluetooth opens a dialog and returns once the user made a choice. The status that is returned corresponds to the choice the user made.

Note: the Permission.bluetoothScan and Permission.bluetoothConnect permissions are Android-only, and will always return PermissionStatus.permanentlyDenied on iOS devices.

If you are experiencing this problem, please provide me with the details of your setup, including:

  • iOS version
  • Plugin version
  • A minimal reproducible code sample in the form of a main.dart file
  • The contents of your Podfile and Info.plist

@JeroenWeener JeroenWeener added the status: needs more info We need more information before we can continue work on this issue. label Sep 22, 2023
@github-actions
Copy link

github-actions bot commented Oct 6, 2023

Without additional information, we are unfortunately not able to resolve this issue. Therefore, we reluctantly closed this issue for now. If you run into this issue later, feel free to file a new issue with a reference to this issue. Add a description of detailed steps to reproduce, expected and current behaviour, logs and the output of 'flutter doctor -v'. Thanks for your contribution.

@github-actions github-actions bot added the status: closed (missing info) Indicates the issue was automatically closed due to a lack of information. label Oct 6, 2023
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Oct 6, 2023
@Daeon97
Copy link

Daeon97 commented Dec 12, 2024

Hi everyone,

I have been unable to reproduce this issue on a physical iPhone running iOS 16. I have used the code provided in the original post, combined with the code in this comment.

For me, the code works as expected on the latest version of the plugin (11.0.0). The call to Permission.bluetooth opens a dialog and returns once the user made a choice. The status that is returned corresponds to the choice the user made.

Note: the Permission.bluetoothScan and Permission.bluetoothConnect permissions are Android-only, and will always return PermissionStatus.permanentlyDenied on iOS devices.

If you are experiencing this problem, please provide me with the details of your setup, including:

  • iOS version
  • Plugin version
  • A minimal reproducible code sample in the form of a main.dart file
  • The contents of your Podfile and Info.plist

@JeroenWeener this issue is still happening. I have just experienced this. I have added a very descriptive comment here #1333 (comment) please take a look

@Daeon97
Copy link

Daeon97 commented Dec 12, 2024

Update:

I managed to fix the issue. I have updated my comment here #1333 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P2 Important issues not at the top of the work list. platform: ios Issue is related to the iOS platform status: closed (missing info) Indicates the issue was automatically closed due to a lack of information. status: needs more info We need more information before we can continue work on this issue. type: bug Something isn't working
Projects
None yet
Development

No branches or pull requests