inthehand / 32feet

Personal Area Networking for .NET. Open source and professionally supported
https://inthehand.com/components/32feet/
MIT License
838 stars 208 forks source link

.netMaui GA Android BluetoothLE: Stumbled at using RequestPermissions #197

Closed gfmoore closed 2 years ago

gfmoore commented 2 years ago

Hi, I have great hopes for this. So trying to follow the example at https://github.com/inthehand/32feet/wiki/Bluetooth-Low-Energy

So I nuget the InTheHand.BluetoothLE 4.0.24 I add the line

RequestPermissions(new string[] { Manifest.Permission.AccessCoarseLocation, Manifest.Permission.BluetoothAdmin }, 1);

I get the red wavy lines under RequestPermission and Manifest

I assume? that I need to use

using InTheHand.Bluetooth;  (I expected BluetoothLE, but not in the intellisense,  as I don't want to use Bluetooth classic?)

However the red wavy lines don't disappear.

What stupid thing am I doing (or not doing) :()

gfmoore commented 2 years ago

Oooh I got rid of wavy lines under Manifest by

using Android;

Now for RequestPermission which is I assume a method in the InTheHand.Bluetooth package

Edit: Uhmm some Errors image

peterfoot commented 2 years ago

RequestPermission is an Android API. In a Xamarin Android app I think the required usings were added automatically to the android head project. This will have changed slightly with the move to .NET 6 and MAUI.

gfmoore commented 2 years ago

Hi Peter thanks for responding so quickly.

Could you suggest exactly what i need to do? Bluetooth is not on the Maui roadmap and so I suspect I need to do some manual tinkering, but I have no idea what. Bit new to this platform and struggling through the treacle. :)

peterfoot commented 2 years ago

There are some details here on requesting permissions in a Maui app - https://docs.microsoft.com/en-us/dotnet/maui/platform-integration/appmodel/permissions?tabs=ios#requesting-permissions

gfmoore commented 2 years ago

Yes, and I'm working through it, but Bluetooth is NOT one of the permissions made available by MS which is not good (or other words!). Thanks anyway.

peterfoot commented 2 years ago

I see - that's annoying because it was possible with the old Xamarin.Essentials in the same basic way. I'll look at it and see if there is an easy workaround...

gfmoore commented 2 years ago

EDIT: probably irrelevant now, see comments below

I'm looking at the bottom of the docs where it explains how to extend the permissions, but it's very difficult to get my head around. I've created a class: BluetoothPermissions.cs

namespace TSDZ2Monitor.Classes;

public class BluetoothPermissions : Permissions.BasePlatformPermission
{
  public override (string androidPermission, bool isRuntime)[] RequiredPermissions =>
    new List<(string androidPermission, bool isRuntime)>
    {
        (global::Android.Manifest.Permission.AccessCoarseLocation, true),
        (global::Android.Manifest.Permission.AccessFineLocation, true),

        (global::Android.Manifest.Permission.Bluetooth, true),
        (global::Android.Manifest.Permission.BluetoothAdmin, true),
        (global::Android.Manifest.Permission.BluetoothScan, true),
        (global::Android.Manifest.Permission.BluetoothConnect, true),
        (global::Android.Manifest.Permission.BluetoothAdvertise, true)

    }.ToArray();
}

and this corresponds with the AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />

  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.BLUETOOTH" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

  <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
  <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

  <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

</manifest>

Note the change from UPPERCASE to lowercase

In my Page codebehind I do

using InTheHand.Bluetooth;
using TSDZ2Monitor.Classes;

namespace TSDZ2Monitor.Pages;

public partial class BluetoothPage : ContentPage
{
    public BluetoothPage()
    {
        InitializeComponent();

        Console.WriteLine("Bluetooth here");

    getBLEPermission();
    static async void getBLEPermission()
    {
      //PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
      PermissionStatus status = await Permissions.RequestAsync<BluetoothPermissions>();
      if (status != PermissionStatus.Granted)
      {
        status = await Permissions.RequestAsync<BluetoothPermissions>();
        if (status != PermissionStatus.Granted)
        {
          //well kill the app because it's no use
          return;
        }
      }
    }

  }

}

So it will ask for location permissions (and I manually set the app permission to ask each time for testing), but of course it won't ask about bluetooth, because no code is written for that.

There is a skeleton:

public class MyPermission : Permissions.BasePermission
{
    // This method checks if current status of the permission.
    public override Task<PermissionStatus> CheckStatusAsync()
    {
        throw new System.NotImplementedException();
    }

    // This method is optional and a PermissionException is often thrown if a permission is not declared.
    public override void EnsureDeclared()
    {
        throw new System.NotImplementedException();
    }

    // Requests the user to accept or deny a permission.
    public override Task<PermissionStatus> RequestAsync()
    {
        throw new System.NotImplementedException();
    }

    // Indicates that the requestor should prompt the user as to why the app requires the permission, because the
    // user has previously denied this permission.
    public override bool ShouldShowRationale()
    {
        throw new NotImplementedException();
    }
}

but as per usual with MS documentation this is written for Vulcans and not mere mortals and it doesn't explain how to use it or what to put in it.

I think progress is being made, but....

gfmoore commented 2 years ago

The following post https://gist.github.com/salarcode/da8ad2b993e67c602db88a62259d0456 shows how to add theBluetooth permissions. It seems to be working as for my app it now seems to have Bluetooth permission options. It doesn't display a popup requesting access. I don't yet know if that is something Android automatically does or it's what needs to be written for Maui. For example requesting Location permission results in a very pretty popup.

Anyway it's progress and maybe can be improved?

The source thread for this is https://github.com/dotnet/maui/discussions/277

peterfoot commented 2 years ago

I'll add a link to that post to the Wiki. It's a good sample because it covers all the different Android versions where different permission combinations are required. Ultimately it would be good to either include a maui permission in this library or submit it to the maui essentials library so that it is always available out of the box.