Blocks Based Bluetooth LE Connectivity framework for iOS/watchOS/tvOS/OSX. Quickly configure centrals & peripherals, perform read/write operations, and respond characteristic updates.

Overview

ExtendaBLE

Cocoapods Compatible Carthage compatible Build Status Platform License

alt tag

Introduction

ExtendaBLE provides a very flexible syntax for defining centrals and peripherals with ease. Following a blocks based builder approach you can easily create centrals, peripherals, associated services, characteristics, and define callbacks to listen for characteristic changes accordingly.

One of the unique features of ExtendaBLE is that it allows to bypass the limitations of the MTU size in communicating between devices. The library negotiates a common MTU size, and allows breaks down the data to be sent between devices into packets, which are then reconstructed by the receiving entity.

An Android library is in the works with support for packet based communication between iOS /tvOs/OSX. ExtendaBLE-Android, a work in progress can be found here..

ExtendaBLE-Android

Features

  • Blocks Syntax for Building Centrals and Peripherals
  • Callbacks for responding to, read and write, characteristic changes
  • Packet Based Payload transfer using negotiated MTU sizes
  • Characteristic Update Callbacks
  • Streamlined parsing for characteristic read operations

Installation

Communication

  • If you found a bug, or have a feature request, open an issue.
  • If you need help or a general question, use Stack Overflow. (tag 'extenda-ble')
  • If you want to contribute, review the Contribution Guidelines, and submit a pull request.

Basic Setup

In configuring BLE the first step is to configure a unique UUID for the shared a for the service(s) and characteristic(s) to intercommunicate between the peripheral & central.

For the purposes of documentation, the following constants will be shared across the configuration examples

let dataServiceUUIDKey                  = "3C215EBB-D3EF-4D7E-8E00-A700DFD6E9EF"
let dataServiceCharacteristicUUIDKey    = "830FEB83-C879-4B14-92E0-DF8CCDDD8D8F"

If you are not familiar with how BLE works, please review the Core Bluetooth Programming Guide before continuing.

Peripheral Manager

In it's simplest form, the following is an example of how to configure peripheral using a simple blocks based syntax.

peripheral = ExtendaBLE.newPeripheralManager { (manager) in

    manager.addService(dataServiceUUIDKey) { (service) in
        service.addCharacteristic(dataServiceCharacteristicUUIDKey) { (characteristic) in
            characteristic.properties([.read, .write]).permissions([.readable, .writeable])
        }
    }
}

Begin Advertising

To start advertising services and their respective characteristics, just call on startAdvertising() on the peripheral created in the prior section.

peripheral?.startAdvertising()

Responding to Updates

If you would like to respond to characteristic updates on the peripheral when a central updates a value, define an onUpdate { (data, error) in } per characteristic accordingly. When the Central finishes updating the value, the callback will be triggered.

peripheral = ExtendaBLE.newPeripheralManager { (manager) in
    manager.addService(dataServiceUUIDKey) { (service) in

        service.addCharacteristic(dataServiceCharacteristicUUIDKey) { (characteristic) in
            characteristic.properties([.read, .write, .notify]).permissions([.readable, .writeable])                

            characteristic.onUpdate { (data, error) in
                /* Called whenever the value is updated by the CENTRAL */
            }
        }
    }
}

Notifying Central

If you would like the peripheral to retain a connection for a specific characteristic, and notify the connected central manager when the value is updated, when configuring the properties, ensure to include the .notify CBCharacteristicProperty in the definition as follows.

peripheral = ExtendaBLE.newPeripheralManager { (manager) in

    manager.addService(dataServiceUUIDKey) { (service) in
        service.addCharacteristic(dataServiceCharacteristicUUIDKey) { (characteristic) in
            characteristic.properties([.read, .write, .notify]).permissions([.readable, .writeable])
        }
    }
}

Central Manager

In it's simplest form, the following is an example of how to configure central manager using a simple blocks based syntax.

central = ExtendaBLE.newCentralManager { (manager) in

    manager.addService(dataServiceUUIDKey) {(service) in
        service.addCharacteristic(dataServiceCharacteristicUUIDKey) { (characteristic) in
            characteristic.properties([.read, .write]).permissions([.readable, .writeable])
        }
    }
}

Begin Scanning

Start scanning for peripheral(s) defined with the services, and their respective characteristics, just call on startScan() on the central created in the prior section. The central will auto connect to the peripheral when found.

central?.startScan()

Responding to State Changes

Responding to stages of the scanning operation, the following callbacks can be defined for the manager.

central = ExtendaBLE.newCentralManager { (manager) in

    manager.addService(dataServiceUUIDKey) {(service) in
        /* Characteristic Definitions */
    }.onPeripheralConnectionChange{ (connected, peripheral, error) in
        /* Respond to Successful Connection */
    }.onDidDiscover { (central, advertisementData, rssi) in
        /* Respond to Discovered Services */
    }.onStateChange { (state) in
        /* Respond to State Changes */
    }
}

Respond to Successful Connection

