This article originally appeared on June 27, 2017.
Apple’s iBeacon protocol has been around for quite some time and is working all around you, even if you don't see it. It’s pretty much the technological advancement of the QR code or standard barcode, emitting some sort of data package to any device that can pick it up via Bluetooth. Computers and smartphones can pick these beacons up, but what about new technology? Specifically, mixed and augmented reality devices such as HoloLens.
First, you’re going to need a couple of things. Unity3D (Version 5.5.2 or later), Visual Studio 2015 or later with .NET 4, and HoloLens with the latest firmware. An actual device is needed to test this as the simulator doesn't pick it up. You’ll also need to find and download the Windows.Devices.Bluetooth Dynamic-Link Library (DLL) from Microsoft directly. I’ll explain how to use it later.
How it works
For this to work, you’ll have to follow a process. Unity only technically supports .NET 3.5 and earlier. So we’ll have to create a DLL that’s .NET 4.0-based to use the Windows.Devices.Bluetooth namespace alongside it. We’ll call it the HoloBeaconScanner DLL.
- Your Unity app will call the HoloBeaconScanner DLL I built, set up a scanner, register the beacon-found event handler and start scanning.
- Once a beacon comes into range, we’ll grab the data bytes and format them DLL-side.
- Then, when we have everything formatted the way we want, we’ll invoke an event handler that currently sends back a string delimited by a ‘*’ (star character). In the future, I’ll modify it with a dictionary or JSON package, but for now we’ll create a delimited string.
In the diagram below, I show you how everything is talking to one another.
Custom DLL download
You can go ahead and download the actual HoloBeaconScanner.dll file.
Setting up our project
- Open Unity and start a new project.
- Make sure your build settings are targeting the Windows Store with the HoloLens properties.
Under your Assets folder, create a new folder called Plugins.
In this Plugins folder, copy the HoloBeaconScanner.dll.
Click on the DLL in Unity to see the DLL Import Settings. You should only select WSAPlayer and change the Platform settings like this:
Under Plugins, create a folder called WSA.
In the WSA folder, place the Windows.Devices.Bluetooth.dll file.
Click on the DLL in Unity to see the Import Settings. You should see that everything is selected, which is fine. It will look like this
Dive into code.
Now we’re ready to jump into the code on the Unity side. Note that we’re going to wrap anything that calls the DLL in #if !UNITY_EDITOR, and this is mainly so the Unity Engine knows we don't want to compile that bit of code while in the editor. If you don't have this, the code won’t build. You can read more about Platform Dependent Compilation on the Unity3D website.
- First, let’s create a new C# script and call it BeaconDetector.
- Then, let’s set the namespace:
- Next, let’s set a global scanner class so we can start and stop it from a public function. We’ll also initialize it in the Start() function. As you can see, the scanner class has an event handler on it called ScannedBeaconEventHandler. So we want to attach to that handler with our BeaconFound method.
- Set up our public functions for the UI to attach to. We want a few buttons that can link to the start and stop methods of the beacon scanner.
- Set up our found beacon event. The DLL is going to return a delimited string every time a beacon is scanned and found. The delimited string should contain our UUID, Major, Minor, Power and the Distance Value. Finally, I set up a simple class called Beacon so we can store all of the data we collect from the scanner. Here’s what it looks like. Now when you run it on HoloLens and a beacon is in range, you’ll be able to see if picking up the beacon info printed in the console.
A big side note: If you want to update the UI, you’re going to have to do it from the main thread. So, you would want to run UI updates in a fixed update method or pass the information to another class to update the main thread.
Personally, I added a second class that created a pool of beacons the scanner found and then used that pool elsewhere.
Here's an example of what I did with some of the UI elements and what it looks like in a HUD-like environment.