Coder Social home page Coder Social logo

nordicsemiconductor / ios-corebluetooth-mock Goto Github PK

View Code? Open in Web Editor NEW
224.0 10.0 51.0 3.36 MB

Mocking library for CoreBluetooth framework.

License: BSD 3-Clause "New" or "Revised" License

Ruby 0.36% Swift 99.64%
ble corebluetooth mock mocking-framework bluetooth-low-energy nrf5x

ios-corebluetooth-mock's Introduction

Core Bluetooth Mock

Version number Platform Carthage compatible SPM compatible

The Core Bluetooth Mock library was designed to emulate Core Bluetooth objects, providing easy way to test Bluetooth-enabled apps. As the native Bluetooth API is not supported on a simulator, using this library you can run, test and take screenshots of such apps without the need of a physical phone or tablet. You may also start working on the iOS app when your peripheral is still under development.

Core Bluetooth?

The Core Bluetooth framework provides the classes needed for your apps to communicate with Bluetooth-equipped low energy (LE) wireless technology. It requires an iPhone or iPad to work making Bluetooth-enabled apps difficult to test. As the documentation states:

Don’t subclass any of the classes of the Core Bluetooth framework. Overriding these classes isn’t supported and results in undefined behavior.

Core Bluetooth Mock!

The Core Bluetooth Mock library defines a number of CBM... classes and constants, that wrap or imitate the corresponding CB... counterparts from Core Bluetooth framework. For example, CBMCentralManager has the same API and behavior as CBCentralManager, etc. On physical iDevices all calls to CBMCentralManager and CBMPeripheral are forwarded to their native equivalents, but on a simulator a user defined mock implementation is used.

Requirements

The Core Bluetooth Mock library is available only in Swift, and compatible with

  • iOS 12.0+1,
  • macOS 10.14+,
  • tvOS 12.0+1,
  • watchOS 4.0+

(with some features available only on newer platforms).

Note

For projects running Objective-C we recommend https://github.com/Rightpoint/RZBluetooth library.

Installation

The library support CocoaPods, Carthage and Swift Package Manager.

CocoaPods
  • Create/Update your Podfile with the following contents

    target 'YourAppTargetName' do
        pod 'CoreBluetoothMock'
    end
  • Install dependencies

    pod install
  • Open the newly created .xcworkspace

Carthage
  • Create a new Cartfile in your project's root with the following contents

    github "https://github.com/NordicSemiconductor/IOS-CoreBluetooth-Mock" ~> x.y // Replace x.y with your required version
    
  • Build with carthage

    carthage update --platform iOS // also supported are tvOS, watchOS and macOS
  • Copy the CoreBluetoothMock.framework from Carthage/Build to your project and follow instructions from Carthage.

Swift Package Manager
  • In Xcode: File -> Swift Packages -> Add package dependency, type https://github.com/NordicSemiconductor/IOS-CoreBluetooth-Mock.git and set required version, branch or commit.

  • If you have Swift.package file, include the following dependency:

    dependencies: [
        // [...]
        .package(name: "CoreBluetoothMock", 
                 url: "https://github.com/NordicSemiconductor/IOS-CoreBluetooth-Mock.git", 
                 .upToNextMajor(from: "x.y")) // Replace x.y with your required version
    ]

    and add it to your target:

    targets: [
        // [...]
        .target(
            name: "<Your target name>",
            dependencies: ["CoreBluetoothMock"]),
    ]

Documentation

The documentation of the library is available here.

Migration from CoreBluetooth

Migration example is available here. See Pull Request #1 for step-by-step guide.

Note

The migration example application currently does not use mocks in tests. For that, check out the Example folder in this repository with nRF Blinky app, which is using mock peripherals in Unit Tests and UI Tests. See below.

Sample application: nRF Blinky

nRF Blinky is an example app targeted towards newcomer BLE developers, and also demonstrating the use of Core Bluetooth Mock library. This application controls an LED on an nRF5DK and receive notifications whenever the button on the kit is pressed and released.

