在iOS Swift中想要在后台模式下运行广告外设

3

我刚刚使用服务和特征UUID创建了我的广告外设。

以下是我的服务和特征UUID:

let kTRANSFER_SERVICE_UUID                = “29ada058-c7d6-4ed5-bc7f-1c7b0458b3b8”                                   
let kTRANSFER_CHARACTERISTIC_UUID = “91e032f2-c915-47c6-a8d9-6b3bc6c8e73d”

现在我创建了CBPeripheralManager实例。
private var peripheralManager: CBPeripheralManager!
private let beaconOperationsQueue = DispatchQueue(label: "beacon_operations_queue")
private let option = [CBCentralManagerScanOptionAllowDuplicatesKey:true]

// Assign peripheralManager with Queue & Option
peripheralManager = CBPeripheralManager(delegate: self, queue: beaconOperationsQueue, options: option)

我现在正在调用StartAdvertising方法,但是这只能在前台模式下工作, 现在我想在后台模式下允许它工作,因此我在Info.plist中添加了UIBackgroundModes关键字。

 public func startAdvertising(serviceID: String, name: String) {

        let valueData = name.data(using: .utf8)

        self.serviceID = CBUUID(string: serviceID)
        self.peripheralName = name

        let CustomChar = CBMutableCharacteristic(type: CBUUID(string: kTRANSFER_CHARACTERISTIC_UUID), properties: [.read], value: valueData, permissions: [.readable])

        let myService = CBMutableService(type: self.serviceID, primary: true)
        myService.characteristics = [CustomChar]

        peripheralManager.add(myService)

        if self.peripheralManager.isAdvertising{

            self.peripheralManager.stopAdvertising()
        }
        peripheralManager.startAdvertising([
            CBAdvertisementDataServiceUUIDsKey: [serviceID],
            CBAdvertisementDataOverflowServiceUUIDsKey:[serviceID],
            CBAdvertisementDataLocalNameKey: peripheralName!])
    }

当进入后台时,会发生以下情况:

CBAdvertisementDataLocalNameKey广告键将被忽略,周边设备的本地名称不会被广告。

CBAdvertisementDataServiceUUIDsKey广告键中包含的所有服务UUID将放置在特殊的“溢出”区域中;它们只能被显式扫描它们的iOS设备发现。

我已经设置了“Overflow”,但仍无法在后台模式下工作,有人可以为此提供指导吗?


你怎么知道它没有在后台工作?你使用什么设备/应用程序来发现你的外围设备? - Paulw11
我们正在将BLE Scanner / NRF Connect应用程序用于另一个Android / iOS设备。在此过程中,我们试图查看由我的iOS手机广告的外围设备,该手机现在正在后台模式下运行该应用程序。在这种情况下,我的外围设备的服务和特征没有显示在任何应用程序中。只有当我的应用程序处于前台模式时才能正常工作。 - Nik Jack
当您的应用程序在后台进行广告时,您可能只能从另一个iOS设备扫描。您将无法在扫描数据中看到服务或特征,只有连接后才能看到。 - Paulw11
是的,在浅蓝色应用程序中它显示了设备,我能够连接设备,但它没有显示我正在广告的服务或特征,因此正在寻找一些必要的帮助。 - Nik Jack
让我们在聊天中继续讨论 - Paulw11
显示剩余3条评论
1个回答

10

苹果对CoreBluetooth广告和扫描在应用程序处于后台时的工作方式施加了限制,不幸的是,这种行为相当复杂,请耐心等待。

在本讨论中,“后台”指应用程序在屏幕上不可见的任何情况下。(例如:手机锁屏、屏幕关闭、显示Springboard或其他应用程序都是应用程序处于后台的情况。)

CBPeripheralManager GATT服务广告

  • 在后台,服务广告会更改为一个Apple专有格式,使用制造商广告,看起来像这样:0b ff 4c 00 10 06 57 1e fc 8a e1 7c。无论是在前台启动广告还是在后台启动广告,当广告BLE应用程序处于后台时,此广告都使用专有格式
  • 上述广告不包含服务UUIDs。无论CBAdvertisementDataServiceUUIDsKey中包含什么内容,都不会出现在广告中。
  • 上述广告不包含本地名称。无论CBAdvertisementDataLocalNameKey中包含什么内容,都不会出现在广告中。
  • 此广告仅适用于将特定服务UUIDs从CBAdvertisementDataServiceUUIDsKey传递给使用CBCentralManager在前台扫描的其他iOS设备。这是使用Apple专有技术实现的。实际的服务UUIDS仅由iOS在请求前台iOS应用程序扫描时,通过“溢出区域”提供。如果没有前台iOS应用程序进行扫描,则不会工作,因为实际的服务UUIDs永远不会从“溢出区域”中请求。

CBCentralManager GATT服务扫描

  • 在后台,没有指定服务UUID的扫描不会产生任何结果。如果您有如下代码:centralManager?.scanForPeripherals(withServices: nil, options: nil),则不会匹配任何内容。您必须明确指定服务UUIDs。

  • 尝试从同一设备请求多个广告的回调将得不到任何结果,因为后台忽略了CBCentralManagerScanOptionAllowDuplicatesKey选项。您只会在设备首次出现时获得一个回调。

  • 扫描特定服务UUID将成功,最多每个限制只提供一次回调,前提是广告设备不是处于后台的iOS应用程序。

  • 如果广告设备是处于后台的iOS应用程序,则广告将使用上述专有技术。因为中心在后台,iOS不会从处于后台的外围设备请求溢出区域。不会发生任何发现回调。

这会导致的最终结果是,iOS到iOS的GATT广告和发现仅在两个蓝牙应用程序中的一个在前台时才能工作。如果两个应用都在后台运行,则新的发现将不起作用。但是,现有的连接将继续工作,并且在两个应用都在后台时重新连接,如果设备消失并重新出现,则会提供新的发现回调。关键是发现必须在两个应用程序之一在前台时成功过一次。
要使上述内容起作用,您无需在开始广告时设置CBAdvertisementDataOverflowServiceUUIDsKey。如果广告应用程序在后台,则苹果将自动将任何值放入键CBAdvertisementDataServiceUUIDsKey的溢出区域。CBAdvertisementDataOverflowServiceUUIDsKey是只读的--收到扫描结果时可以访问此信息。您在广告时不使用它。
有趣的是:当您在此情况下拥有多个iOS设备(超过两个)时,中央和周边设备可以在两者都在后台时发现彼此,前提是有第三个iOS应用程序正在前台作为中央设备进行扫描。然后,该第三个iOS设备可以请求“溢出区域”,从而使处于后台状态的iOS设备可以监听此内容并通过窃听受益。
Android或其他非iOS设备可以扫描上述专有iOS广告,虽然它们无法看到Service UUID或从“溢出区域”请求它们,但仍可以连接并在连接内查询服务UUID。这是低效的,但可以工作。

没错,这都是真的。请参见https://dev59.com/rYnca4cB1Zd3GeqP9VS9。阅读http://www.davidgyoungtech.com/2020/05/07/hacking-the-overflow-area真是一种享受。David,干得好! - Anne van Rossum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接