iOS Bluetooth LE framework

Overview

Build Status CocoaPods Compatible Platform License Carthage Compatible

BlueCap: Swifter CoreBluetooth

Features

  • A futures interface replacing protocol implementations.
  • Timeout for Peripheral connection, Service scan, Service + Characteristic discovery and Characteristic read/write.
  • A DSL for specification of GATT profiles.
  • Characteristic profile types encapsulating serialization and deserialization.
  • Example applications implementing CentralManager and PeripheralManager.
  • A full featured extendable scanner and Peripheral simulator available in the App Store.
  • Thread safe.
  • Comprehensive test coverage.

Requirements

  • iOS 12.0+
  • Xcode 11.3.1

Installation

CocoaPods

CocoaPods is an Xcode dependency manager. It is installed with the following command,

gem install cocoapods

Requires CocoaPods 1.1+

Add BluCapKit to your to your project Podfile,

platform :ios, '10.0'
use_frameworks!

target 'Your Target Name' do
  pod 'BlueCapKit', '~> 0.7'
end

To enable DBUG output add this post_install hook to your Podfile

Carthage

Carthage is a decentralized dependency manager for Xcode projects. It can be installed using Homebrew,

brew update
brew install carthage

To add BlueCapKit to your Cartfile

github "troystribling/BlueCap" ~> 0.7

To download and build BlueCapKit.framework run the command,

carthage update

then add BlueCapKit.framework to your project.

If desired use the --no-build option,

carthage update --no-build

This will only download BlueCapKit. Then follow the steps in Manual to add it to a project.

Manual

  1. Place the BlueCap somewhere in your project directory. You can either copy it or add it as a git submodule.
  2. Open the BlueCap project folder and drag BlueCapKit.xcodeproj into the project navigator of your applications Xcode project.
  3. Under your Projects Info tab set the iOS Deployment Target to 9.0 and verify that the BlueCapKit.xcodeproj iOS Deployment Target is also 9.0.
  4. Under the General tab for your project target add the top BlueCapKit.framework as an Embedded Binary.
  5. Under the Build Phases tab add BlueCapKit.framework as a Target Dependency and under Link Binary With Libraries add CoreLocation.framework and CoreBluetooth.framework.

Getting Started

With BlueCap it is possible to easily implement CentralManager and PeripheralManager applications, serialize and deserialize messages exchanged with Bluetooth devices and define reusable GATT profile definitions. The BlueCap asynchronous interface uses Futures instead of the usual block interface or the protocol-delegate pattern. Futures can be chained with the result of the previous passed as input to the next. This simplifies application implementation because the persistence of state between asynchronous calls is eliminated and code will not be distributed over multiple files, which is the case for protocol-delegate, or be deeply nested, which is the case for block interfaces. In this section a brief overview of how an application is constructed will be given. Following sections will describe supported use cases. Example applications are also available.

CentralManager

A simple CentralManager implementation that scans for Peripherals advertising a TiSensorTag Accelerometer Service, connects on peripheral discovery, discovers service and characteristics and subscribes to accelerometer data updates will be described.

All applications begin by calling CentralManager#whenStateChanges.

let manager = CentralManager(options: [CBCentralManagerOptionRestoreIdentifierKey : "us.gnos.BlueCap.central-manager-documentation" as NSString])

let stateChangeFuture = manager.whenStateChanges()

To start scanning for Peripherals advertising the TiSensorTag Accelerometer Service follow whenStateChanges() with CentralManager#startScanning and combine the two with the SimpleFutures FutureStream#flatMap combinator. An application error object is also defined,

public enum AppError : Error {
    case invalidState
    case resetting
    case poweredOff
    case unknown
    case unlikely
}

let serviceUUID = CBUUID(string: TISensorTag.AccelerometerService.uuid)

let scanFuture = stateChangeFuture.flatMap { [weak manager] state -> FutureStream<Peripheral> in
    guard let manager = manager else {
        throw AppError.unlikely
    }
    switch state {
    case .poweredOn:
        return manager.startScanning(forServiceUUIDs: [serviceUUID])
    case .poweredOff:
        throw AppError.poweredOff
    case .unauthorized, .unsupported:
        throw AppError.invalidState
    case .resetting:
        throw AppError.resetting
    case .unknown:
        throw AppError.unknown
    }
}