The mock implementation is used in Unit tests and UI tests. See AppDelegate.swift where the mock environment is set up and and UITests.swift and UITests.swift classes.

The mock peripherals are defined in MockPeripherals.swift.

Nordic LED and Button Service

A simplified proprietary service by Nordic Semiconductor, containing two characteristics one to control LED3 and Button1:

  • Service UUID: 00001523-1212-EFDE-1523-785FEABCD123

    • First characteristic controls the LED state (On/Off).
      • UUID: 00001525-1212-EFDE-1523-785FEABCD123
      • Value: 1 => LED On
      • Value: 0 => LED Off
    • Second characteristic notifies central of the button state on change (Pressed/Released).
      • UUID: 00001524-1212-EFDE-1523-785FEABCD123
      • Value: 1 => Button Pressed
      • Value: 0 => Button Released

    For full specification, check out documentation.

Requirements

  • An iOS device with BLE capabilities, or a simulator (to run the mock).
  • A Development Kit (unless testing mock).
  • The Blinky example firmware to flash on the Development Kit. For your convenience, we have bundled two firmwares in this project under the Firmwares directory.
  • To get the latest firmwares and check the source code, you may go directly to our Developers website and download the SDK version you need, then you can find the source code and hex files to the blinky demo in the directory /examples/ble_peripheral/ble_app_blinky/
  • The LBS (LED Button Service) is also supported in nRF Connect SDK: here.
  • More information about the nRFBlinky example firmware can be found in the documentation.

Installation and usage

  • Prepare your Development kit.

    • Plug in the Development Kit to your computer via USB.
    • Power On the Development Kit.
    • The Development Kit will now appear as a Mass storage device.
    • Drag (or copy/paste) the appropriate HEX file onto that new device.
    • The Development Kit LEDs will flash and it will disconnect and reconnect.
    • The Development Kit is now ready and flashed with the nRFBlinky example firmware.
  • Start Xcode and run build the project against your target iOS Device (Note: BLE is not available in the iOS simulator, so the iOS device is a requirement to test with real hardware).

    • Launch the nRF Blinky app on your iOS device.
    • The app will start scanning for nearby peripherals.
    • Select the Nordic_Blinky peripheral that appears on screen (Note: if the peripheral does not show up, ensure that it's powered on and functional).
    • Your iOS device will now connect to the peripheral and state is displayed on the screen.
    • Changing the value of the Toggle switch will turn LED 3 on or off.
    • Pressing Button 1 on the Development Kit will show the button state as Pressed on the app.
    • Releasing Button 1 will show the state as Released on the App.

Footnotes

  1. Xcode 15 dropped support for iOS 9.0 and tvOS 9.0 in simulator. Now the minimum supported version is 12.0 for both platforms. 2

ios-corebluetooth-mock's People

Contributors

adamrhunter avatar adrianbindc avatar audiodo-lars avatar dinesharjani avatar drama999 avatar enricodk avatar everlof avatar jason-gabriele avatar jaylyerly avatar johanneshintze avatar kennylovrin avatar kscheff avatar nickkibish avatar ovenham avatar philips77 avatar s-hocking avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ios-corebluetooth-mock's Issues

Service discovery not firing

I am having an issue with service discovery, using version 0.16.1 via Swift package manager.

After connecting to our physical device, and issuing peripheral.discoverServices([]) our delegate is not receiving a didDiscoverCharacteristicsFor callback.

Stepping through the code I have found when we set our delegate it seems that inside CBMCentralManagerNative.swift our delegate is thrown away and a wrapper delegate (that has no reference to ours) is used in place.

public weak var delegate: CBMPeripheralDelegate? {
didSet {
if let _ = delegate {
// We need to hold a strong reference to the wrapper, otherwise
// it would be immediately deallocated.
wrapper = CBPeripheralDelegateWrapper(self)
peripheral.delegate = wrapper
} else {
wrapper = nil
peripheral.delegate = nil
}
}
}

I can see didDiscoverServices is being called on the CBPeripheralDelegateWrapper, but not being passed down to our delegate.

func peripheral(_ peripheral: CBPeripheral,
didDiscoverServices error: Error?) {
smartCopy(peripheral.services)
impl.delegate?.peripheral(impl, didDiscoverServices: error)
}

I set the delegate via the CBPeripheral we receive during didDiscover phase. Everything works perfectly when mocking, seems like an issue with the native flow only.

Other then that fantastic library, I wrote the code purely against this library and once we received the physical device everything else seems to work perfectly. Well done.

Peripheral connected through the system never connects if not advertising

I am not too familiar with the internal workings, so maybe I am missing something: We upgraded to the recent version, but all our tests are breaking now because a mock peripheral that is already connected by the system never connects.

Looking through the diff, it seems the manager now only set mock.state = .connecting. The actual connection is only triggered in static CBMCentralManagerMock.peripheralBecameAvailable(_:) which is called when a peripheral is advertising. Previously, the connection was established during the CBMCentralManagerMock.connect(_:options:).

Our peripheral does connect to iOS in the background without any involvement from our app. The peripheral stops advertising when connected. Our mock looks like this

CBMPeripheralSpec
	.simulatePeripheral(proximity: .near)
	.advertising(
		advertisementData: [
			CBMAdvertisementDataServiceUUIDsKey: (...)),
			CBMAdvertisementDataLocalNameKey: "Mock",
		],
		withInterval: 0.250,
		alsoWhenConnected: false
	)
	.connected(
		name: "Mock",
		services: [(...)],
		delegate: MockSpecDelegate()
	)
	.build()

