.net, C# tip, Visual Studio, Xamarin

How to detect nearby Bluetooth devices with .NET and Xamarin.Android

I’m working on an Xamarin.Android app at the moment – for this app, I need to detect what Bluetooth devices are available to my Android phone (so the user can choose which one to pair with).

For modern versions of Android, it’s not as simple as just using a BroadcastReceiver (although that is part of the solution). In this post I’ll write about the steps needed to successfully use the Bluetooth hardware on your Android phone with .NET.

One thing to note – I can test detecting Bluetooth devices by deploying my code directly onto an Android device, but I can’t use the Android emulator as it doesn’t have Bluetooth support.

As usual I’ve uploaded my code to GitHub (you can get it here).

Update AndroidManifest.xml with Bluetooth and Location permissions

First I had to make sure that my application told the device what hardware services it needed to access. For detecting and interacting with Bluetooth hardware, there are four services to add to the application AndroidManifest.xml:

  • Bluetooth
  • Bluetooth Admin
  • Access Coarse Location
  • Access Fine Location

When the application loads on the Android device for the first time, the user will be challenged to allow the application permission to use these hardware services.

I’ve pasted my AndroidManifest.xml file below – yours will look slightly different, but I’ve highlighted the important bit in red.

<?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>

 

List the Bluetooth devices which the Android device has already paired with

This part is very straightforward – remember the code below will list to console only the Bluetooth devices which have already been detected and paired with the Android device. It will not list other devices which haven’t already been paired with each other (I write about this later in the article).

Obviously you’d probably want to write the output to a UI component rather than write to the console, but for this article I wanted to cut this down to only the Bluetooth interactions and not focus on UI interactions.

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}");
    }
}

There’s not much more to say about this – I can put this pretty much anywhere in the C# code and it’ll just work as expected.

List new Bluetooth devices by creating a BluetoothDeviceReceiver class that extends BroadcastReceiver

Next I wanted to list the Bluetooth devices that haven’t been paired with the Android device. I can do this by creating a receiver class, which extends the ‘BroadcastReceiver’ base class, and overrides the ‘OnReceive’ method – I’ve included the code for my class below.

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}");
            }
        }
    }
}

This receiver class is registered with the application and told to activate when the Android device detects specific events – such as finding a new Bluetooth device. Xamarin.Android does this through something called an ‘Intent’. The code below shows how to register the receiver to trigger when a Bluetooth device is detected.

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

When the Android device finds a new Bluetooth device and calls the OnReceive method, the class checks that the event is definitely the right one (i.e. BluetoothDevice.ActionFound).

Then it checks that the devices are not already paired (i.e. ‘Bonded’) and again my class just writes some details to the console about the Bluetooth device that its found.

But we’re not quite done yet – there’s one more very important piece of code which is necessary for modern versions of Android.

Finally – check permissions are applied at runtime

This is the bit that is sometimes missed in other tutorials, and that’s possibly because this is only needed for more recent versions of Android, so older tutorials wouldn’t have needed this step.

Basically even though the Access Coarse and Fine Location permissions are already specified in the AndroidManifest.xml file, if you’re using later than version 23 of the Android SDK, you need to also check that the permissions are correctly set at runtime. If they aren’t, you need to add code to prompt the user to grant these permissions.

There’s lots more about this topic on the Xamarin blog here.

I’ve pasted my MainActivity class below. This class:

  • Checks permissions,
  • Prompts the user for any permissions that are missing,
  • Registers the receiver to trigger when Bluetooth devices are detected, and
  • Starts scanning for Bluetooth devices.
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(thisManifest.Permission.AccessCoarseLocation);
 
            // check if the app has permission to access fine location
            var fineLocationPermissionGranted =
                ContextCompat.CheckSelfPermission(thisManifest.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();
        }
    }
}

Now the application will call the BluetoothDeviceReceiver class’s OnReceive method when it detects Bluetooth hardware.

Wrapping up

Hopefully this is useful to anyone writing a Xamarin.Android application that interacts with Bluetooth devices – I struggled with this for a while and wasn’t able to find an article which detailed all the pieces of the puzzle:

  • Update the manifest with the 4 required application permissions
  • Create a class that extends BroadcastReceiver,
  • Check at runtime that the location permissions have been granted and prompt the user if they haven’t, and
  • Register the receiver class and start discovery.