scanFuture.onFailure { [weak manager] error in
    guard let appError = error as? AppError else {
        return
    }
    switch appError {
    case .invalidState:
	break
    case .resetting:
        manager?.reset()
    case .poweredOff:
        break
    case .unknown:
        break
    }
}

Here when .poweredOn is received the scan is started. On all other state changes the appropriate error is thrown and handled in the error handler.

To connect discovered peripherals the scan is followed by Peripheral#connect and combined with FutureStream#flatMap,

var peripheral: Peripheral?

let connectionFuture = scanFuture.flatMap { [weak manager] discoveredPeripheral  -> FutureStream<Void> in
    manager?.stopScanning()
    peripheral = discoveredPeripheral
    return peripheral.connect(connectionTimeout: 10.0)
}

Here the scan is also stopped after a peripheral with the desired service UUID is discovered.

The Peripheral Services and Characteristics need to be discovered and the connection errors need to be handled. Service and Characteristic discovery are performed by 'Peripheral#discoverServices' and Service#discoverCharacteristics and more errors are added to AppError.

public enum AppError : Error {
    case dataCharactertisticNotFound
    case enabledCharactertisticNotFound
    case updateCharactertisticNotFound
    case serviceNotFound
    case invalidState
    case resetting
    case poweredOff
    case unknown
    case unlikely
}

let discoveryFuture = connectionFuture.flatMap { [weak peripheral] () -> Future<Void> in
    guard let peripheral = peripheral else {
        throw AppError.unlikely
    }
    return peripheral.discoverServices([serviceUUID])
}.flatMap { [weak peripheral] () -> Future<Void> in
    guard let peripheral = peripheral, let service = peripheral.services(withUUID: serviceUUID)?.first else {
        throw AppError.serviceNotFound
    }
    return service.discoverCharacteristics([dataUUID, enabledUUID, updatePeriodUUID])
}

discoveryFuture.onFailure { [weak peripheral] error in
    switch error {
    case PeripheralError.disconnected:
        peripheral?.reconnect()
    case AppError.serviceNotFound:
        break
    default:
	break
    }
}

Here a reconnect attempt is made if the Peripheral is disconnected and the AppError.serviceNotFound error is handled. Finally read and subscribe to the data Characteristic and handle the dataCharactertisticNotFound.

public enum AppError : Error {
    case dataCharactertisticNotFound
    case enabledCharactertisticNotFound
    case updateCharactertisticNotFound
    case serviceNotFound
    case invalidState
    case resetting
    case poweredOff
    case unknown
}

var accelerometerDataCharacteristic: Characteristic?

let subscriptionFuture = discoveryFuture.flatMap { [weak peripheral] () -> Future<Void> in
   guard let peripheral = peripheral, let service = peripheral.services(withUUID: serviceUUID)?.first else {
        throw AppError.serviceNotFound
    }
    guard let dataCharacteristic = service.service.characteristics(withUUID: dataUUID)?.first else {
        throw AppError.dataCharactertisticNotFound
    }
    accelerometerDataCharacteristic = dataCharacteristic
    return dataCharacteristic.read(timeout: 10.0)
}.flatMap { [weak accelerometerDataCharacteristic] () -> Future<Void> in
    guard let accelerometerDataCharacteristic = accelerometerDataCharacteristic else {
        throw AppError.dataCharactertisticNotFound
    }
    return accelerometerDataCharacteristic.startNotifying()
}.flatMap { [weak accelerometerDataCharacteristic] () -> FutureStream<Data?> in
    guard let accelerometerDataCharacteristic = accelerometerDataCharacteristic else {
        throw AppError.dataCharactertisticNotFound
    }
    return accelerometerDataCharacteristic.receiveNotificationUpdates(capacity: 10)
}

dataUpdateFuture.onFailure { [weak peripheral] error in
    switch error {
    case PeripheralError.disconnected:
        peripheral?.reconnect()
    case AppError.serviceNotFound:
        break
    case AppError.dataCharactertisticNotFound:
	break
    default:
	break
    }
}

These examples can be written as a single flatMap chain as shown in the CentralManager Example.

PeripheralManager

A simple PeripheralManager application that emulates a TiSensorTag Accelerometer Service supporting all Characteristics will be described. It will advertise the service and respond to characteristic write requests on the writable Characteristics.

First the Characteristics and Service are created and the Characteristics are then added to Service

