chipweinberger / flutter_blue_plus

Flutter plugin for connecting and communicationg with Bluetooth Low Energy devices, on Android, iOS, macOS
Other
788 stars 475 forks source link

[Help]: ANDROID: scan permission popup appears twice #972

Closed hiperioncn closed 3 months ago

hiperioncn commented 3 months ago

Requirements

Have you checked this problem on the example app?

No

FlutterBluePlus Version

1.32.11

Flutter Version

3.22.2

What OS?

Android

OS Version

android14

Bluetooth Module

esp32

What is your problem?

When I run the example app, click "scan" button, show ble request popup twice.

More info from https://github.com/boskokg/flutter_blue_plus/issues/966

chipweinberger commented 3 months ago

thats not a pairing request. It's a permissions popup.

hiperioncn commented 3 months ago

So why the example show permission popup twice?What can i do for it?

chipweinberger commented 3 months ago

we ask for 2 different permissions when scanning.BLUETOOTH_SCAN & BLUETOOTH_CONNECT

                    if (Build.VERSION.SDK_INT >= 31) { // Android 12 (October 2021)
                        permissions.add(Manifest.permission.BLUETOOTH_SCAN);
                        if (androidUsesFineLocation) {
                            permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
                        }
                        // it is unclear why this is needed, but some phones throw a
                        // SecurityException AdapterService getRemoteName, without it
                        permissions.add(Manifest.permission.BLUETOOTH_CONNECT);
                    }

but we only ask 1 at a time.

    private void askPermission(List<String> permissionsNeeded, OperationOnPermission operation)
    {
        // finished asking for permission? call callback
        if (permissionsNeeded.isEmpty()) {
            operation.op(true, null);
            return;
        }

        String nextPermission = permissionsNeeded.remove(0);

        operationsOnPermission.put(lastEventId, (granted, perm) -> {
            operationsOnPermission.remove(lastEventId);
            if (!granted) {
                operation.op(false, perm);
                return;
            }
            // recursively ask for next permission
            askPermission(permissionsNeeded, operation);
        });

        ActivityCompat.requestPermissions(
                activityBinding.getActivity(),
                new String[]{nextPermission},
                lastEventId);

        lastEventId++;
    }

you'll need to submit a PR to fix it, by asking both permissions at the same time.

chipweinberger commented 3 months ago

you can try this code. You'll need to change the FBP code.

@Override
public boolean onRequestPermissionsResult(int requestCode,
                                          String[] permissions,
                                          int[] grantResults) {
    OperationOnPermission operation = operationsOnPermission.get(requestCode);

    if (operation != null && grantResults.length > 0) {
        for (int i = 0; i < permissions.length; i++) {
            if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                // If any permission is denied, call the operation with false
                operation.op(false, permissions[i]);
                return true;
            }
        }
        // All permissions are granted
        operation.op(true, null);
        return true;
    } else {
        return false;
    }
}

private void ensurePermissions(List<String> permissions, OperationOnPermission operation) {
    // only request permission we don't already have
    List<String> permissionsNeeded = new ArrayList<>();
    for (String permission : permissions) {
        if (permission != null && ContextCompat.checkSelfPermission(context, permission)
                != PackageManager.PERMISSION_GRANTED) {
            permissionsNeeded.add(permission);
        }
    }

    // no work to do?
    if (permissionsNeeded.isEmpty()) {
        operation.op(true, null);
        return;
    }

    // Request all permissions at once
    askPermission(permissionsNeeded, operation);
}

private void askPermission(List<String> permissionsNeeded, OperationOnPermission operation) {
    // finished asking for permission? call callback
    if (permissionsNeeded.isEmpty()) {
        operation.op(true, null);
        return;
    }

    // Store the operation for later use in onRequestPermissionsResult
    operationsOnPermission.put(lastEventId, operation);

    // Request all needed permissions at once
    ActivityCompat.requestPermissions(
            activityBinding.getActivity(),
            permissionsNeeded.toArray(new String[0]),
            lastEventId);

    lastEventId++;
}