Core Bluetooth in watchOS Tutorial
Learn how to communicate with external BLE devices from within watchOS in this Core Bluetooth tutorial! By Audrey Tam.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Core Bluetooth in watchOS Tutorial
30 mins
- Getting Started
- What is Core Bluetooth?
- Overview
- Central Manager
- Peripheral Manager
- Central Manager Delegate Protocol
- Peripheral Manager Delegate Protocol
- Peripheral Delegate Protocol
- watchOS vs iOS
- Building the Watch App
- Creating the Interface
- Reduce the Amount of Text to Send
- Copy-Pasting and Editing CentralViewController code
- Where to Go From Here?
Core Bluetooth has been around since 2011 on macOS and iOS, since 2016 on tvOS, and now it’s available on watchOS, with an Apple Watch Series 2.
What’s Core Bluetooth? It’s Apple’s framework for communicating with devices that support Bluetooth 4.0 low-energy, often abbreviated as BLE. And it opened up standard communication protocols to read and/or write from external devices.
Back in 2011, there weren’t many BLE devices, but now? Well, this is from the Bluetooth site (bit.ly/2j1DqpU):
“More than 31,000 Bluetooth member companies introducing over 17,000 thousand new products per year and shipping more than 3.4 billion units each year.”
BLE is everywhere: in health monitors, home appliances, fitness equipment, Arduino and toys. In July 2017, Apple announced its collaboration with hearing-aid implant manufacturer Cochlear, to create the first “Made for iPhone” implant. (bit.ly/2vZahUU)
But you don’t have to acquire a specific gadget to work through this tutorial: the sample project uses an iPhone as the BLE device. In the app you’ll build, the iOS device provides a two-part service: it transfers text to the Watch, or the Watch can open Maps at the user’s location on the iOS device.
The first part is a Swift translation of Apple’s BLE_Transfer sample app. It’s a very useful example, because it shows how to send 20-byte chunks of data. I added the Maps part to show you how to send a control instruction to the BLE device, and I thought it’s something you’d want to do from the Watch Maps app: open Maps on a larger display so you can find what you need more easily!
Getting Started
Download the starter app for this tutorial here.
Open the starter app. Build and run on two iOS devices. Go into Settings to trust the developer, then build and run again.
Select Peripheral Mode on one device, and Central Mode on the other. Tap the peripheral’s Advertising switch to start advertising.
PeripheralViewController
has a textView
, prepopulated with some text. When the central manager subscribes to textCharacteristic
, the peripheral sends this text in 20-byte chunks to the central, where it appears in a textView
:
Modify the peripheral’s text, and tap Done. The peripheral sends the updated value to the central:
When the central has discovered mapCharacteristic
, CentralViewController
bar button’s title changes to Map Me. Tap this bar button, allow the app to use your location, then tap Map Me again: the peripheral device opens the Maps app, at your location:
Stop the app on both devices. It’s time to learn about Core Bluetooth, and look at some code!
What is Core Bluetooth?
Lets’s start with some vocabulary.
A Generic Attributes (GATT) profile describes how to bundle, present and transfer data using Bluetooth Low Energy. It describes a use case, roles and general behaviors. A device’s GATT database can describe a hierarchy of services, characteristics and attributes.
The classic server/client roles are the central app and the peripheral or accessory. In the starter app, either iOS device can be central or peripheral. When you build the Watch app, it can only be the central device:
A peripheral offers services. For example, Blood Pressure monitor is a pre-defined GATT service (bit.ly/2lfpqwB). In the starter app, the service is TextOrMap
.
A service has characteristics. The Blood Pressure service has pre-defined GATT characteristics (bit.ly/2vOhGqa): Blood Pressure Feature, which blood pressure monitor features this sensor supports, and Blood Pressure Measurement. A characteristic has a value, properties to indicate operations the characteristic supports, and security permissions.
A central app can read or write a service’s characteristics, such as reading the user’s heart rate from a heart-rate monitor, or writing the user’s preferred temperature to a room heater/cooler. In the starter app, the TextOrMap
service has two characteristics: the peripheral sends updates of the textCharacteristic
value to the central; when the central writes the mapCharacteristic
value, the peripheral opens the Maps app at the user’s location.
Services and characteristics have UUIDs: universally unique identifiers. There are predefined UUIDs for standard peripheral devices, like heart monitors or home appliances. You can use the command line utility uuidgen
to create custom UUID strings, then use these to initialize CBUUID
objects.
The Maximum Transmission Unit (MTU) is 27 bytes, but really 20 bytes, because each packet uses 7 bytes as it travels through three protocol layers. You can improve throughput using write without response, if the characteristic allows this, because you don’t have to wait for the peripheral’s response. If your central app and peripheral are running on iPhone 7, the new iPad Pro, or Apple Watch Series 2, you get the Extended Data Length of 251 bytes! I’m testing the sample app on an iPhone SE, so I’m stuck with 20-byte chunks.
Overview
The most interesting classes in the Core Bluetooth framework are CBCentralManager
and CBPeripheralManager
. Each has methods and a comprehensive delegate protocol, to monitor activity between central and peripheral devices. There’s also a peripheral delegate protocol. Everything comes together in an intricate dance!
Think about what the devices need to do:
- Central devices need to scan for and connect to peripherals. Peripherals need to advertise their services.
- Once connected, the central device needs to discover the peripheral’s services and characteristics, using peripheral delegate methods. Often at this point, an app might present a list of these for the user to select from.
- If the central app is interested in a characteristic, it can subscribe to notifications of updates to the characteristic’s value, or send a read/write request to the peripheral. The peripheral then responds by sending data to the central device, or doing something with the write request’s value. The central app receives updated data from another peripheral delegate method, and usually uses this to update its UI.
- Eventually, the central device might disable a notification, triggering delegate methods of the peripheral and the peripheral manager. Or the central device disconnects the peripheral, which triggers a central manager delegate method, usually used to clean up.
Now look at what each participant does.