About me: I regularly post about Microsoft technologies and .NET – if you’re interested, please follow me on Twitter, or have a look at my previous posts here. Thanks!

Xamarin

Building Xamarin.Android projects and how to find the ‘missing Android SDKs required for building’.

Recently I’ve seen the error below when trying to build some sample Xamarin projects out-of-the-box in Visual Studio 2017.

sdk error

Seems like a simple error to fix…just follow the instructions and double click on the message to install the missing Android SDKs, right?

On my machine double-clicking on the error does not install the missing Android SDKs which makes me a sad developer.

After a lot of searching, I found the reason that double-clicking does nothing is because my instance of VS2017 is set to not do anything, and I expect I’m not the only one seeing this error because VS2017 is set to behave this way during the default installation.

If you’re unlucky and are at this article because you’re seeing the same error as me and double clicking is doing nothing for you, you could try this – in Visual Studio go to Tools -> Options, and scroll down to the Xamarin settings so you see a screen like the one below. You’ll probably see an un-ticked tickbox setting with the name ‘Auto Install Android SDKs’.

settings1

I changed the value to ticked and hit OK.

settings2

After I changed this setting, I tried double clicking on the error message again, and this time the window below popped up immediately. I was able to follow through the SDK installation wizard and make the project compile.

android sdk licence

So a pretty simple fix, but it’d be better if the error message said:

Make sure that Visual Studio is set to Auto Install Android SDKs in Xamarin’s Android.Settings option, and then double click on this message and follow the instructions‘.

.net, Troubleshooting, Xamarin

Troubleshooting the default install of Xamarin with Visual Studio 2017 and Windows 10 Creators Update

Since I’ve recently started using Xamarin for cross platform development, I thought it would be nice to share with the community how I’ve got past some of the issues which tripped me up for a while when I was becoming familiar with it. This isn’t really a normal “getting started with Xamarin” tutorial – there’s lots of them already out there already, like this one – but hopefully anyone starting off with Xamarin will find it useful.

I use Windows 10 (and have installed the Creator’s Update) – this allows me to use Xamarin.Forms. You’ll know if you’re on the Creator’s Update version if your Windows build number is 1703. If you’re on a different version of Windows, you might have different experiences to me (you can check your version by going to Windows Settings -> System -> About).

Before we begin – what’s Xamarin and why should I use it?

With Xamarin tools built into Visual Studio, developers can create native applications in C# for Windows, Mac and Linux devices. So instead of writing and managing three different codebases for three different platforms, developers can just write their code once and deploy it to different app-stores.

Installing Xamarin tools for Visual Studio 2017

With Visual Studio 2017, it’s very easy just open up the setup wizard, select the Xamarin tools (as shown below) and just wait for it to install.

vs_community_image

It’s probably going to take a long time to install VS2017 with Xamarin – adding Xamarin to the base Visual Studio install makes it about 25GB bigger.

Tip: If you leave your machine to download and install Xamarin, it’s worth adjusting your power settings to make sure an unattended machine doesn’t switch off in the middle of the download – like mine did the first time (facepalm).

Creating a project with the default Xamarin template

This bit is straightforward to anyone who’s created a new project in Visual Studio 2017 before.

Select File -> New Project to open the dialog below, and choose a name for the project:

screenshot.1

After clicking OK on the dialog above (which chooses a Cross Platform App project type), the dialog will close and open a new project. I chose to use Xamarin.Forms (which allows developers to create cross platform user interfaces). I also chose to create a Shared Project because I only expect my code to be used in my application, rather than shared with other developers as a Portable Class Library (you can read more about the differences between Shared Projects and Portable Class Libraries here).

screenshot.2

When you click OK, the project and files will be created, and a window like the one below will appear with instructions for setting up the Mac Agent. (I don’t have a Mac and I’d need Visual Studio Enterprise to use this anyway, so I normally click on the “Don’t show this again” box in the bottom left corner).

screenshot.3

Finally you’ll be prompted for the versions of Windows that you want the UWP flavour of your project to target. I normally just click OK here.

screenshot.4

At this point, you’ll have a simple Xamarin solution in Visual Studio 2017, which contains 4 projects – one for iOS, one for Android, one for UWP, and one shared project.