// create accelerometer service
let accelerometerService = MutableService(uuid: TISensorTag.AccelerometerService.uuid)

// create accelerometer data characteristic
let accelerometerDataCharacteristic = MutableCharacteristic(profile: RawArrayCharacteristicProfile<TISensorTag.AccelerometerService.Data>())

// create accelerometer enabled characteristic
let accelerometerEnabledCharacteristic = MutableCharacteristic(profile: RawCharacteristicProfile<TISensorTag.AccelerometerService.Enabled>())

// create accelerometer update period characteristic
let accelerometerUpdatePeriodCharacteristic = MutableCharacteristic(profile: RawCharacteristicProfile<TISensorTag.AccelerometerService.UpdatePeriod>())

// add characteristics to service
accelerometerService.characteristics = [accelerometerDataCharacteristic, accelerometerEnabledCharacteristic, accelerometerUpdatePeriodCharacteristic]

Next create the PeripheralManager add the Service and start advertising.

enum AppError: Error {
    case invalidState
    case resetting
    case poweredOff
    case unsupported
    case unlikely
}

let manager = PeripheralManager(options: [CBPeripheralManagerOptionRestoreIdentifierKey : "us.gnos.BlueCap.peripheral-manager-documentation" as NSString])

let startAdvertiseFuture = manager.whenStateChanges().flatMap { [weak manager] state -> Future<Void> in
    guard let manager = manager else {
        throw AppError.unlikely
    }
    switch state {
    case .poweredOn:
        manager.removeAllServices()
        return manager.add(self.accelerometerService)
    case .poweredOff:
        throw AppError.poweredOff
    case .unauthorized, .unknown:
        throw AppError.invalidState
    case .unsupported:
        throw AppError.unsupported
    case .resetting:
        throw AppError.resetting
    }
}.flatMap { [weak manager] _ -> Future<Void> in
    guard let manager = manager else {
        throw AppError.unlikely
    }
    manager.startAdvertising(TISensorTag.AccelerometerService.name, uuids:[CBUUID(string: TISensorTag.AccelerometerService.uuid)])
}

startAdvertiseFuture.onFailure { [weak manager] error in
    switch error {
    case AppError.poweredOff:
        manager?.reset()            
    case AppError.resetting:
        manager?.reset()
    default:
	break
    }
    manager?.stopAdvertising()
}

Now respond to write events on accelerometerEnabledFuture and accelerometerUpdatePeriodFuture.

// respond to Update Period write requests
let accelerometerUpdatePeriodFuture = startAdvertiseFuture.flatMap {
    accelerometerUpdatePeriodCharacteristic.startRespondingToWriteRequests()
}

accelerometerUpdatePeriodFuture.onSuccess {  [weak accelerometerUpdatePeriodCharacteristic] (request, _) in
    guard let accelerometerUpdatePeriodCharacteristic = accelerometerUpdatePeriodCharacteristic else {
        throw AppError.unlikely
    }
    guard let value = request.value, value.count > 0 && value.count <= 8 else {
        return
    }
    accelerometerUpdatePeriodCharacteristic.value = value
    accelerometerUpdatePeriodCharacteristic.respondToRequest(request, withResult:CBATTError.success)
}

// respond to Enabled write requests
let accelerometerEnabledFuture = startAdvertiseFuture.flatMap {
    accelerometerEnabledCharacteristic.startRespondingToWriteRequests(capacity: 2)
}

accelerometerEnabledFuture.onSuccess { [weak accelerometerUpdatePeriodCharacteristic] (request, _) in
    guard let accelerometerEnabledCharacteristic = accelerometerEnabledCharacteristic else {
        throw AppError.unlikely
    }
    guard let value = request.value, value.count == 1 else {
        return
    }
    accelerometerEnabledCharacteristic.value = request.value
    accelerometerEnabledCharacteristic.respondToRequest(request, withResult:CBATTError.success)
}

See PeripheralManager Example for details.

Test Cases

Test Cases are available. To run type,

pod install

and run from test tab in generated workspace.

Examples

Examples are available that implement both CentralManager and PeripheralManager. The BluCap app is also available. The example projects are constructed using either CocoaPods or Carthage. The CocaPods projects require installing the Pod before building,

pod install

and Carthage projects require,