To perform a Read/Write upon connecting to a peripheral, define a callback as follows to be notified of the successful connection.

central = ExtendaBLE.newCentralManager { (manager) in

    manager.addService(dataServiceUUIDKey) {(service) in
        service.addCharacteristic(dataServiceCharacteristicUUIDKey) { (characteristic) in
            characteristic.properties([.read, .write]).permissions([.readable, .writeable])
        }
    }.onPeripheralConnectionChange{ (connected, peripheral, error) in
        /* Perform Read Transaction upon connecting */
    }
}

Responding to Update Notification

If you would like to retain a connection for a specific characteristic, and be notified by the peripheral when the value is updated, when configuring the properties, ensure to include the .notify CBCharacteristicProperty in the definition as follows, and create a call back to respond to the change.

central = ExtendaBLE.newCentralManager { (manager) in

    manager.addService(dataServiceUUIDKey) {(service) in
        service.addCharacteristic(dataServiceCharacteristicUUIDKey) { (characteristic) in
            characteristic.properties([.read, .write, .notify]).permissions([.readable, .writeable])

            characteristic.onUpdate { (data, error) in
                /* Called whenever the value is updated by the PERIPHERAL */
            }
        }
    }
}

Perform Write

To perform a write for a specific characteristic for a connected peripheral, call the write(..) on the central, and with the content to write, and the characteristicUUID to write to. The callback will be triggered once the write is complete.

central?.write(data: stringData, toUUID: dataServiceCharacteristicUUIDKey) { (writtenData, error) in    

    /* Do something upon successful write operation */
}

Perform Read

To perform a read for a specific characteristic for a connected peripheral, call the read(..) on the central, and with the characteristicUUID to read. The callback will be triggered once the read is complete with the Data read, or an error if the operation failed.

central?.read(characteristicUUID: dataServiceCharacteristicUUIDKey) { (returnedData, error) in
    let valueString = String(data: returnedData!, encoding: .utf8)?

    /* Do something upon successful read operation */  
}

Packet Based Communication

BLE has a limitation as to how much data can be sent between devices relative to the MTU size. To enabled the ability for the central and peripheral to communicate characteristic data greater in size than this limitation, ExtendaBLE provides the ability to use packets to breakup and rebuild the data when communicating between devices.

To enable the ability to send data greater than the MTU limitation of BLE, set the packetsEnabled to true on both the peripheral and the central. This will ensure that when communications occurs, the data is broken up into individual packets which will be sent across and rebuilt once the operation is complete.

peripheral = ExtendaBLE.newPeripheralManager { (manager) in

    manager.addService(dataServiceUUIDKey) { (service) in
        service.addCharacteristic(dataServiceCharacteristicUUIDKey) { (characteristic) in
            characteristic.properties([.read, .write])
            characteristic.permissions([.readable, .writeable])
            characteristic.packetsEnabled(true)
        }
    }
}

central = ExtendaBLE.newCentralManager { (manager) in

    manager.addService(dataServiceUUIDKey) {(service) in
        service.addCharacteristic(dataServiceCharacteristicUUIDKey) { (characteristic) in
            characteristic.properties([.read, .write])
            characteristic.permissions([.readable, .writeable])     
            characteristic.packetsEnabled(true)
        }
    }
}

Extracting Data from Byte Stream

When communicating reading from physical peripheral, generally the specifications will return a byte stream, and will identify where different types of data are located, and it is up to the developer to extract and covert specific parts of the returned data. With ExtendaBLE and extension is included to easily extract data from such streams. The following methods can be called on the returned Data instance with a specified start index to extract the following types of data.

public func int8Value(atIndex : Int) -> Int8?
public func int16Value(atIndex : Int) -> Int16?
public func int32Value(atIndex : Int) -> Int32?
public func int64Value(atIndex : Int) -> Int64?
public func uint8Value(atIndex : Int) -> UInt8?
public func uint16Value(atIndex : Int) -> UInt16?
public func uint32Value(atIndex : Int) -> UInt32?
public func uint64Value(atIndex : Int) -> UInt64?
public func stringValue(atIndex : Int) -> String?

If finer control is needed, ranges can be used to extract specific data from the stream as follows.

public func int8Value(inRange range : Range<Data.Index>) -> Int8?
public func int16Value(inRange range : Range<Data.Index>) -> Int16?
public func int32Value(inRange range : Range<Data.Index>) -> Int32?
public func int64Value(inRange range : Range<Data.Index>) -> Int64?
public func uint8Value(inRange range : Range<Data.Index>) -> UInt8?
public func uint16Value(inRange range : Range<Data.Index>) -> UInt16?
public func uint32Value(inRange range : Range<Data.Index>) -> UInt32?
public func uint64Value(inRange range : Range<Data.Index>) -> UInt64?
public func doubleValue(inRange range : Range<Data.Index>) -> Double?
public func floatValue(inRange range : Range<Data.Index>) -> Float?
public func stringValue(inRange range : Range<Data.Index>) -> String?
You might also like...
Omnipod Bluetooth PumpManager For Loop