Also notice that there is one file open in VS2017 after you create the solution – App.xaml.cs in the shared project. I’ll explain why this is relevant later.

And now for the gremlins ex machina

After this point, I hit a few snags. Things I wanted to do that didn’t work out of the box for me were:

  • Compile the application without error or warnings
  • Run the application in a Windows Phone Emulator
  • Run the application in an Android Emulator

I’ll run through some of the symptoms of problems I encountered trying the things above, and how I fixed them.

Compiling the solution led to multiple warnings and errors

Tip: Prepare to wait a while when building the solution for the first time – it needs to download a lot of NuGet packages.

Unfortunately my attempt to compile the project out of the box showed an error in the UWP project and a bunch of warning messages for the Android project.

Getting rid of the error CS0103 –  ‘InitializeComponent’ does not exist in the current context

The error reports “The name ‘InitializeComponent’ does not exist in the current context.”

screenshot-7

I eventually noticed a couple of things that seemed a bit bizarre:

  • Even though I have an error, the message in the status bar in the bottom left reports “Rebuild All succeeded” – both can’t be right surely?
  • This error relates to the App.xaml.cs file which is open in the editor panel. When I opened Main.xaml.cs from the Shared Project in the VS2017 editor, I now see two errors (as shown in the image below).

screenshot.13

So these errors don’t seem to negatively affect the build, and if I really want to get rid of them, I can just close those files which gets rid of the errors (as shown below).

screenshot.11

Getting rid of warnings about $(TargetFrameworkVersion) mismatches

Three of the warnings I saw were very similar:

The $(TargetFrameworkVersion) for Xamarin.Forms.Platform.dll (v7.1) is 
greater than the $(TargetFrameworkVersion) for your project (v6.0). 
You need to increase the $(TargetFrameworkVersion) for your project.

The $(TargetFrameworkVersion) for Xamarin.Forms.Platform.Android.dll (v7.1) 
is greater than the $(TargetFrameworkVersion) for your project (v6.0). 
You need to increase the $(TargetFrameworkVersion) for your project.

The $(TargetFrameworkVersion) for FormsViewGroup.dll (v7.1) is greater 
than the $(TargetFrameworkVersion) for your project (v6.0). 
You need to increase the $(TargetFrameworkVersion) for your project.

The warning says I need to increase the TargetFrameworkVersion for my Android project, but when I look at the properties for this project, I actually can’t increase it past version 6 (MarshMallow).

screenshot.1

Fortunately we’re not at a dead end here – we can go to the Start Menu, and search for the “SDK Manager” for Android, which is installed with the Xamarin component of Visual Studio 2017 (shown below).

screenshot.2

Tip: Run the Android SDK Manager as administrator by right-clicking on the shortcut and select “More -> Run as administrator”. If you don’t run as administrator, you might get an error later when the program tries to create a temporary folder for downloads.

When I start the Android SDK Manager, it analyses the packages presently installed, and advises what needs to be updated. On my system, 10 packages needed to be installed or updated, as shown below.

screenshot.3

When I click on the “Install 10 packages…” button, another window appears asking me to accept the licence. I accepted the licence and clicked on “Install”.

screenshot.4

The installation and update procedure starts – this can take a few minutes.

screenshot.5

Once it’s finished installing, let’s return to Visual Studio 2017  –  I restarted it, and then cleaned and rebuilt the solution. This time the warnings about $(TargetFrameworkVersion) mismatches are gone.

Getting rid of warning IDE0006 – “Error encountered while loading the project”

I sometimes found that I had a warning IDE0006 which advised “Error encountered while loading the project. Some project features, such as full solution analysis for the failed project and projects that depend on it, have been disabled“.

screenshot.6

This usually happened just after I created a project, and I found that if I close VS2017, restart it, and re-open and rebuild the solution the warning disappears.

So to summarise, in order to compile the default project without errors or warnings:

  • Run the Android SDK manager as administrator, and install/update the recommended packages.
  • Restart Visual Studio 2017 and re-open the project.
  • Close all files from the shared project which have the type *.xaml.cs.

Running in your application in the Windows Phone Emulator

Tip: If you want to run your application in an emulator, you’ll definitely need a 64-bit machine which allows hardware virtualisation. Your machine will also need to be pretty powerful, or you might find running an emulator to be unbearably slow.