carthage update
BlueCap BlueCap provides CentralManager, PeripheralManager and iBeacon Ranging with implementations of GATT profiles. In CentralManager mode a scanner for Bluetooth LE peripherals is provided. In PeripheralManager mode an emulation of any of the included GATT profiles or an iBeacon is supported. In iBeacon Ranging mode beacon regions can be configured and monitored.
CentralManager CentralManager implements a BLE CentralManager scanning for services advertising the TiSensorTag Accelerometer Service. When a Peripheral is discovered a connection is established, services are discovered, the accelerometer is enabled and the application subscribes to accelerometer data updates. It is also possible to change the data update period.
CentralManagerWithProfile A version of CentralManager that uses GATT Profile Definitions to create services.
PeripheralManager PeripheralManager implements a BLE PeripheralManager advertising a TiSensorTag Accelerometer Service. PeripheralManager uses the onboard accelerometer to provide data updates.
PeripheralManagerWithProfile A version of Peripheral that uses GATT Profile Definitions to create services.
Beacon Peripheral emulating an iBeacon.
Beacons iBeacon ranging.

Documentation

BlueCap supports many features that simplify writing Bluetooth LE applications. Use cases with example implementations are described in each of the following sections.

  1. CentralManager: The BlueCap CentralManager implementation replaces CBCentralManagerDelegate and CBPeripheralDelegate protocol implementations with a Scala Futures interface using SimpleFutures.

  2. PeripheralManager: The BlueCap PeripheralManager implementation replaces CBPeripheralManagerDelegate protocol implementations with a Scala Futures interface using SimpleFutures.

  3. Serialization/Deserialization: Serialization and deserialization of device messages.

  4. GATT Profile Definition: Define reusable GATT profiles and add profiles to the BlueCap app.