If I revert the change in CBMCentralManagerMock:728

mock.state = .connecting
mock.connect() { result in
  switch result {
	case .success:
		self.delegate?.centralManager(self, didConnect: mock)
	case .failure(let error):
		self.delegate?.centralManager(self, didFailToConnect: mock, error: error)
}

everything works again.


Is this an oversight? Or am I missing something? Is there a new way to simulate this use case?

Can't read out values after disconnect

Hello,

I've integrated this framework and it works pretty well. However, when we reconnect, we don't get callbacks for the for the didUpdateValueFor after we've called readValue(for characteristic.

If I just restart the app, it works fine and connect. Do you have any hint of what to look for and how to debug this issue?

To clarify. This only happens while running without mock enabled. Mocking works good and running without this library work good as well.

What we do is:

  1. Call connect after the device reports that it disconnected
  2. Get "didConnect" callback
  3. Call "readValue" on the peripheral.

Would be nice if writeValue for characteristic with .notify triggered simulateValueUpdate automatically

I might not be seeing some bigger picture, as I've only worked with one BLE device, but in my mind it makes sense to automatically trigger simulateValueUpdate whenever writing to a characteristic that has a .notify property.

Once again, it's possible that I just don't see all the possible scenarios, but on the device I work with, every characteristic that is writable and can notify, notifies of the written change.

Deadlock

I've found a potential deadlock while trying to simulate a write without response. If I create a CBCentralManager mock that uses the main queue, the code will crash trying to dispatch synchronously on main. CBMCentralManagerMock.swift about line 1105 method

public func writeValue(_ data: Data,
                           for characteristic: CBMCharacteristic,
                           type: CBMCharacteristicWriteType)

Here

else {
            queue.sync { //<--Here
                guard availableWriteWithoutResponseBuffer > 0 else {
                    return
                }
                availableWriteWithoutResponseBuffer -= 1
                _canSendWriteWithoutResponse = false
            }

Consider opening CBM classes for subclassing

The CBM library is great for simulating a full Bluetooth connection workflow, but sometimes I just want to satisfy a dependency on a CoreBluetooth object in order to test other parts of a class. For example, I might have a class with a dependency on a CBPeripheral object that I want to test without using any CoreBluetooth capabilities.

To achieve this use case it would be helpful if the core CBM classes were open, so that they could be subclassed and used this way.

Subclassing might also be a useful way of customising CBM behaviour for test purposes.

Unit test failing with EXC_BAD_ACCESS

Some times unit test crashing with error: Thread 4: EXC_BAD_ACCESS (code=1, address=0xeb0494cb1130)

Screenshot 2021-05-17 at 10 08 27

My temporary fix for this failure is, that running second or third time unit test passing ok. But any way would be fine if it would not crash at all.

Using latest version: 0.12.1

CBCentralManagerMock#connect API differs from the real one

This is minor, but still forced me to change the production code in order to accommodate for CBM.

With the real API there is a default nil value for options, so I used this: centralManager.connect(retrievedPeripheral), with CBM, it's necessary to set options explicitly, even if it's a nil.

open func connect(_ peripheral: CBPeripheral, options: [String : Any]? = nil)
vs
open func connect(_ peripheral: CBMPeripheral, options: [String : Any]?)

App backgrounding not updating timers

With Core Bluetooth it is possible to keep the peripheral connected and receive e.g. regularly notifications when the App is in background mode. My use case is to receive notifications in background to update real time model. The Mock however is suspended and the typical Timer or GDC doesn't fire anymore when the user sends the App to background.

There are workaround to keep timers going (see https://www.raywenderlich.com/5817-background-modes-tutorial-getting-started). Those might be a solution for development, but will be of limited use for an App Store submission due to potential API miss-use.

Library does not compile with Xcode 13 beta/iOS 15 SDK due to CoreBluetooth API changes

A number of inverse relationships in CoreBluetooth (e.g. CBCharacteristic.service) have been changed from unowned(unsafe) to weak, and therefore Optional in the iOS 15 SDK.

This results in numerous compilation errors when attempting use the IOS-CoreBluetooth-Mock library:

~/IOS-CoreBluetooth-Mock/CoreBluetoothMock/Classes/CBMCentralManagerNative.swift:391:51: Value of optional type 'CBService?' must be unwrapped to a value of type 'CBService'

Peripheral disconnect and teardown cause assertion failure

This issue is a bit convoluted...I know exactly why it's happening, but I'm not sure what the best approach is to fix it.

I have a test case where at the end of the test I disconnect a peripheral. This decrements CBMPeripheralSpec.virtualConnections inside a closure after a delay.

Immediately after my test finishes, my tearDown() method runs CBMCentralManagerMock.tearDownSimulation(). This sets virtualConnections = 0.

Due to the delay on the peripheral disconnect, the closure runs after tearDown() has already set virtualConnections = 0, and it decrements virtualConnections so that it ends up set to -1.

Finally, the assert() here runs and fails the test because virtualConnections is negative.

One idea I had for a fix is to run all internal closures on a private queue that can be paused and cleared during teardown. These closures would have to dispatch to the main queue (or the user-specified queue) to call back to delegates etc. It might be a bit complex to implement, but it would avoid any delayed closures from running after the teardown, which really shouldn't happen.

How to start a real DFU when using this library?

Hello,

I've integrated this library and it works great for the most part. However, our part of the code that interfaces with the DFU-library from Nordic Semiconductors is a bit problematic.

After I've created a DFUServiceInitiator and gonna call start(target: target) (https://github.com/NordicSemiconductor/IOS-DFU-Library/blob/d79e33c7eed7f67454578ff08462ea92e97dc330/iOSDFULibrary/Classes/Implementation/DFUServiceInitiator.swift#L465), I can't, because there's no way to access the real peripheral from the CBMPeripheral.

Any hints on how to resolve this?

peripheral.discoverServices with empty list []

When using the mock the call to .discoverServices returns with am empty list.

Expected: the call should return all mockServices when supplying an empty list ([]).

Documentation to this call from Apple states:

Discussion

You can provide an array of CBUUID objects — representing service UUIDs — in the serviceUUIDs parameter. When you do, the peripheral returns only the services of the peripheral that match the provided UUIDs.

Init() Unavailable

Using Xcode Version 12.5 (12E262) and deploying to iOS 13.0, I am unable to build the CoreBluetoothMock pod. While building I get the following errors:

/Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:65:5: 'init()' is unavailable /CoreBluetooth.CBAttribute:4:12: 'init()' has been explicitly marked unavailable here /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:72:14: 'init()' is unavailable /CoreBluetooth.CBAttribute:4:12: 'init()' has been explicitly marked unavailable here /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMCentralManagerNative.swift:490:17: 'init()' is unavailable /CoreBluetooth.CBPeer:4:12: 'init()' has been explicitly marked unavailable here /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMCentralManagerMock.swift:681:17: 'init()' is unavailable /CoreBluetooth.CBPeer:4:12: 'init()' has been explicitly marked unavailable here /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMCentralManagerMock.swift:688:17: 'init()' is unavailable /CoreBluetooth.CBPeer:4:12: 'init()' has been explicitly marked unavailable here /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:176:5: 'init()' is unavailable /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:176:5: 'init()' has been explicitly marked unavailable here (CoreBluetooth.CBAttribute) /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:184:5: 'init()' is unavailable /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:184:5: 'init()' has been explicitly marked unavailable here (CoreBluetooth.CBAttribute) /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:270:5: 'init()' is unavailable /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:270:5: 'init()' has been explicitly marked unavailable here (CoreBluetooth.CBAttribute) /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:276:5: 'init()' is unavailable /Pods/CoreBluetoothMock/CoreBluetoothMock/Classes/CBMServiceTypes.swift:276:5: 'init()' has been explicitly marked unavailable here (CoreBluetooth.CBAttribute)

Task: Add support for SPM

Trying to get Xcode 13.4.1 compiling with the swift package alone doesn't work on my M1 machine (I did not check others). All options are based on Pods, so it is a long configuration fight in the project settings in order to get it proper compiling using the swift package.

I have not check the Pod install, since it was a rough start with the M1.

Suggestion: move project to swift package instead of Pod install.

Unable to re-initialize native central manager after mock central manager initialized

When creating a "demo mode" for an application, it'd be great to be able to allow users to toggle between a "native" and "mock" central manager with all supported features of the device and software. This way users can evaluate how a product behaves before the purchase by just downloading the app.

I'd found that I can do it with this library with
self.centralManager = CBMCentralManagerFactory.instance(delegate: CBMCentralManagerDelegate, queue: DispatchQueue?, options: [String: Any]?, forceMock: Bool) by re-initializing a central manager with the forceMock toggled.

However, I've found this only works when the CBMCentralManagerOptionRestoreIdentifierKey is modified each time or omitted from options: in the init method above. Otherwise, the native centralManagerState didUpdateState(_:) returns unsupported after initialization if a native central manager was initialized beforehand (e.g. native > mock > native.) I've found the native central manager was able to call deinit but the mock central manager is unable to call deinit when this occurs.

For now, workarounds include:

  1. using CBMCentralManagerOptionRestoreIdentifierKey only when forceMock = false,
  2. remove this key and lose support for CoreBluetooth peripheral restoration, or
  3. include a custom string for the key each time to enable it for the native centralManager again.

I'm using a similar centralManager and peripheral implementation to the Blinky example provided (using notification central and a reference cycle between the central manager and peripherals). I've also tried with and without setting the CBMCentralManagerFactory.simulateStateRestoration callback in the App Delegate:

CBMCentralManagerFactory.simulateStateRestoration = { identifier in
   return [
      CBMCentralManagerRestoredStatePeripheralsKey: [Seeds.Peripherals.downrigger.identifier],
      CBMCentralManagerRestoredStateScanServicesKey: [],
      CBMCentralManagerRestoredStateScanOptionsKey: [
         CBMCentralManagerScanOptionAllowDuplicatesKey: false,
         CBMCentralManagerScanOptionSolicitedServiceUUIDsKey: []
      ]
   ]
}

This issue should be easily replicated by adding a print statement in the centralManager deinit method and toggling between a native and mock central manager; observing the method is only called when the central manager is native.

Ability to reset mock to initial state

Hi there! I'm using this library to write automated tests for my BLE framework. It would be really helpful to be able to teardown the mock and add/remove simulated peripherals, and set it up again with a clean slate, to support automated testing. Is it possible to do this?

I should add that I have tried calling simulatePowerOff() as is done in the Example test cases, and then changing the simulated peripherals. But this prints the error "Warning: Peripherals can be added to simulation only once, and not after any central manager was initiated"

CBServices Not Refreshed on Connect

Hello.

I'm trying to implement a smarter way of using iOS's service cache so I don't need to call discoverServices on every connection. I've noticed that iOS seems to recreate the CBService and CBCharacteristic objects on each connection, even if the underlying details haven't changed. If I use the native CoreBluetooth objects, I can simply refresh my cached objects and issue read/writes without needing to call discoverServices on each connection. However, CoreBluetoothMock doesn't update the objects unless you specifically call discoverServices. Would it be possible to call smartCopy on connect to update the object references?

Thanks

Here's an example of my testing just using the native CoreBluetooth:

Previous Connection:
<CBCharacteristic: 0x28062b6c0, UUID = ...
<CBCharacteristic: 0x28062b720, UUID = ...
<CBCharacteristic: 0x28062b7e0, UUID = ...
<CBCharacteristic: 0x28062b780, UUID = ...

Current Connection:
<CBCharacteristic: 0x280605740, UUID = ...
<CBCharacteristic: 0x280605bc0, UUID = ...
<CBCharacteristic: 0x2806060a0, UUID = ...
<CBCharacteristic: 0x280604ea0, UUID = ...

You can see the pointer is changing on each connect

Support for permissions and pairing pop-ups

When developing apps with pairing flows it's critical to be able to take into account the effect of these pop ups on the user experience. For example CB does not give any indication that a permission or pairing pop up is visible. For the pairing pop up specifically, it does not even tell you if the user rejected it, pairing simply fails with some obscure insufficient encryption error.

Being able to simulate this behaviour with the mocks will make it easier to develop the UX for these scenarios without a real device.

permissions
pairing

retrievePeripherals(withIdentifiers:) does not work as expected

When using the real CoreBluetooth, after I've connected to the peripheral once, I can use retrievePeripherals(withIdentifiers:) to retrieve already known peripherals on any consequent application launch. With CoreBluetoothMock - no such luck. I assumed these would be retrieved from the list of peripherals set with CBMCentralManagerMock.simulatePeripherals, but this sets peripherals to private static var peripherals: [CBMPeripheralSpec] = [] and retrievePeripherals checks private var peripherals: [UUID : CBMPeripheralMock] = [:] of every manager and never finds anything on application consequent launch.

CBCentralManager.authorization is not supported

This is something that exists since iOS 13 (so, pretty old by now) and can be used to check app's authorization even before initing CBManager.

Sadly, using the recommended approach of aliasing for CBM, I had to hide my production code behind build configuration flags in order to be able to use CBM, as I am using CBCentralManager.authorization

So, would be nice to have CBCentralManager.authorization and CBManagerAuthorization

iOS 13.0: https://developer.apple.com/documentation/corebluetooth/cbmanager/3180033-authorization
iOS 13.1+: https://developer.apple.com/documentation/corebluetooth/cbmanager/3377595-authorization

too many mock advertising notifications are sent ...

... when .scanForPeripherals are called.

Each call to CBMCentralManagerMock.scanForPeripherals creates a new repeating timer. This leads to flooding notifications the app. This stops only when the app stops scanning so the timers will tear down themselves.

Library Evolution Support

Hi, I just started using this library and I'm really glad it exists!

However, I'm getting this warning next to import CoreBluetoothMock using CocoaPods with version 0.8.0 when I enabled Build Libraries for Distribution in the project Build Settings:

Module 'CoreBluetoothMock' was not compiled with library evolution support; using it means binary compatibility for 'Project Name' can't be guaranteed

Would it be possible to enable Build Libraries for Distribution to improve ABI support for later versions? If not, no worries!

Can't mock duplicate services with CBMPeripheralSpecDelegate?

I'm interfacing with a device that has two battery level services. (The device has two physical batteries.). In Core Bluetooth, I can distinguish these by resolving the descriptors on the characteristics. The value of the CBMUUIDCharacteristicFormatString descriptor is different for the two services. I think that's the correct way to do it according to the spec.

But, I run into a problem when I try to mock this object. In CBMPeripheralSpecDelegate, I can implement the following method to return the data for the descriptor.

 func peripheral(_ peripheral: CBMPeripheralSpec, didReceiveReadRequestFor descriptor: CBMDescriptor) -> Result<Data, Error> 

But I don't think I have enough information here to distinguish between the two services. The UUID for both the service and the characteristic are the standard 'battery level' values (180F / 2A19). I don't see another way to differentiate between the two.

Am I missing something? Is there another identifier I can use? Nothing stood out looking through the source code. Is there another mechanism for supplying the value of a descriptor?

Thanks for the insight!

typealias file seems to hide KVO properties

Hello,
I've added as swift package dependency CoreBluetoothMock library and added as suggested the CoreBluetoothTypeAliases.swift to the project. Removed any reference to import CoreBluetooth in my framework project.
Everything seems ok, but I get an complire error here:

  let peripheralStatePublisher: AnyPublisher<PeripheralState, Never>
    
    init(_ peripheral: CBPeripheral) {
        self.cbPeripheral = peripheral
        self.peripheralStatePublisher = self.cbPeripheral.publisher(for: \.state)
            .map{ (state) -> PeripheralState in
                PeripheralState(state: state)
            }
            .share()
            .eraseToAnyPublisher()
        self.cbPeripheral.delegate = self.peripheralProxy
    }

What I'm trying to do is to leverage KVO and combine capabilities to create a publisher for peripheral state changes.
At the line where I try to get the publisher I get Value of type 'CBPeripheral' (aka 'CBMPeripheral') has no member 'publisher'.
I've tried also to import Foundation and Combine in the alias file, but I still get this error.
I'm using Xcode 11.5 and the 0.8.0 version of the library.

Simulated peripheral name always nil

When I am trying to simulate peripherals the name of the retrieved device is always nil.

What I did so far:

  1. Create a mock peripheral
 let mockGateway1 = CBMPeripheralSpec
                .simulatePeripheral(proximity: .near)
                .advertising(
                    advertisementData: [
                        CBMAdvertisementDataLocalNameKey    : "mock1",
                        CBMAdvertisementDataServiceUUIDsKey : [CBMUUID(string: "f9505467-a5c5-42c2-95c8-0ec77aeXXXX")],
                        CBMAdvertisementDataIsConnectable   : true as NSNumber
                    ],
                    withInterval: 0.250,
                    alsoWhenConnected: false)
                .connectable(
                    name: "mock1",
                    services: [],
                    delegate: nil,
                    connectionInterval: 0.150,
                    mtu: 23)
                .build()
  1. Call simulatePeripherals and `simulateInitalState:
         CBMCentralManagerMock.simulatePeripherals([mockGateway1])
            CBMCentralManagerMock.simulateInitialState(.poweredOn)
  1. Then in didDiscover delegate I got one peripheral, but its name is always nil:

image

What did I wrong?

Introduce a way to provide own impl of CBMCentralManager

As @evnik suggested in #54 (comment) there should be a way to provide own implementation for CBMCentralManager. After #54 has been merged to develop it was refactored from a protocol to a class.

Questions:

  1. The new implementation is an open class, so it should be possible to extend it. It the protocol required?
  2. What name should it have?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.