为啥我的 CBPeripheralManager 有广告但无法被发现?

Posted

技术标签:

【中文标题】为啥我的 CBPeripheralManager 有广告但无法被发现?【英文标题】:Why is my CBPeripheralManager advertising but not discoverable?为什么我的 CBPeripheralManager 有广告但无法被发现? 【发布时间】:2017-08-25 18:56:54 【问题描述】:

我正在使用我的 iPhone 作为外围设备和我的 mac 作为中心来制作一个核心蓝牙应用程序。我的 iPhone 已开机并有广告,但在蓝牙浏览器中,其他 iPhone 和 Mac 无法发现它。但是,我朋友的安卓手机可以发现它。这是怎么回事? ios端:

import UIKit
import CoreBluetooth

class ViewController: UIViewController, CBPeripheralManagerDelegate 

@IBOutlet weak var statusLabel: UILabel!
@IBOutlet weak var connectionInfoLabel: UILabel!
var peripheralManager: CBPeripheralManager!
var accelerometerXCharacteristic: CBMutableCharacteristic!
var phoneDataService: CBMutableService!
var accelerometerXData: Data!

override func viewDidLoad() 
    super.viewDidLoad()

    connectionInfoLabel.isHidden = true
    //Ignore this I was testing the data encoding
    let accelerometerVal = "45"
    let someData = accelerometerVal.data(using: String.Encoding.utf8)
    let revertedString = String(data: someData!, encoding: String.Encoding.utf8)! as String
    let integer = Int(revertedString)!
    print(integer)

    setupBT(delegate: self, intialXData: someData!)


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.


func setupBT(delegate: CBPeripheralManagerDelegate, intialXData: Data) 
    peripheralManager = CBPeripheralManager(delegate: delegate, queue: nil)
    //print(peripheralManager.state)

    let accelerometerXCharacteristicUUID = CBUUID(string: "07B24C73-C35B-45C7-A43D-58240E3DB4DF")
    let phoneDataServiceUUID = CBUUID(string: "CAB1B028-2243-4F2C-A2F1-3BE5AD51AD61")

    accelerometerXCharacteristic = CBMutableCharacteristic(type: accelerometerXCharacteristicUUID, properties: CBCharacteristicProperties.read, value: intialXData, permissions: CBAttributePermissions.readable)

    phoneDataService = CBMutableService(type: phoneDataServiceUUID, primary: true)
    phoneDataService.characteristics = [accelerometerXCharacteristic]





func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) 
    var statusMessage = ""

    switch peripheral.state 
    case .poweredOn:
        statusMessage = "Bluetooth Status: Turned On"
        peripheralManager.add(phoneDataService)
        peripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey : [phoneDataService.uuid], CBAdvertisementDataLocalNameKey: "DSiPhone"])

    case .poweredOff:
        statusMessage = "Bluetooth Status: Turned Off"

    case .resetting:
        statusMessage = "Bluetooth Status: Resetting"

    case .unauthorized:
        statusMessage = "Bluetooth Status: Not Authorized"

    case .unsupported:
        statusMessage = "Bluetooth Status: Not Supported"

    default:
        statusMessage = "Bluetooth Status: Unknown"
    

    print(statusMessage)



func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) 
    if ((error) != nil) 
        print("Error \(error!.localizedDescription)")
    


func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) 
    print("Advertising")
    if ((error) != nil) 
        print("Error advertising \(error!.localizedDescription)")
    


func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) 
    var requestedCharacteristic: CBMutableCharacteristic?
    switch request.characteristic.uuid 
    case accelerometerXCharacteristic.uuid:
        requestedCharacteristic = accelerometerXCharacteristic
    default:
        requestedCharacteristic = nil

    
    if let characteristic = requestedCharacteristic 
        if request.offset > characteristic.value!.count 
            request.value = characteristic.value?.subdata(in: request.offset..<(characteristic.value!.count - request.offset))
            peripheralManager.respond(to: request, withResult: CBATTError.success)
         else 
            peripheralManager.respond(to: request, withResult: CBATTError.invalidAttributeValueLength)
        
     else 
        peripheralManager.respond(to: request, withResult: CBATTError.attributeNotFound)
    