Comments
  • Scanning services automatically filter out same UUID services?

    Scanning services automatically filter out same UUID services?

    Hi, the device we create has 2 same UUID services for battery from different sources. When I use bluecap service discovery, it automatically filter out the service. So when I use other BLE app, I will able to find lets say total 5 services, but bluecap only show 4 services due to same UUID? Is it possible to remove the filter option? If so , how can I do it?

    Thank you.

    opened by soonfay 12
  • Discovered Services and Characteristics are removed on new search

    Discovered Services and Characteristics are removed on new search

    Hey!

    When I am reading/writing to characteristics on my BLE device, I configure the device and then start getting notified for updates to a particular characteristic (so that I can monitor a button press).

    Alongside this I regularly poll the battery level and signal strength of the peripheral but whenever I try to discover new services/and or characteristics, the previous services and characteristics are removed and forgotten about. This means that when the button is pressed I see the log message come through from CoreBluetooth that a characteristic was updated, but it can't find which peripheral the characteristic belongs to.

    I can see references to discoveredServices.removeAll() and discoveredCharacteristics.removeAll() in a few places.

    Is there a reason that services and characteristics are removed from the Peripheral when you try to discover new ones? I'm happy to submit a PR to resolve this if desired but wanted to check beforehand.

    Thanks!

    opened by CImrie 9
  • Add tvOS Support

    Add tvOS Support

    This attempts to solve #51.

    Specifically the steps done are:

    • [x] Add new target for tvOS
    • [x] Rename iOS target to include the platform
    • [x] Add all parts of code that are available via tvOS APIs, which means:
      • [x] Removed the location feature (as CoreLocation doesn't provide APIs for it)
      • [x] Removed some peripheral-related initializers (see also this thread on SO)
    • [x] Add tvOS-support in .podspec for Cocoapods support (pod lib lint passed)
    • [x] Shared tvOS scheme for Carthage support
    • [x] List tvOS as an alternative to iOS in requirements section within README

    Everything should behave as before regarding iOS – the target name change shouldn't affect the framework name as I changed it not to rely on the target name (otherwise the iOS framework would have a differing name from the tvOS framework, which is usually not the expected behavior).

    opened by Jeehut 8
  • Is it possible to setNotifyValue for a Characteristic once you've discovered it?

    Is it possible to setNotifyValue for a Characteristic once you've discovered it?

    I'm working with a library right now from my chipset manufacturer, and trying to rewrite this and wrap it with the BlueCap framework, but I'm having trouble with the BLE messaging because I need to be able to setNotifyValue for a characteristic once I've discovered it. For example, the manufacturer's library makes this call:

    [self.connectedPeripheral.peripheral
     setNotifyValue:YES
     forCharacteristic:characteristic];
    

    This call is made after the services and characteristics have been discovered, and is basically saying, "I've found this characteristic on my peripheral, and now I want to be notified of changes to it." However, the BlueCap library wraps setNotifyValue into a private internal function, so when the characteristic is discovered, the initializer casts it to a CBCharacteristicInjectable, and the internal cbCharacteristic.isNotifying value is set to NO, and there's no way to change this after the fact, as far as I can tell. Am I missing something simple? Is there something more complex, like me needing to create a profile for the characteristics on my device? Or do I need to figure out a way to fix this and send a PR? Thanks for your help, and thanks for this awesome framework.

    opened by KevinGAleman 8
  • support for cocoa pods

    support for cocoa pods

    More of a request rather than an issue. Do you intend to add support for cocoa pods for BlueCap? It makes updates and new features / bug fixes much easier to incorporate than manually adding to projects.

    opened by magellan314 8
  • Connection callbacks not called if scanning is not stopped

    Connection callbacks not called if scanning is not stopped

    Unlike in the examples where stopScanning() is called before connect(), I'd like to keep scanning for other devices after making a connection.

    In didConnectPeripheral(), connectionPromise? was nil because the Peripheral in _discoveredPeripherals[] was overwritten in didDiscoverPeripheral() which always creates a new Peripheral instance.

    Is it possible to keep objects in _discoveredPeripherals[] stable? Update the properties instead of replacing the object.

    This will allow holding references to the Peripheral object.

    I'm happy to discuss more or even coding.

    opened by arrix 7
  • How to catch the error when a connected peripheral was been power down?

    How to catch the error when a connected peripheral was been power down?

    As the README.md say, we can give the Future a failure callback. But for the error PeripheralError.disconnected, it just stand for the disconnection without error, which should happen when the manager actively disconnect the peripheral.

    For the unexpected disconnection, such as shutting down the peripheral, exceeding the effective distance, the delegate will received a message with error in BluetoothKit. In this case, your design just put it to the failure promise.

    if let error = error {
                    Logger.debug("disconnecting with errors uuid=\(identifier.uuidString), name=\(self.name), error=\(error.localizedDescription), disconnection count=\(_disconnectionCount) ")
                    connectionPromise?.failure(error)
                } else  {
                    Logger.debug("disconnecting with no errors uuid=\(identifier.uuidString), name=\(self.name)")
                    self.connectionPromise?.failure(PeripheralError.disconnected)
                }
    

    Is there a better resolution for this condition?

    opened by liuwin7 6
  • Critical bug

    Critical bug

    There are wrong logic when called function loadRetrievedPeripheral().

    1. Call func loadRetrievedPeripheral(_ peripheral: CBPeripheralInjectable) -> Peripheral
    2. Created new instance of newBCPeripheral (line 262 CentralManager.swift) and it sets
      self.cbPeripheral.delegate = self (line 203 in Peripheral.swift)
    3. Replaced peripheral (line 262 CentralManager.swift) and self._discoveredPeripherals[peripheral.identifier] = newBCPeripheral and it removes old peripheral and calls deinit (line 208 in Peripheral.swift) BUT it also removes delegate for new peripheral
    4. As result it never calls any of peripheral delegate functions

    Way to fix: Peripheral.swift

    1. remove deinit { self.cbPeripheral.delegate = nil } 2 ) and replace: var delegate: CBPeripheralDelegate? { get set } with: weak var delegate: CBPeripheralDelegate? { get set }
    opened by JeniaTretiakova-ezlo 6
  • CBMutableDescriptors can't be added to MutableCharacteristics

    CBMutableDescriptors can't be added to MutableCharacteristics

    As far as I can tell there is no way to add a CDMutableDescriptor to BlueCap's MutableCharacteristic class. The underlying CBMutableCharacteristic is not exposed either so there is no way to add the descriptors directly to the characteristic itself.

    opened by MrSage 6
  • CentralManager state reported as unsupported if already connected to a peripheral. Errors thrown are sometimes CoreBluetooth errors instead of PeripheralError.

    CentralManager state reported as unsupported if already connected to a peripheral. Errors thrown are sometimes CoreBluetooth errors instead of PeripheralError.

    If I connect to, discover services and characteristics, notify and receive notification updates with a peripheral and I use the same central to attempt to connect and do the same with another peripheral, the state of the CentralManager is unsupported, yet if I forgo the state checking and connect anyway, it works as intended.

    I am running this on an iPhone 7 Plus 256GB running iOS 10.3.2 beta 4.

    Here is my code for the connection, discovery, etc.:

    func connect() {
            let dataUpdateFuture = self.central.whenStateChanges().flatMap { [unowned self] state -> FutureStream<Void> in
                
                switch state {
                case .poweredOn:
                    return self.peripheral.connect(connectionTimeout: 10.0)
                case .poweredOff:
                    throw BLEError.poweredOff
                case .unauthorized:
                    throw BLEError.unauthorized
                case .unsupported:
                    throw BLEError.unsupported
                case .resetting:
                    throw BLEError.resetting
                case .unknown:
                    throw BLEError.unknown
                }
     
                return self.peripheral.connect(connectionTimeout: 10.0)
                }.flatMap { [unowned self] () -> Future<Void> in
                    //Update UI
                    self.peripheral.startPollingRSSI(period: 0.25, capacity: 10).onSuccess { rssi in
                        BLE.sharedInstance.invoke(method: { $0.didUpdateRSSI?(rssi) })
                    }
                    BLE.sharedInstance.invoke(method: { $0.didGetPeripheralUUID?(self.peripheral.identifier.uuidString) })
                    self.uuid = self.peripheral.identifier.uuidString
    
                    print("Discovering services")
                    return self.peripheral.discoverServices([s2UUID], timeout: 10.0)
                }.flatMap { [unowned self] () -> Future<Void> in
                    guard let service = self.peripheral.services(withUUID: s2UUID)?.first else {
                        throw AppError.serviceNotFound
                    }
                    print("Discovering characteristics")
                    return service.discoverCharacteristics([rawUUID], timeout: 10.0)
                }.flatMap { [unowned self] () -> Future<Void> in
                    guard let service = self.peripheral.services(withUUID: s2UUID)?.first else {
                        throw BLEError.serviceNotFound
                    }
                    guard let rawCharacteristic = service.characteristics(withUUID: rawUUID)?.first else {
                        throw BLEError.rawDataCharacteristicNotFound
                    }
                    print("Start notifying raw characteristic")
                    self.rawDataCharacteristic = rawCharacteristic
                    return rawCharacteristic.startNotifying()
                }.flatMap { [unowned self] () -> FutureStream<Data?> in
                    guard let rawCharacteristic = self.rawDataCharacteristic else {
                        throw BLEError.rawDataCharacteristicNotFound
                    }
                    print("Receiving raw characteristic notification update")
                    return rawCharacteristic.receiveNotificationUpdates(capacity: 30)
            }
    

    As for errors being thrown, I have to use CBErrors to catch some of them, like so:

    dataUpdateFuture.onFailure { error in
                print("Data update error: \(error)")
                switch error {
                case BLEError.serviceNotFound:
                    self.disconnect()
                case PeripheralError.disconnected, PeripheralError.connectionTimeout, CBError.connectionTimeout, CBError.connectionFailed:
                    self.connect()
                default:
                    break
                }
            }
    
    opened by Soulphalanx 6
  • next_release example

    next_release example

    Hi, I'm trying to test next_release branch but I'm new in Swift, what's the new syntaxis to create a new connection and when it's successful, it could probably be something like this? Could you give me a more complete example please?

    manager.startScanning(forServiceUUIDs: [CBUUID]?).flatMap(mapping: (Peripheral) throws -> Future)

    Thanks in advance

    opened by cesargut 6
  • Is there support for passkey or OOB BLE pairing methods?

    Is there support for passkey or OOB BLE pairing methods?

    From what I have read, this does not seem to be possible as part of BluetoothCore API. Has any of these capabilities been exposed as part of this project?

    opened by taylorcenters 0
  • Receiving didModifyServices message for Peripheral

    Receiving didModifyServices message for Peripheral

    When the distant device application gets killed, I would like to disconnect properly from my side, I am receiving only one log from the library internals: ./Pods/BlueCapKit/BlueCapKit/Central/Peripheral.swift:peripheral(_:didModifyServices:):332

    As it is not forwarded anywhere, and the Peripheral registers as the CBDelegate, I cannot handle the notification from my side. Do I have to modify the source code to forward that message or am I missing something?

    Thanks for your support,

    opened by michael-martinez 1
  • Is there a way to enqueue read/writes?

    Is there a way to enqueue read/writes?

    With the current library I am using for Android, I do something like this:

    writeCharacteristic(callback1).enqueue() waitForNotification(callback1).enqueue()

    I don't have a general callback for notifications.

    This is nice because I am interested in the value only after writes, I can use a different callback for different messages to keep things organized and I can put a lot of these in a queue and nothing gets mixed up.

    Is it possibly to do something like this on iOS?

    opened by kabiskac 0
Owner
Troy Stribling
Troy Stribling
iOS & OSX Bluetooth library for RxSwift

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 Dec 16, 2022
You will learn how to scan QR code with iOS framework.

QR Code Scanner You will learn how to scan QR code with in iOS without using any library. It is as simple to scan QR code in iOS. In this example, We

Nitin Aggarwal 11 Dec 8, 2022
Library for iOS Camera API. Massively increase performance and ease of use within your next iOS Project.

CameraKit helps you add reliable camera to your app quickly. Our open source camera platform provides consistent capture results, service that scales,

CameraKit 628 Dec 27, 2022
A better way to operate QR Code in Swift, support iOS, macOS, watchOS and tvOS.

EFQRCode is a lightweight, pure-Swift library for generating stylized QRCode images with watermark or icon, and for recognizing QRCode from images, in

EFPrefix 4.3k Jan 2, 2023
Easily communicate between iOS/OSX devices using BLE

BluetoothKit Easily communicate between iOS devices using BLE. Background Apple mostly did a great job with the CoreBluetooth API, but because it enca

Rasmus Høhndorf Hummelmose 2.1k Dec 29, 2022
Simply the fastest way to transmit data between iOS/tvOS and OSX

DarkLightning DarkLightning is a lightweight Swift library to allow data transmission between iOS/tvOS devices (Lightning port, Dock connector, USB-C)

Jens Meder 318 Nov 29, 2022
Luminous provides you a lot of information about the system and a lot of handy methods to quickly get useful data on the iOS platform.

Luminous Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements iOS 8+ Swift 5 Xcode 1

Andrea Mario Lufino 324 Nov 27, 2022
WatchCon is a tool which enables creating easy connectivity between iOS and WatchOS.

WatchCon WatchCon is a tool which enables creating easy connectivity between iOS and WatchOS Requirements iOS 9.0+ / watchOS 2.0+ CocoaPods CocoaPods

Abdullah Selek 33 Sep 22, 2022
TapticEngine generates haptic feedback vibrations on iOS device.

TapticEngine Overview TapticEngine generates haptic feedback vibrations on iOS device. This library wrapps on UIImpactFeedbackGenerator, UISelectionFe

WorldDownTown 253 Oct 28, 2022
NFCPassportReader for iOS 13

NFCPassportReader This package handles reading an NFC Enabled passport using iOS 13 CoreNFC APIS THIS IS AN IN-PROGRESS BRANCH AND NOT EVEN REMOTELY S

Andy Qua 581 Dec 27, 2022
Just simple template - example how to use haptics in iOS Development

Haptics Just simple template - example how to use haptics in iOS Development imp

Alexander Ryakhin 1 Jan 31, 2022
Grab kbsync dynamically from your jailbroken iOS device.

KbsyncTool Grab kbsync dynamically from your jailbroken iOS device. Usage Test1:~ root# kbsynctool -s 9000 [DEBUG] Did open IPv4 listening socket 3 [D

i_82 13 Oct 31, 2022
Writes twitter and contact (links) to writable nfcs on iPhone 7+ iOS 14+

nfc writer ios app nfc writer app is a hacky fun side project that writes twitter and contact (links) to writable nfcs. runs on iPhone 7+ iOS 14+. joi

Vivian Phung 5 Nov 23, 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
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
Blocks Based Bluetooth LE Connectivity framework for iOS/watchOS/tvOS/OSX. Quickly configure centrals & peripherals, perform read/write operations, and respond characteristic updates.

ExtendaBLE Introduction ExtendaBLE provides a very flexible syntax for defining centrals and peripherals with ease. Following a blocks based builder a

Anton 94 Nov 29, 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
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
iOS & OSX Bluetooth library for RxSwift

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 Dec 16, 2022