So You Want to Build a Bluetooth App with React Native and Expo

So You Want to Build a Bluetooth App with React Native and Expo

A step-by-step guide by Adrian Carolli.

Let’s say you’re starting your next project, and your app is Bluetooth-based. Which means you have to connect to a Bluetooth-enabled device. At Penta Medical, we use React Native and various libraries to connect to our Bluetooth Low Energy (BLE) device without having to write much native code. Here’s a quick guide to help you accomplish all of this with React Native and Expo. (Before we begin, you should know that this method will only work for BLE devices and not Bluetooth classic devices.)

Part 1 — Ejecting Expo and Bluetooth

This guide is Part One of a planned three-part series. In this first part, we focus on ejecting Expo and setting up React Native to interface with the Bluetooth capabilities of the phone. In the second part, we’ll explore a simple Bluetooth app, and in the third, we’ll re-build the same app using Expo’s future Bluetooth API. Here’s a quick overview of what we’ll cover today:


  1. Introduction
  2. Eject Expo
  3. iOS setup
  4. Android setup
  5. Conclusion
  6. Who to ask for help
  7. Troubleshooting

1 — Introduction

As many developers have, Expo was the first place we looked for a Bluetooth API. It only made sense to turn to them as they provide a ton of useful JavaScript APIs that interact with a mobile device. But lo and behold our Google search left us empty handed. There is no Bluetooth API for Expo yet, but you can still build a Bluetooth app with Expo.

As soon as we discovered this, we made a feature request on Canny for an Expo Bluetooth API. Canny is the best way to get the features you care about prioritized on the Expo roadmap.

2 — Eject Expo

But maybe you’re like us and you need Bluetooth and you need it now. You can still use Expo, but there is a catch, you will need to eject your Expo project. Yes, you heard me right.

Before we dive into ejecting your Expo project let’s talk about the challenges of ejecting expo. Here are some of them:

- Adding native libraries requires a great deal of Xcode and Android Studio setup (the focus of this guide).

- Expo makes your life easier, but when you eject Expo some of that easiness goes away. For example, getting setup and getting the app on your phone.

- Installing your project is no longer as easy as npm install

So, if Expo builds a Bluetooth API it will make our life much easier, but for now we must use the libraries at our disposal. There is a library called React Native BLE Plx built by a company called Polidea. We are going to use this library to interact with the Bluetooth capabilities of the mobile device. Since this library adds custom native modules we must eject our Expo project. This allows us to use ExpoKit to add custom native modules. Let’s get started.

Step 1

Before we begin its a good idea to update your Mac OS to the latest version. Additionally, you will need Xcode and the Command Line Tools which come with Xcode. You can get Xcode here and or update Xcode to the latest version in the App Store.

Lastly, open `Xcode` → `Preferences` → `Locations` and ensure you have the Command Line Tools setup like the below image.

Image for post
Step 1 in Xcode

From this point on I am assuming you have an Expo project setup. For example, you used `expo-cli` or similar as a starting point for your app. For example:

npm install -g expo-cli
mkdir ~/workspace
cd ~/workspace
expo init myapp

And have changed directories into your app like so `cd ~/workspace/myapp`.

Step 2

If you don’t have it, run `npm install -g expo` to get the expo command line library. If you haven’t used `expo`, the first thing you’ll need to do is log in with your Expo account using `expo login`.

Step 3

Ejecting requires the same keys as building a standalone app. Follow these instructions before continuing to the next step. The important keys are: `bundleIdentifier`, `package`, `name`, `icon`, `version`, `slug` and `sdkVersion`.

Step 4

From your project directory, run `expo eject`. This will download the required dependencies and build native projects under the `ios` and `android` directories.

Install `react-native-cli` CLI tools if you don’t have it like so: `npm install -g react-native-cli`.

We can now add third-party native modules for React Native, non-Expo-specific instructions such as `react-native link` will work. We will need to use this command to use `react-native-ble-plx`.

Step 5

From your project directory, we need to install `react-native-ble-plx` to do so run `npm install react-native-ble-plx --save`.

Step 6

Now we link the native dependency like so `react-native link react-native-ble-plx`, a command we are only allowed to use because we have ejected Expo.

