Come rilevare i dispositivi Bluetooth nelle vicinanze con .NET e Xamarin.Android

Come rilevare i dispositivi Bluetooth nelle vicinanze con .NET e Xamarin.Android

Al momento sto lavorando su un'app Xamarin.Android:per questa app, devo rilevare quali dispositivi Bluetooth sono disponibili per il mio telefono Android (in modo che l'utente possa scegliere con quale accoppiarsi).

Per le versioni moderne di Android, non è così semplice come usare un BroadcastReceiver (sebbene faccia parte della soluzione). In questo post scriverò dei passaggi necessari per utilizzare correttamente l'hardware Bluetooth sul tuo telefono Android con .NET.

Una cosa da notare:posso provare a rilevare i dispositivi Bluetooth distribuendo il mio codice direttamente su un dispositivo Android, ma non posso usare l'emulatore Android perché non ha il supporto Bluetooth.

Come al solito ho caricato il mio codice su GitHub (puoi trovarlo qui).

Aggiorna AndroidManifest.xml con Bluetooth e autorizzazioni di geolocalizzazione

Per prima cosa dovevo assicurarmi che la mia applicazione indicasse al dispositivo a quali servizi hardware era necessario accedere. Per rilevare e interagire con l'hardware Bluetooth, sono disponibili quattro servizi da aggiungere all'applicazione AndroidManifest.xml:

  • Bluetooth
  • Amministratore Bluetooth
  • Accedi alla posizione grossolana
  • Accedi alla posizione eccellente

Quando l'applicazione viene caricata sul dispositivo Android per la prima volta, all'utente verrà chiesto di concedere all'applicazione l'autorizzazione a utilizzare questi servizi hardware.

Ho incollato il mio file AndroidManifest.xml di seguito:il tuo avrà un aspetto leggermente diverso, ma ho evidenziato la parte importante in rosso.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          android:versionCode="1"
          android:versionName="1.0"
          package="Bluetooth_Device_Scanner.Bluetooth_Device_Scanner">
  <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="27" />
  <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
  </application>
  <uses-permission android:name="android.permission.BLUETOOTH" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

Elenca i dispositivi Bluetooth con cui il dispositivo Android è già accoppiato

Questa parte è molto semplice:ricorda che il codice seguente elencherà per console solo i dispositivi Bluetooth che sono già stati rilevati e associati al dispositivo Android. Non elencherà altri dispositivi che non sono già stati accoppiati tra loro (ne parlerò più avanti nell'articolo).

if (BluetoothAdapter.DefaultAdapter != null && BluetoothAdapter.DefaultAdapter.IsEnabled)
{
    foreach (var pairedDevice in BluetoothAdapter.DefaultAdapter.BondedDevices)
    {
        Console.WriteLine(
            $"Found device with name: {pairedDevice.Name} and MAC address: {pairedDevice.Address}");
    }
}

Non c'è molto altro da dire su questo:posso inserirlo praticamente ovunque nel codice C# e funzionerà come previsto.

Elenca i nuovi dispositivi Bluetooth creando una classe BluetoothDeviceReceiver che estende BroadcastReceiver

Successivamente volevo elencare i dispositivi Bluetooth che non sono stati associati al dispositivo Android. Posso farlo creando una classe ricevitore, che estende la classe base "BroadcastReceiver" e sovrascrive il metodo "OnReceive":ho incluso il codice per la mia classe di seguito.

using System;
using Android.Bluetooth;
using Android.Content;
 
namespace Bluetooth_Device_Scanner
{
    public class BluetoothDeviceReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            var action = intent.Action;
            
            if (action != BluetoothDevice.ActionFound)
            {
                return;
            }
 
            // Get the device
            var device = (BluetoothDevice)intent.GetParcelableExtra(BluetoothDevice.ExtraDevice);
 
            if (device.BondState != Bond.Bonded)
            {
                Console.WriteLine($"Found device with name: {device.Name} and MAC address: {device.Address}");
            }
        }
    }
}

Questa classe di ricevitore viene registrata con l'applicazione e gli viene detto di attivarsi quando il dispositivo Android rileva eventi specifici, come la ricerca di un nuovo dispositivo Bluetooth. Xamarin.Android lo fa attraverso qualcosa chiamato "Intento". Il codice seguente mostra come registrare il ricevitore per attivarlo quando viene rilevato un dispositivo Bluetooth.

