Contents

rozd/faketooth

**Simulate Bluetooth Low Energy devices on Apple platforms — no hardware required.**

Installation

Add the following dependency to your Package.swift:

dependencies: [
    .package(url: "https://github.com/rozd/faketooth.git", from: "0.5.0")
]

Usage

1. Import

import Faketooth

2. Configure simulated peripherals

Assign an array of FaketoothPeripheral instances to CBCentralManager.simulatedPeripherals. Each peripheral represents a virtual BLE device with its own identifier, name, services, and advertisement data.

CBCentralManager.simulatedPeripherals = [
    FaketoothPeripheral(
        identifier: UUID(),
        name: "Test",
        services: [
            FaketoothService(
                uuid: CBUUID(),
                isPrimary: true,
                characteristics: [
                    FaketoothCharacteristic(
                        uuid: CBUUID(),
                        properties: [.read, .notify, .write],
                        descriptors: [
                            FaketoothDescriptor(
                                uuid: CBUUID(string: "2902"),
                                valueProducer: { () -> Any? in
                                    return Data(capacity: 2)
                                }
                            )
                        ],
                        valueProducer: { "Hello".data(using: .utf8) },
                        valueHandler: { data in
                            print("\(String(data: data!, encoding: .utf8)!)")
                        }
                    )
                ]
            )
        ],
        advertisementData: [
            CBAdvertisementDataLocalNameKey: "Name for Advertisement"
        ]
    )
]

3. Use CoreBluetooth as usual

Build and run your project. Faketooth intercepts CBCentralManager calls transparently — scanning, connecting, service discovery, reads, writes, and notifications all work against your virtual peripherals.

When simulation is active, Faketooth:

  • Fires centralManagerDidUpdateState: with .poweredOn on first interaction
  • Filters scanForPeripherals(withServices:) results by advertised service UUIDs
  • Filters discoverServices: and discoverCharacteristics:forService: by UUID when non-nil
  • Supports retrieveConnectedPeripherals(withServices:) for finding connected simulated peripherals

4. Simulate errors

Set optional error properties to test your app's error-handling code paths. When an error is set, the corresponding delegate callback fires with the error and the operation does not mutate state (matching real CoreBluetooth behavior).

// Simulate a connection failure
peripheral.connectionError = NSError(
    domain: CBErrorDomain,
    code: CBError.connectionFailed.rawValue,
    userInfo: nil
)
// centralManager(_:didFailToConnect:error:) will be called instead of didConnect

// Simulate a characteristic read error
characteristic.readError = NSError(
    domain: CBATTErrorDomain,
    code: CBATTError.readNotPermitted.rawValue,
    userInfo: nil
)
// peripheral(_:didUpdateValueFor:error:) will receive the error

// Clear the error to restore normal behavior
peripheral.connectionError = nil
characteristic.readError = nil

Available error properties:

  • FaketoothPeripheral: connectionError, disconnectionError, discoverServicesError, discoverCharacteristicsError, discoverDescriptorsError
  • FaketoothCharacteristic: readError, writeError
  • FaketoothDescriptor: readError, writeError

5. Deactivate

Set simulatedPeripherals to nil to restore real CoreBluetooth behavior:

CBCentralManager.simulatedPeripherals = nil

How It Works

Faketooth swizzles eight CBCentralManager methods in +load. Each swizzled method checks whether simulation is active — if simulatedPeripherals is nil, it falls through to the original CoreBluetooth implementation. This means Faketooth is completely inert unless explicitly activated.

| Class | Role | |---|---| | CBCentralManager+Faketooth | Swizzles scanning, connecting, retrieval, state, isScanning | | FaketoothPeripheral | Overrides service discovery, read/write, notifications; supports error injection | | FaketoothService | Holds characteristics, links back to peripheral | | FaketoothCharacteristic | Supports valueProducer (read), valueHandler (write), and error injection | | FaketoothDescriptor | Supports valueProducer, valueHandler, and error injection | | FaketoothSettings | Configurable delays per operation via FaketoothDelaySettings |

Examples

The repository includes examples demonstrating different use cases. See the Demo directory.

Contributing

Contributions are welcome! If you encounter issues, have questions, or want to suggest improvements, please open an issue.

License

Faketooth is available under the MIT license. See the LICENSE file for more information.

Package Metadata

Repository: rozd/faketooth

Default branch: master

README: README.md