Using BLE async Scans in a Background service ?

Hi,

I am working on a Bluetooth Low Energy scanner for Android, which has to scan every X minutes all nearly devices, getting all services and characteristics, and sending them to a HTTP server. This task has to be executed in background, so I figured I should use Services, but I dont know if that can work correctly with BLE scans.

BLE scans mainly use async methods and callbacks, is it possible to set all this process in a task or something I can control with a background service ?

By the way, I found many things about background services, and I don't get what I should use ... Can someone take a few minutes to explain me ? :dizzy:

Thanks !

Best Answer

  • JeanEuuuudesJeanEuuuudes US ✭✭
    edited September 2018 Accepted Answer

    Solved, using the native API.

    Here's the code:

    BackgroundService.cs

    using Android.Util;
    using Android.Bluetooth;
    using Android.Bluetooth.LE;
    
    public class BackgroundService : Service
        {
            IBinder binder;
            public List<BluetoothDevice> Devices;
            BluetoothManager Manager;
    
            [return: GeneratedEnum]
            public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
            {
                if (Manager == null) Manager = (BluetoothManager)Application.Context.GetSystemService(BluetoothService);
                if (Devices != null)
                {
                    if (Devices.Count != 0)
                    {
                        foreach (BluetoothDevice d in Devices) Log.Debug("BLE", "-----> " + d.Address);
                    }
                }
                Devices = new List<BluetoothDevice>();
                if (Manager.Adapter.IsDiscovering)
                {
                    Log.Debug("BLE", "ALREADY SCANNING");
                }
                else
                {
                    Log.Debug("BLE", "START SCANNING");
                    Manager.Adapter.BluetoothLeScanner.StartScan(new LeScanCallback(this));
                }
                return StartCommandResult.NotSticky;
            }
    
            public override IBinder OnBind(Intent intent)
            {
                binder = new BackgroundServiceBinder(this);
    
                return binder;
            }
    
        }
    
        public class LeScanCallback : ScanCallback
        {
            BackgroundService m;
    
            public LeScanCallback (BackgroundService m)
            {
                this.m = m;
            }
    
            public override void OnScanResult (ScanCallbackType cbt, ScanResult res)
            {
                if (!m.Devices.Contains(res.Device)) m.Devices.Add(res.Device);
                Log.Debug("BLE", "Device found: " + res.Device.Address);
            }
        }
    

    BackgroundServiceBinder.cs

    public class BackgroundServiceBinder : Binder
        {
            BackgroundService Service;
    
            public BackgroundServiceBinder (BackgroundService serv)
            {
                this.Service = serv;
            }
    
            public BackgroundService GetBackgroundService ()
            {
                return this.Service;
            }
        }
    

    MainActivity.cs

    protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
    
                SetContentView(Resource.Layout.Main);
                StartService();
            }
    
            private void StartService()
            {
                Log.Debug("BLE", "STARTING BACKGROUND");
                StartService(new Intent(this, typeof(BackgroundService)));
            }
    

Answers

  • BillyLiuBillyLiu Member, Xamarin Team Xamurai

    @JeanEuuuudes
    Do you want to scan Bluetooth in Background service?
    You could try to use Bluetooth LE plugin for Xamarin.
    It requires ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION BLUETOOTH BLUETOOTH_ADMIN permissions.

        List<IDevice> deviceList;
    
        [return: GeneratedEnum]
        public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
        {
    
            var ble = CrossBluetoothLE.Current;
            var adapter = CrossBluetoothLE.Current.Adapter;
            deviceList = new List<IDevice>();
            adapter.DeviceDiscovered += (s, a) => {
                deviceList.Add(a.Device);
    
            } ;
    
            Task task = new Task(() => adapter.StartScanningForDevicesAsync());
            task.Start();
    
            return StartCommandResult.NotSticky;
        }
    
  • JeanEuuuudesJeanEuuuudes USMember ✭✭

    Thanks for your help @BillyLiu .
    Thats right, I need to scan BLE devices in a Background Service.

    So, using this plugin, I can start a service which executes a task. Then, at the end of this task, I should schedule a delayed task ... Am I right ?

    thanks !

  • JeanEuuuudesJeanEuuuudes USMember ✭✭
    edited September 2018 Accepted Answer

    Solved, using the native API.

    Here's the code:

    BackgroundService.cs

    using Android.Util;
    using Android.Bluetooth;
    using Android.Bluetooth.LE;
    
    public class BackgroundService : Service
        {
            IBinder binder;
            public List<BluetoothDevice> Devices;
            BluetoothManager Manager;
    
            [return: GeneratedEnum]
            public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
            {
                if (Manager == null) Manager = (BluetoothManager)Application.Context.GetSystemService(BluetoothService);
                if (Devices != null)
                {
                    if (Devices.Count != 0)
                    {
                        foreach (BluetoothDevice d in Devices) Log.Debug("BLE", "-----> " + d.Address);
                    }
                }
                Devices = new List<BluetoothDevice>();
                if (Manager.Adapter.IsDiscovering)
                {
                    Log.Debug("BLE", "ALREADY SCANNING");
                }
                else
                {
                    Log.Debug("BLE", "START SCANNING");
                    Manager.Adapter.BluetoothLeScanner.StartScan(new LeScanCallback(this));
                }
                return StartCommandResult.NotSticky;
            }
    
            public override IBinder OnBind(Intent intent)
            {
                binder = new BackgroundServiceBinder(this);
    
                return binder;
            }
    
        }
    
        public class LeScanCallback : ScanCallback
        {
            BackgroundService m;
    
            public LeScanCallback (BackgroundService m)
            {
                this.m = m;
            }
    
            public override void OnScanResult (ScanCallbackType cbt, ScanResult res)
            {
                if (!m.Devices.Contains(res.Device)) m.Devices.Add(res.Device);
                Log.Debug("BLE", "Device found: " + res.Device.Address);
            }
        }
    

    BackgroundServiceBinder.cs

    public class BackgroundServiceBinder : Binder
        {
            BackgroundService Service;
    
            public BackgroundServiceBinder (BackgroundService serv)
            {
                this.Service = serv;
            }
    
            public BackgroundService GetBackgroundService ()
            {
                return this.Service;
            }
        }
    

    MainActivity.cs

    protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
    
                SetContentView(Resource.Layout.Main);
                StartService();
            }
    
            private void StartService()
            {
                Log.Debug("BLE", "STARTING BACKGROUND");
                StartService(new Intent(this, typeof(BackgroundService)));
            }
    
Sign In or Register to comment.