ShEsKo ShEsKo - 2 months ago 44
Swift Question

CBPeripheral Service seems to be invisible

I am implementing a CentralManager with the CoreBluetooth framework in order to extract values provided by peripherals.

I first look for peripherals that have a service with a specific UUID ("52486FA8-FF0B-4A91-A344-D642D0E91AD0"). The CentralManager finds the peripheral but when I try to print the Services of that peripheral, I get an empty array.

Here is my code

//
// ViewController.swift
// centralLearn
//
// Created by Francesco Vanduynslager on 24/09/2016.
// Copyright © 2016 Francesco Vanduynslager. All rights reserved.
//

import UIKit
import CoreBluetooth

class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var centralManager: CBCentralManager!
var discoveredPeripherals: [CBPeripheral]!

let serviceUUID = CBUUID(string:"52486FA8-FF0B-4A91-A344-D642D0E91AD0")

override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
discoveredPeripherals = []
}

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

func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("Central Started")
centralManager.scanForPeripherals(withServices: [serviceUUID],
options: nil)
} else if central.state == .poweredOff {
centralManager.stopScan()
}
}

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Discovered Peripheral: \(peripheral.name)")
self.discoveredPeripherals.append(peripheral)
centralManager.connect(peripheral, options: nil)
centralManager.stopScan()
}

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Connected to peripheral!! \(peripheral)")
print("count: \(peripheral.services?.count)")
peripheral.delegate = self

if (peripheral.services == nil) {
peripheral.discoverServices([serviceUUID])
}
}

func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if error != nil {
print("Discover service Error: \(error)")
} else {
print("Discovered Service")
for service in peripheral.services!{
print("SERV: \(service)")
peripheral.discoverCharacteristics([CBUUID(string: "5A5E5393-4505-471C-BA90-7AD044FFFD9C")], for: service)
}
print(peripheral.services)
print("DONE")
}
}

func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
let characteristic = service.characteristics?[0]
print("Discovered Characteristic")
peripheral.readValue(for: characteristic!)
}


func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if error != nil {
print("Read value service Error: \(error)")
} else {
print("Value of Characteristic: \(characteristic.value)")
}
}
}


And the resulting prints are as follow:

Central Started
Discovered Peripheral: Optional("-ShEsKo-")
Connected to peripheral!! <CBPeripheral: 0x1740f7d00, identifier = A9B3F888-99E1-C62B-DF93-87F1F99AE847, name = -ShEsKo-, state = connected>
count: nil
Discovered Service
Optional([])
DONE


EDIT

Here is my peripheral code:

//
// ViewController.swift
// peripheralLearn
//
// Created by Francesco Vanduynslager on 24/09/2016.
// Copyright © 2016 Francesco Vanduynslager. All rights reserved.
//

import UIKit
import CoreBluetooth
import CoreLocation

class ViewController: UIViewController, CBPeripheralManagerDelegate {
var localBeacon: CLBeaconRegion!
var beaconPeripheralData: NSDictionary!
var peripheralManager: CBPeripheralManager!

var services: [CBMutableService]!

override func viewDidLoad() {
super.viewDidLoad()
initLocalBeacon()
// Do any additional setup after loading the view, typically from a nib.
}

func initLocalBeacon() {
if localBeacon != nil {
stopLocalBeacon()
}

let localBeaconUUID = "B65D79F6-74A2-482F-A669-FA5AB35CD3B8"
let localBeaconMajor: CLBeaconMajorValue = 123
let localBeaconMinor: CLBeaconMinorValue = 456

let uuid = UUID(uuidString: localBeaconUUID)!
localBeacon = CLBeaconRegion(proximityUUID: uuid, major: localBeaconMajor, minor: localBeaconMinor, identifier: "Your private identifer here")

beaconPeripheralData = localBeacon.peripheralData(withMeasuredPower: nil)
peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: nil)



/// FIRST SERVICE
let serviceUUID = CBUUID(string: "52486FA8-FF0B-4A91-A344-D642D0E91AD0")
let characteristicUUID = CBUUID(string: "5A5E5393-4505-471C-BA90-7AD044FFFD9C")

let characteristic = CBMutableCharacteristic(type: characteristicUUID,
properties: .read,
value: "hello".data(using: .utf8),
permissions: .readable)

let service = CBMutableService(type: serviceUUID, primary: true)

service.characteristics = [characteristic]

services=[service]
peripheralManager.add(service)
}

func stopLocalBeacon() {
peripheralManager.stopAdvertising()
peripheralManager = nil
beaconPeripheralData = nil
localBeacon = nil
}

func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
print("peripheral Started")
// peripheralManager.startAdvertising(beaconPeripheralData as! [String: AnyObject]!)
peripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey: [services[0].uuid, services[1].uuid]])
} else if peripheral.state == .poweredOff {
peripheralManager.stopAdvertising()
}
}

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

func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
if (error != nil){
print("ERROR starting advertising")
}else{
print("Did Start advertising")
}
}

func peripheralManager(_ peripheral: CBPeripheralManager, willRestoreState dict: [String : Any]) {
print("Restoring state")
}

func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
if (error != nil) {
print("ERROR adding service: \(error)")
}else{
print("Service added: \(service)")
}
}
}

Answer

Your problem is in your peripheral code. You can't add the service to the CBMutablePeripheral until the CBPeripheralManager is in the powered on state.

I suggest you move your service to its own function and call this function when you are in the powered on state.

func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
    if peripheral.state == .poweredOn {
        print("peripheral Started")
        //            peripheralManager.startAdvertising(beaconPeripheralData as! [String: AnyObject]!)
        self.setupService()
    } else if peripheral.state == .poweredOff {
        peripheralManager.stopAdvertising()
    }
}

func setupService() {
    let serviceUUID = CBUUID(string: "52486FA8-FF0B-4A91-A344-D642D0E91AD0")
    let characteristicUUID = CBUUID(string: "5A5E5393-4505-471C-BA90-7AD044FFFD9C")

    let characteristic = CBMutableCharacteristic(type: characteristicUUID,
                                                 properties: .read,
                                                 value: "hello".data(using: .utf8),
                                                 permissions: .readable)

    let service = CBMutableService(type: serviceUUID, primary: true)

    service.characteristics = [characteristic]

    services=[service]
    peripheralManager.add(service)
    peripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey: [services[0].uuid]])

}