我们的系统包括一个带遥控装置的主设备。主要设备是GAP Central和GATT Server。远程控制单元通过BLE进行通告和连接,其中远程是GAP外围设备和GATT客户端。当按下遥控器上的按钮时,它会将按钮状态特征写入GATT服务器。
我们想要编写一个iOS应用程序来充当和替换遥控器。 iOS CoreBluetooth是否可以作为GAP外设运行,同时也是GATT客户端?应用程序必须作为外围设备进行广告,然后在连接后进行服务发现。应用程序按钮将对主设备的GAP Central GATT服务器上的特征执行写入请求。
我们的配置与GATT DB通常位于GAP外设上的标准BLE模型略有不同。但在我们的情况下,将主设备的设置存储在遥控器中是没有道理意义的。 iOS是否足够灵活以支持此配置?
只是为了澄清:你在谈论BLE服务请求。不幸的是,CoreBluetooth只支持一个方向的服务请求,即iOS设备是GAP Central,另一个GAP Peripheral可以在iOS设备上发现GATT服务器。这基本上是Pebble用来访问媒体控制(Apple Media Service)和通知(Apple Notification Center Service)的配件。您将在CBCentralManager上找到特殊字典键CBCentralManagerScanOptionSolicitedServiceUUIDsKey
以支持上述场景,但CBPeripheralManager上没有相应的支持您的场景。
希望有所帮助。
尽管许多组合都是有效的,但看起来CoreBluetooth会结合GAP和GATT角色。因此,即使您的iOS应用程序将自己宣传为BLE外围设备,您也可以使用CBCentralManager连接回中央设备。您可以使用retrieveConnectedPeripherals(withServices:)或retrievePeripherals(withIdentifiers:)来查找中央设备,而不是像在中央应用程序中那样进行扫描。
不幸的是,在didConnect
中没有CBPeripheralManagerDelegate方法。如果您打算使用retrievePeripherals(withIdentifiers:)
,您需要添加虚拟服务和特性,并让您的中央设备在连接后访问该特性。当您收到didReceiveRead
或didSubscribeTo
事件时,您可以连接回request.central.identifier
。使用retrieveConnectedPeripherals(withServices:)
比较简单,但在我的测试中并没有始终如一地返回中央设备。
retrieveConnectedPeripherals(withServices :)示例
import CoreBluetooth
// A GATT client for an iOS App that operates as a BLE Peripheral. CoreBluetooth requires using a CBCentralManager
// to use remote GATT services, but we don't have to actually scan for the remote device.
class GattClient: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
// Replace with your service UUIDs
let remoteServiceUUIDs = [CBUUID(string: "FACE")]
var centralManager: CBCentralManager!
var remoteDevice: CBPeripheral? = nil
var timer: Timer? = nil
override init() {
super.init()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if (central.state == .poweredOn) {
// There's no `didConnect` event we can listen for, so poll for connected devices.
timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: findConnectedDevice)
}
}
func findConnectedDevice(timer: Timer) {
// Don't scan, just connect to the device already connected to us offering the right services.
print("Searching for connected devices...")
let connectedPeripherals = centralManager.retrieveConnectedPeripherals(withServices: remoteServiceUUIDs)
print("Devices found: \(connectedPeripherals.count)")
if (connectedPeripherals.count == 1) {
remoteDevice = connectedPeripherals[0]
print("Connecting...")
centralManager.connect(remoteDevice!, options: nil)
timer.invalidate()
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Discovering services...")
peripheral.delegate = self
peripheral.discoverServices(remoteServiceUUIDs)
}
...
}