iOS

iOS对于ANCS设备的处理

2022-06-08  本文已影响0人  飛天江郎

1.什么是ANCS?

ANCS是Apple Notification Center Service的简称,中文为苹果通知中心服务。
ANCS是苹果让周边蓝牙设备(手环、手表等)可以通过低功耗蓝牙访问IOS设备(iphone、ipad等)上的各类通知提供的一种简单方便的机制。

ANCS是基于BLE协议中的通用属性协议(Generic Attribute Profile,GATT)协议实现的,他是GATT协议的一个子集。在ANCS协议中,IOS设备作为gatt-server,而周边设备作为gatt client来连接和使用server提供的其他services。

详细的可以参考官网上的解释ANCS spec

2.带来的影响是什么?

目前iOS这边关于蓝牙的开发大多都是基于Ble来实现的,对连接断开有较深使用经验的人都知道,iOS蓝牙这边的Ble关于断连重新连接模块都是用的懒加载(再次连上同一个mac地址的ble设备,底层没有重新获取特征值,只是从缓存里读了一份给到上层)

所以ANCS带来的影响是:

既然无法断开,那就意味着一旦连上了就无法让别的手机去搜索到,而且杀死当前连上的应用后,也无法通过常规的手段(centerManager.scanForPeripherals(withServices: nil, options: nil))去搜索到设备。

3.如何解决?

以下提供了一个demo来感受一下整个过程:

import Foundation
import CoreBluetooth
class BLEManager: NSObject,CBCentralManagerDelegate,CBPeripheralDelegate{
    lazy var centerManager:CBCentralManager = {
        CBCentralManager(delegate: self, queue: DispatchQueue.main)
    }()
    var myPeripheral:CBPeripheral?
    private var list:[CBPeripheral] = []
    override init() {
        super.init()
    }
    func start(){
        centerManager.scanForPeripherals(withServices: nil, options: nil)
        print("⚠️ Need to hasPerfix your ble device's name or it maybe found nothing")
        DispatchQueue.main.asyncAfter(deadline: .now()+2, execute: {
            if let item = self.list.first {
                if item.state == .disconnected {
                    self.centerManager.connect(item, options: nil)
                }
            }
        })
    }
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case .unknown:
            break
        case .resetting:
            break
        case .unsupported:
            break
        case .unauthorized:
            break
        case .poweredOff:
            break
        case .poweredOn:
            centerManager.scanForPeripherals(withServices: nil, options: nil)
        @unknown default:
            break
        }
    }
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        if ((peripheral.name?.hasPrefix("AC701N_")) != nil){
            if peripheral.name == "AC701N_GJ" {
                centerManager.stopScan()
                list.append(peripheral)
                print("Did found:\n\(peripheral)")
            }
        }
    }
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        self.myPeripheral = peripheral
        self.myPeripheral?.delegate = self
        self.myPeripheral?.discoverServices(nil)
    }
    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
        print("disconnect Ble in this application !")
        print("The Ble ANCS device is alway here,you can watch it in system setting")
        let uuid = UUID(uuid: peripheral.identifier.uuid)
        let array = central.retrievePeripherals(withIdentifiers:[uuid])
        for item in array {
            print("Now the ble is founded in here:\n\(item)")
            DispatchQueue.main.asyncAfter(deadline: .now()+10) {
                print("Here is to reconnect by 10 sec.")
                self.centerManager.connect(item, options: nil)
            }
        }
    }
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        guard let services = peripheral.services else{
            return
        }
        for service in services {
            if service.uuid.uuidString == "AE00" {
                peripheral.discoverCharacteristics(nil, for: service)
            }
        }
    }
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        guard let charts = service.characteristics else { return }
        for chart in charts {
            if chart.uuid.uuidString == "AE01" {
                print("get wirte chart");
            }
            if chart.uuid.uuidString == "AE02" {
                print("get read chart")
            }
        }
        print("Please make sure pair in your phone ,it will disconnect by 10 sec.")
        DispatchQueue.main.asyncAfter(deadline: .now()+10) {
            print("go to cancel connect BLE")
            self.centerManager.cancelPeripheralConnection(peripheral)
        }
    }
}

运行起来:

class ViewController: UIViewController {
    var mgr = BLEManager()
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        mgr.start()
    }
}

log分析

2022-04-01 12:00:37.131809+0800 BleConnect[683:73634] [CoreBluetooth] API MISUSE: <CBCentralManager: 0x282755320> can only accept this command while in the powered on state
⚠️ Need to hasPerfix your ble device's name or it maybe found nothing
Did found:
<CBPeripheral: 0x2822540b0, identifier = A790557A-3B84-644B-B3AF-E8AC733D7089, name = AC701N_GJ, mtu = 0, state = disconnected>
get wirte chart
get read chart
Please make sure pair in your phone ,it will disconnect by 10 sec.
go to cancel connect BLE
disconnect Ble in this application !
The Ble ANCS device is alway here,you can watch it in system setting
Now the ble is founded in here:
<CBPeripheral: 0x2822540b0, identifier = A790557A-3B84-644B-B3AF-E8AC733D7089, name = AC701N_GJ, mtu = 23, state = disconnected>
Here is to reconnect by 10 sec.
get wirte chart
get read chart
Please make sure pair in your phone ,it will disconnect by 10 sec.
go to cancel connect BLE
disconnect Ble in this application !
The Ble ANCS device is alway here,you can watch it in system setting
Now the ble is founded in here:
<CBPeripheral: 0x2822540b0, identifier = A790557A-3B84-644B-B3AF-E8AC733D7089, name = AC701N_GJ, mtu = 23, state = disconnected>

最后注意的点

上一篇 下一篇

猜你喜欢

热点阅读