// Register for broadcasts when a device is discovered
_receiver = new BluetoothDeviceReceiver();
RegisterReceiver(_receiver, new IntentFilter(BluetoothDevice.ActionFound));

Quando il dispositivo Android trova un nuovo dispositivo Bluetooth e chiama il metodo OnReceive, la classe verifica che l'evento sia sicuramente quello giusto (es. BluetoothDevice.ActionFound).

Quindi controlla che i dispositivi non siano già accoppiati (ad es. "Bonded") e di nuovo la mia classe scrive solo alcuni dettagli sulla console sul dispositivo Bluetooth che ha trovato.

Ma non abbiamo ancora finito:c'è un altro pezzo di codice molto importante che è necessario per le versioni moderne di Android.

Infine:verifica che i permessi vengano applicati in fase di esecuzione

Questa è la parte che a volte manca in altri tutorial, e forse perché è necessaria solo per le versioni più recenti di Android, quindi i tutorial meno recenti non avrebbero avuto bisogno di questo passaggio.

Fondamentalmente, anche se le autorizzazioni Access Coarse e Fine Location sono già specificate nel file AndroidManifest.xml, se stai utilizzando una versione successiva alla 23 dell'SDK Android, devi anche verificare che le autorizzazioni siano impostate correttamente in fase di runtime. In caso contrario, è necessario aggiungere il codice per richiedere all'utente di concedere queste autorizzazioni.

Ho incollato la mia classe MainActivity di seguito. Questa classe:

  • Verifica le autorizzazioni,
  • Richiede all'utente eventuali autorizzazioni mancanti,
  • Registra il ricevitore in modo che si attivi quando vengono rilevati dispositivi Bluetooth e
  • Avvia la ricerca di dispositivi Bluetooth.
using Android;
using Android.App;
using Android.Bluetooth;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Support.V4.App;
using Android.Support.V4.Content;
 
namespace Bluetooth_Device_Scanner
{
    [Activity(Label = "Bluetooth Device Scanner", MainLauncher = true)]
    public class MainActivity : Activity
    {
        private BluetoothDeviceReceiver _receiver;
 
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
 
            SetContentView(Resource.Layout.activity_main);
 
            const int locationPermissionsRequestCode = 1000;
 
            var locationPermissions = new[]
            {
                Manifest.Permission.AccessCoarseLocation,
                Manifest.Permission.AccessFineLocation
            };
 
            // check if the app has permission to access coarse location
            var coarseLocationPermissionGranted =
                ContextCompat.CheckSelfPermission(this, Manifest.Permission.AccessCoarseLocation);
 
            // check if the app has permission to access fine location
            var fineLocationPermissionGranted =
                ContextCompat.CheckSelfPermission(this, Manifest.Permission.AccessFineLocation);
 
            // if either is denied permission, request permission from the user
            if (coarseLocationPermissionGranted == Permission.Denied ||
                fineLocationPermissionGranted == Permission.Denied)
            {
                ActivityCompat.RequestPermissions(this, locationPermissions, locationPermissionsRequestCode);
            }
 
            // Register for broadcasts when a device is discovered
            _receiver = new BluetoothDeviceReceiver();
 
            RegisterReceiver(_receiver, new IntentFilter(BluetoothDevice.ActionFound));
 
            BluetoothDeviceReceiver.Adapter.StartDiscovery();
        }
    }
}

Ora l'applicazione chiamerà il metodo OnReceive della classe BluetoothDeviceReceiver quando rileva l'hardware Bluetooth.

Conclusione

Si spera che questo sia utile a chiunque scriva un'applicazione Xamarin.Android che interagisce con i dispositivi Bluetooth:ho lottato con questo per un po' e non sono riuscito a trovare un articolo che descrivesse in dettaglio tutti i pezzi del puzzle:

  • Aggiorna il manifest con le 4 autorizzazioni dell'applicazione richieste
  • Crea una classe che estenda BroadcastReceiver,
  • Verifica in fase di esecuzione che le autorizzazioni alla posizione siano state concesse e chiedi all'utente se non l'hanno fatto, e
  • Registra la classe ricevente e inizia il rilevamento.

Su di me: Pubblico regolarmente informazioni sulle tecnologie Microsoft e .NET:se sei interessato, seguimi su Twitter o dai un'occhiata ai miei post precedenti qui. Grazie!