Unfortunately, `react-native link` is not fully automatic. From this point on we will need to set-up Android and iOS manually.

3 — iOS Setup

Let’s set up the project for iOS. The minimal supported version of iOS is 8.0.

Step 1

In Xcode, add an empty Swift file if you don’t have at least one:

- Select File/New/File…

- Choose Swift file and click Next.

- Name it however you want, select your application target and create it.

- Accept to create Objective-C bridging header.

Step 2

In a terminal from your project directory install `cocoapods` like so:

sudo gem install cocoapods
pod setup

Step 3

Update your `ios/Podfile` to contain:

pod 'react-native-ble-plx', :path => '../node_modules/react-native-
pod 'react-native-ble-plx-swift', :path => '../node_modules/react-

Step 4

Then from your project directory install the pods in the `ios` directory:

cd ./ios
pod install

Step 5

Optionally, if you want to support background mode:

- In your application target go to the `Capabilities` . →.`Background Modes` → Enable `Uses Bluetooth LE Accessories`.

- Pass `restoreStateIdentifier` and `restoreStateFunction` to the `BleManager` constructor.

Image for post
Step 6 in Xcode

Step 6

Now in Xcode you can build the project, `Product` → `Build` and then run the project `Product` → `Run`. If you get warnings thats okay, but if you get errors see the troubleshooting section below.

4 — Android Setup

Let’s setup the project for Android.

Step 1

Install Android Studio here. Choose the standard setup.

Image for post
Step 1 in Android Studio

Step 2

In `android/app/build.gradle`, ensure that the min SDK version is at least 18:

android {
     defaultConfig {
            minSdkVersion 18

Step 3

In `android/app/src/main/AndroidManifest.xml`, add Bluetooth permissions and update `<uses-sdk/>`:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        <uses-permission android:name="android.permission.BLUETOOTH"/>

<!-- Add this line if your application always requires BLE. More
info can be found on:

        <uses-feature android:name="android.hardware.bluetooth_le"


Step 4

Connect your phone via USB. In a terminal, go to `cd ~/Library/Android/sdk/platform-tools/` and run `./adb devices` to ensure that your device shows up.

From your project directory run `react-native run-android` to test that the app installs on your phone.

5 — Conclusion

I hope you haven’t lost too much hair as that was a lot of setup! Hopefully, when Expo builds a Bluetooth API, it’ll make this process much easier, at which point we’ll explore it in the third part of this series. And in the second part we’ll build a simple Bluetooth app using `react-native-ble-plx` and Expo. For now, check out the documentation to learn more about this useful library we setup.

6 — Who to ask for help

- If you have an Expo specific question, post your question on Expo’s forum. If you need live help check out the `#bluetooth` channel on Expo’s Slack.

- If you have a `react-native-ble-plx` specific question post a Github issue here. The team at Polidea is very helpful.

- Lastly, give me a follow on Twitter and tweet or DM me any questions. I tend to be very active on Twitter.

7 — Troubleshooting

- `Runtime Error: SIGABRT on fileprivate var connectedDevices = Dictionary<UUID, Peripheral>()` — see this Github issue

- `RCTDefines not found` — You forgot to add the Header Build paths (see instructions above)

- `RCTBridgeModule.h not found`— Check the header search path and make sure its not using ./nvm caches. If needed re-clone the project and make sure you `npm cache clean` before you install everything

- `RCTBluetoothManager not found` — first make sure you opened `yourappname.xcworkspace` not `yourappname.xcodeproj`. If that doesn’t work try rebuilding by doing `cd ./node_modules/react-native-ble-plx` then `./build_ios_frameworks.sh`

- `RCTDefines not found in RNDeviceInfo`— You forgot to add the header build path `${SRCROOT}/../../../ios/Pods/Headers/Public` and should do a `npm cache clean` and then restart your computer and build again

- `No visible @interface for 'RCTAsyncLocalStorage' declares the selector 'initWithStorageDirectory:` — see this Github issue

Looking forward to building a Bluetooth app with Expo? Follow our guest blogger Adrian Carolli on Github and Twitter to keep updated.

Related Articles