func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) 
    print("Connection Successful")
    statusLabel.text = "Successful!"
    let didSendValue = peripheralManager.updateValue(accelerometerXData, for: characteristic as! CBMutableCharacteristic, onSubscribedCentrals: nil)
    if !didSendValue 
        print("Send failed")
    


正在打印蓝牙状态已打开和广告。在 Mac 端:

import Cocoa
import CoreBluetooth

class ViewController: NSViewController, CBCentralManagerDelegate 
var centralManager: CBCentralManager!
override func viewDidLoad() 
    super.viewDidLoad()
    centralManager = CBCentralManager(delegate: self, queue: nil)

    // Do any additional setup after loading the view.


override var representedObject: Any? 
    didSet 
    // Update the view, if already loaded.
    


func setupBT() 



func centralManagerDidUpdateState(_ central: CBCentralManager) 
    var statusMessage = ""
    switch central.state 
    case .poweredOn:
        centralManager.scanForPeripherals(withServices: [CBUUID(string: "CAB1B028-2243-4F2C-A2F1-3BE5AD51AD61")], options: nil)
        statusMessage = "Bluetooth Status: Turned On"

    case .poweredOff:
        statusMessage = "Bluetooth Status: Turned Off"

    case .resetting:
        statusMessage = "Bluetooth Status: Resetting"

    case .unauthorized:
        statusMessage = "Bluetooth Status: Not Authorized"

    case .unsupported:
        statusMessage = "Bluetooth Status: Not Supported"

    default:
        statusMessage = "Bluetooth Status: Unknown"
    

    print(statusMessage)


func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) 
    print("Discovered")


打印出蓝牙已开启,但没有发现任何东西。

【问题讨论】:

你是如何尝试发现你的外围设备的? 在设置中使用蓝牙设备浏览器没有发现它,我的 Mac 核心蓝牙应用程序也没有。如有需要可提供mac代码 @BrandonA 我添加了 Mac 代码 我运行了你的代码,它运行良好;尝试重新启动您的 Mac 和/或 iOS 设备 @paulw11 合法吗? Mac 使用该代码发现了 iPhone? 【参考方案1】:

我首选的扫描外围设备的方法是不明确要求任何服务。我发现当CBCentralManager 有时无法从广告本身指示服务时,走这条路线会导致头痛。

相反,发现您感兴趣的外围设备的更可靠方法是不在您的scanForPeripheral 参数中指定任何服务,并且只扫描一次所有内容。在您的 options 字典中包含 CBCentralManagerScanOptionAllowDuplicatesKey 键,其值为 false 包装在 NSNumber 中。

当您收到来自didDiscover peripheral: 方法的回调时,请查看advertisingData。它将有一个名为kCBAdvDataServiceUUIDs 的字段。这将是您放置在外围设备上的一组服务 UUID。检查这些(通常只有一个),看看是否有任何匹配您感兴趣的服务 UUID,如果是,这些是您的外围设备。


扫描

注意:通常我会定期执行此操作。

let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: false)]
centralManager?.scanForPeripherals(withServices: nil, options: options)

回调

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) 
    if let ids = advertisementData["kCBAdvDataServiceUUIDs"] as? [CBUUID], 
    let id = ids.first, 
    id == CBUUID(string: "YourServiceID") 
        print("Found Peripheral \(peripheral)")
    

【讨论】:

这是最好的答案。【参考方案2】:

仅供参考,那里的代码在重新启动后工作得很好,所以显然这是核心蓝牙的一个小故障。如果其他人有这个问题,一定要试试这个!

【讨论】:

以上是关于为啥我的 CBPeripheralManager 有广告但无法被发现?的主要内容,如果未能解决你的问题,请参考以下文章

终止连接 CBPeripheralManager 端

获取 CBPeripheralManager 订阅的 Centrals

CBPeripheralManager 延迟停止广告/位置管理器范围停止 iBeacon

CBPeripheralManager AddService 上的 iOS 崩溃断言失败:

CBPeripheralManager startAdvertising 在 OS X yosemite 上不起作用

ios设备app作为蓝牙外设端