I found this to be straightforward as soon as I installed a Windows Phone emulator.

If you don’t have any Windows Phone emulators installed, you can grab some from here: https://developer.microsoft.com/en-us/windows/downloads/sdk-archive

I changed the start-up project to the UWP project, and changed the debugging target to be one of the Windows Phone Mobile emulators.

screenshot.14

After hitting play (or F5) to start running the Windows UWP application in a Windows Phone emulator, I was prompted to set my machine into Developer mode to allow me to load apps – I just had to select the third option (“Developer mode”) as shown in the image below (you can access this screen from Start -> Settings -> For developers).

screenshot.20

But after changing this setting, everything worked well – no gremlins here. The phone emulator starts up after a couple of minutes, and I was easily able to see the Xamarin application in the list of apps installed to the phone emulator.

screenshot.39

And when I run the Xamarin app in the emulator, I see the correct result – a simple form with a message saying “Welcome to Xamarin Forms!”

screenshot.40

Running your application in the Android Emulator

Visual Studio 2017 comes packaged with several Android Emulators – you can see them if you change the target project to the Android one, and look at the dropdown list on its right.

screenshot.15

Tip: I never use either the two emulators which target ARM. I have never managed to successfully deploy a project to one of these emulators, even with a reasonably powerful machine.

If you don’t believe me, Visual Studio even gives you a warning if you try to use them:screenshot.25

It’s much, much faster to target one of the emulators which targets x86.

Use the Android x86 emulator – but you need to turn Hyper-V off

You don’t need to uninstall Hyper-V to run the Android x86 emulator on Windows 10 – you just need to turn it off. The command to do this is very simple from a command prompt running as administrator:

bcdedit /set hypervisorlaunchtype off

Reboot for this setting change to take effect.

Of course it might not suit you to turn Hyper-V off on your machine – and another alternative is to deploy to an actual Android device – there’s some great instructions for this here: https://developer.xamarin.com/guides/android/getting_started/installation/set_up_device_for_development/

My experience was that I couldn’t successfully start and deploy my project to an Android emulator from Visual Studio 2017. However, I was able to start the Android emulator from the Android AVD Manager, available from the start menu (as shown below).

screenshot.16

When you start this program, you’ll see a dialog like the one below which lists the Android Virtual Devices available on your development machine.

screenshot.17

Select one of the x86 emulators, and click on the “Start…” button. Accept the default options on the launch screen, and an Android phone emulator will start.

screenshot.18

Now go back to Visual Studio 2017. Select the emulator which you’ve just started in the drop down list on the right of the green “Play” arror. Now right click on the Android project, and select “Deploy Solution”.

This should now deploy the Xamarin application to the Android emulator, as shown below (our app is in the top row, second column):

screenshot.19

And when we click on the Xamarin application icon in the emulator, as expected we see the same screen as in the Windows Phone emulator which says “Welcome to Xamarin Forms!”

screenshot.20

Wrapping up

This was just a quick post to help other Xamarin developers who are starting out avoid some of the headaches I had. And just to be really clear, I’m not criticising Xamarin or Visual Studio – getting code to work on 3 different platforms which are constantly changing and updating is pretty miraculous, and ultimately the things I had to do weren’t that big a deal to change.

There are already a few troubleshooting guides from Microsoft on Xamarin like this one. The tips below are things I didn’t find covered anywhere else.

  • Sometimes errors (for example, CS0103) are mis-reported by VS2017 for files which are open in the editor, particularly *.xaml.cs files from the Shared Project – try closing these files and rebuilding to see if the errors go away.
  • Other warnings appear after the project is first created (for example, IDE0006), but if you restart VS2017 and re-build the project, the warning disappears.
  • Opening the Android SDK Manager as administrator and updating the libraries you have on your development machine can help to remove warnings related to TargetFrameworkVersion mismatches – remember to restart VS2017 after the update, and then clean and rebuild your solution through VS2017.
  • Don’t use the Android ARM emulators on Windows 10 – instead start an x86 emulator from the Android AVD manager, and deploy from VS2017 to the emulator which is running.
  • If the x86 emulator won’t start, you might need to disable Hyper-V using the command “bcdedit /set hypervisorlaunchtype off“.

About me: I regularly post about .NET – if you’re interested, please follow me on Twitter, or have a look at my previous posts here. Thanks!