OmniBLE Omnipod Bluetooth PumpManager For Loop Status This module is at the very beginning stages of development and does not even compile yet. DO NOT

Diabetes: test the FreeStyle Libre glucose sensor as a Bluetooth Low Energy device, even directly from an Apple Watch.
Diabetes: test the FreeStyle Libre glucose sensor as a Bluetooth Low Energy device, even directly from an Apple Watch.

Since the FreeStyle Libre 2 / 3 glucose sensors are Bluetooth Low Energy devices, I am trying to leverage their capabilities to implement something ne

Bluetooth mapping in Swift
Bluetooth mapping in Swift

Bluetonium is part of the E-sites iOS Suite. Bluetonium is a Swift Library that makes it easy to communicate with Bluetooth devices. Features 🎲 Servi

Bluetooth mesh messaging SDK for apps

Berkanan SDK Berkanan SDK enables Bluetooth mesh messaging between nearby apps. It's the framework used by Berkanan Messenger (Product Hunt, TechCrunc

MiniVendingMachine - SwiftUI demo Apple Watch app to open a mini vending machine via bluetooth

Mini Vending Machine Use Apple Watch to open vending machine cells. Note: This a

CombineCoreBluetooth is a library that bridges Apple's CoreBluetooth framework and Apple's Combine framework

CombineCoreBluetooth is a library that bridges Apple's CoreBluetooth framework and Apple's Combine framework, making it possible to subscribe to perform bluetooth operations while subscribing to a publisher of the results of those operations, instead of relying on implementing delegates and manually filtering for the results you need.

SwiftyBluetooth - Closures based APIs for CoreBluetooth.

SwiftyBluetooth Closures based APIs for CoreBluetooth. Features Replace the delegate based interface with a closure based interface for every CBCentra

A simple framework that brings Apple devices together - like a family
A simple framework that brings Apple devices together - like a family

Apple Family A simple framework that brings Apple devices together - like a family. It will automatically use bluetooth, wifi, or USB to connect and c

Functional wrapper for Apple's MultipeerConnectivity framework.

A functional wrapper for the MultipeerConnectivity framework. PeerConnectivity is meant to have a lightweight easy to use syntax, be extensible and fl

Owner
Anton
Lead Mobile Architect / Engineer
Anton
AZPeerToPeerConnectivity is a wrapper on top of Apple iOS Multipeer Connectivity framework. It provides an easier way to create and manage sessions. Easy to integrate

AZPeerToPeerConnection Controller Features Multipeer Connectivity Connection via Bluetooth or Wifi No need write all session, browser, services delega

Afroz Zaheer 66 Dec 19, 2022
An open-source Swift framework for building event-driven, zero-config Multipeer Connectivity apps

PeerKit An open-source Swift framework for building event-driven, zero-config Multipeer Connectivity apps Usage // Automatically detect and attach to

JP Simard 861 Dec 23, 2022
Simple, block-based, lightweight library over CoreBluetooth. Will clean up your Core Bluetooth related code.

LGBluetooth Simple, block-based, lightweight library over CoreBluetooth. Steps to start using Drag and Drop it into your project Import "LGBluetooth.h

null 170 Sep 19, 2022
iOS Bluetooth LE framework

Features A futures interface replacing protocol implementations. Timeout for Peripheral connection, Service scan, Service + Characteristic discovery a

Troy Stribling 696 Dec 25, 2022
Bluejay is a simple Swift framework for building reliable Bluetooth LE apps.

Bluejay is a simple Swift framework for building reliable Bluetooth LE apps. Bluejay's primary goals are: Simplify talking to a single Bluetooth LE pe

Steamclock Software 1k Dec 13, 2022
Build your own 'AirTags' 🏷 today! Framework for tracking personal Bluetooth devices via Apple's massive Find My network.

OpenHaystack is a framework for tracking personal Bluetooth devices via Apple's massive Find My network.

Secure Mobile Networking Lab 5.8k Jan 9, 2023
The Bluetooth LE library for iOS and Mac. 100% Swift.

iOS-BLE-Library An in-development Bluetooth Low Energy Library by Nordic Semiconductor to interact with the , which is not complicated, but requires w

Nordic Semiconductor 6 Dec 19, 2022
The easiest way to use Bluetooth (BLE )in ios,even bady can use.

The easiest way to use Bluetooth (BLE )in ios,even bady can use.

刘彦玮 4.6k Dec 27, 2022
Fluetooth - Flutter library for sending bytes to Bluetooth devices on Android/iOS

A Flutter library for sending bytes to Bluetooth devices. Available on Android a

Iandi Santulus 1 Jan 2, 2022
RxBluetoothKit is a Bluetooth library that makes interaction with BLE devices much more pleasant.

RxBluetoothKit is a Bluetooth library that makes interaction with BLE devices much more pleasant. It's backed by RxSwift and CoreBluetooth and it prov

Polidea 1.3k Jan 6, 2023