I have an app which is working in background. I use CBPeripheralManager to Advertising and CBCentralManager to scan. I use two ıos (IOS 11.3 and IOS 13.4.1) device. First one is advertising foreground and background. Second one is scan foreground and background. I can scan;
App in the background, phone is unlocked - Works perfect
App in background, phone is locked, screen is lighted - Works perfect
App in background, phone locked, screen is off - Doesn't work!
/* I check it Advertising app which run background show in Android Device */
What is the problem. Please let me know. How can solve this problem? I want to scan both in background. My code is given bellow;
let scanOptions = [
CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: true)
]
let services = [CBUUID(string: "e2c56db5-dffb-48d2-b060-d0f5a71096e0")]
let advertisingData = [
CBAdvertisementDataLocalNameKey: "xxx",
CBAdvertisementDataServiceUUIDsKey:[CBUUID(string: "e2c56db5-dffb-48d2-b060-d0f5a71096e0")]
] as [String : Any]
func initLocal() {
peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: nil)
cbCentralManager = CBCentralManager(delegate: self, queue: nil,options: nil)
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
peripheralManager.startAdvertising(advertisingData)
}
else if peripheral.state == .poweredOff {
peripheralManager.stopAdvertising()
}
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn{
central.scanForPeripherals(withServices: services,options:scanOptions)
print("scanning...")
}
else {
print("Bluetooth is not active")
}
}
func centralManager(_ central: CBCentralManager,didDiscover peripheral: CBPeripheral,advertisementData: [String : Any],
rssi RSSI: NSNumber)
{
print("RSSI : \(RSSI)")
}
This is my info.plist;
You seem to be expecting duplicates since you've set CBCentralManagerScanOptionAllowDuplicatesKey. That key is ignored in the background. If you're expecting to see the same device more than once via advertising, that's impossible. Discovering new devices that you haven't seen before should work, however. Are you having trouble with that? (You should explain the details of exactly how you're testing this, what precise behaviors you see, and what you expect to see. Bluetooth is very subtle. The details matter quite a lot, and "not working" is far too vague.)
Related
This question already has answers here:
CoreBluetooth and BluetoothManager, device is not BLE
(2 answers)
Closed 3 years ago.
I am trying to discover Bluetooth LE and Classic (BR/EDR) device using Core Bluetooth framework in my app which is running on iOS-13. But I am able to find only BLE devices.
How I can scan for Bluetooth Classic devices?
After initialising CBCentralManager and getting the state of CentralManager as powered on, I am scanning for peripheral devices by passing nil in Services and Options.
Code mentioned below :-
private var cbManager: CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
cbManager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
cbManager.scanForPeripherals(withServices: nil, options:nil)
default:
os_log("Cleaning up cbManager")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if let name = peripheral.name {
print(name)
}
}
Through this I am only getting BLE devices. Expected result should be : BLE and Classic(BR/EDR) devices list.
Inside your .powerOn add this to be able to match on a specific service UUID.
let matchingOptions = [CBConnectionEventMatchingOption.serviceUUIDs: [uuid-to-classic-bt-device]]
cbManager.registerForConnectionEvents(options: matchingOptions)
Then in the delegate method centralManager:connectionEventDidOccur:forPeripheral: you can check for the events .peerDisconnected and .peerConnected to do something with the peripheral you found.
Apple provides an example of this Using Core Bluetooth Classic
I am trying to write an app in Swift that discovers a Android phone (pixel 2). However, it is not showing up in the results. I can however find the pixel in the regular bluetooth settings of the iphone (it's an iphone 8).
My code to discover the Android phone:
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if (central.state == .poweredOn) {
print("Powered on, starting scan")
self.centralManager?.scanForPeripherals(withServices: nil, options: nil)
} else {
print("BT not powered on")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral)
}
It shows me other BT devices but not the Android phone. I also did write an Android app to explicitly enable BT discoverability just in case. But still not showing up.
As #Paulw11 has mentioned, I had to create a BLE GATT service to detect it.
Just look at this example here: https://github.com/androidthings/sample-bluetooth-le-gattserver If you implement the Android app in that way, the iOS app will discover the service.
I have an app that works (so far so good) in connecting my iOS device to a bluetooth arduino, as of now this has been mostly for practice, but now I received the real thing that I'm supposed to connect to.
The problem is that I can't find it! (when I search for it).
If I do scanwithservices: nil, I can see the device and connect to it. However if i scanwithservices: [device'sCBUUID] then I don't get anything.
I double/triple/quatrupled checked the CBUUID using other apps, using my own app and looking at the device documentation, however no matter what I can't find it.
It has a custom CBUUID, from what I've read that's not standard, the CBUUID is:
BLETPodService = CBUUID(string: "4D494B45-414c-5741-5953-524F434B5321")
Searching for this yields nothing, however if I scan for nil I find it and if i check it's characteristics using the Bluefruit app (from Adafruit) I can see it's services and characteristics ID and they match that string I posted in here!
I told a friend and he said it's a BLE bug thats been there for ages (regarding custom CBUUIDs), is this true? is there really no fix for this?
EDIT adding the full scanning code just FYI:
func centralManagerDidUpdateState(_ central: CBCentralManager) {
var statusMessage = ""
switch (central.state)
{
case .unsupported:
statusMessage = "Bluetooth Low Energy is not supported!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .unauthorized:
statusMessage = "Bluetooth Low Energy is not authorized!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .unknown:
statusMessage = "Bluetooth Low Energy is unknown!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .poweredOff:
statusMessage = "Bluetooth Low Energy is powered off!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .resetting:
statusMessage = "Bluetooth Low Energy is resetting!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .poweredOn:
statusMessage = "BLE is ready!" //If BLE is ready then start scanning right away!
peripheralsFoundNames.removeAll()
peripheralsFoundCB.removeAll()
peripheralsFoundRSSIs.removeAll()
peripheralsFoundData.removeAll() //Remove previous data from previous scans
central.scanForPeripherals(withServices: nil, options: nil)
}
}
//What happens when you discover a peripheral
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
//What to do when it discovers a peripheral, add it to the array list
print("Peripheral found: " + (peripheral.name ?? "Unknown Name"))
peripheralsFoundNames.append((peripheral.name ?? "Unknown Name"))
peripheralsFoundData.append((advertisementData.description ))
peripheralsFoundCB.append(peripheral)
peripheralsFoundRSSIs.append(RSSI)
}
I happen to be working on both BLE firmware and iOS App at the same time.
I had the same issue that the filter not working.
The reason that iOS couldn't find the device with the UUID is that the device doesn't include the UUID when it is advertising.
I had to change the device firmware to add service UUID in the advertising data packet. With device advertising the UUID, UUID filter worked as expected.
I also had this problem, but I've found some tricky way.
You can try to match UUIDs (string value) directly in didDiscoverPeripheral func:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
if let services = peripheral.services {
for service in services {
if service.uuid.uuidString.lowercased() == "4D494B45-414c-5741-5953-524F434B5321".lowercased() {
if !peripheralsFoundCB.contains(peripheral) {
peripheralsFoundCB.append(peripheral)
}
}
}
}
}
If this way doesn't work for you I have one more:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
peripheral.discoverServices(nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let services = peripheral.services {
for service in services {
if service.uuid.uuidString.lowercased() == "4D494B45-414c-5741-5953-524F434B5321".lowercased() {
if !peripheralsFoundCB.contains(peripheral) {
peripheralsFoundCB.append(periphera
}
}
}
}
}
Of course you should use
scanwithservices: nil
Swift 3:
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
self.selectPeripheral.discoverServices(nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
let services = peripheral.services as [CBService]!{
for service in services{
if service.uuid.uuidString == "4D494B45-414c-5741-5953-524F434B5321"{
print("service found")
}
}
}
}
I am having exactly the same issue. Currently I might do the same solution suggested by the folks here! But I think its a problem from the hardware side.
I believe what is happening that your EE is not broadcasting the service UUID! What I mean by that if you printed the advertisedInfo you will not see the the following key-value pair in the info:
"kCBAdvDataServiceUUIDs": <__NSArrayM 0x14e6f3b0>("Your CBUUID")
You might see the name key-value and other stuff but definitely not the one I specified.
For that reason if he can do his part by broadcasting the service UUID's then you will be able to scan for that using the following method.
scanForPeripherals(withServices: ["Your CBUUID"], options: nil)
And you will see it :)
I am attempting to follow the tutorial on this page, towards listing and communicating with BLE devices.
Unlike the author, I am not interested in making a GUI application, and would rather keep it console based.
I have made two files to test bluetooth communication, main.swift and BluetoothWorker.swift.
The main class looks as follows:
import Foundation
var worker = BluetoothWorker();
worker.findStretchSensor();
while worker.foundAddresses.isEmpty {
print("### no devices found, sleeping");
sleep(5);
print("### done sleeping");
}
Here is how my Bluetooth class looks like:
import Foundation
import CoreBluetooth;
class BluetoothWorker: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
var foundAddresses = [String]();
var manager = CBCentralManager();
var myPherif: CBPeripheral?;
func findStretchSensor() {
manager = CBCentralManager(delegate: self, queue: nil);
print("### we are in the find sensor");
if (myPherif != nil) {
print("### we are canceling");
manager.cancelPeripheralConnection(myPherif!);
}
print("### we are scanning for devices");
manager.scanForPeripherals(withServices: nil, options: nil);
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("### we are checking the state");
if (central.state != CBCentralManagerState.poweredOn) {
print("### bluetooth is not available");
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("we found a device");
if (peripheral.name != nil) {
let message: String = "found peripheral:: " + peripheral.name!;
foundAddresses.append(peripheral.name!);
print(message);
}
}
}
My console output looks as follows:
### we are in the find sensor
### we are scanning for devices
### no devices found, sleeping
### done sleeping
### no devices found, sleeping
### done sleeping
### no devices found, sleeping
I cannot for the life of me figure out why any of the devices are not listed, ad why the delegated methods are not executing. If I download this example library ( that works very similar to one of my bluetooth devices ), my device is recognized. ( Note, this library is also GUI based )
Is there something obvious I am missing?
Two things I'm seeing here:
You're calling worker.findStretchSensor() too early.
You have to wait until centralManagerDidUpdateState() reports central.state == CBCentralManagerState.poweredOn, i.e:
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("### we are checking the state");
if (central.state == .poweredOn) {
findStretchSensor()
}
}
You're wrongly assuming that central.state is already powered when you create a CBCentralManager. That's not the case. It takes a while to receive the .poweredOn state.
Since you're running an application without GUI, the main queue might not be adequate for handling the Bluetooth events, i.e. there might be no event loop where the Bluetooth stack could dispatch the events to. Probably that's why you're not getting any call to centralManagerDidUpdateState().
Have you tried creating passing a queue for the central manager? I.e.:
queue = ...
manager = CBCentralManager(delegate: self, queue: queue)
i want to detect an altBeacon (transmitted by an Android Smartphone with the QuickBeacon App) with CoreBluetooth and Swift.
But when I search for a specific UUID the delegate method is not being called.
func centralManagerDidUpdateState(central: CBCentralManager!){
if (central.state == .PoweredOff) {
println("CoreBluetooth BLE hardware is powered off")
}
else if (central.state == .PoweredOn) {
var UUIDObj:NSArray! = [CBUUID(string: "2f234454-cf6d-4a0f-adf2-f4911ba9ffa6")]
self.centralManager.scanForPeripheralsWithServices(UUIDObj as [AnyObject], options: nil)
NSLog("Scanning started"); }}
Normally this method should be called
func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) {
When i change the Beacon Format to "iBeacon" it also don't work.
Does anybody know how i can get the advertising values of the AltBeacon and iBeacon standard with coreBluetooth?
Update:
When i search for all peripheral devices i get this information from my AltBeacon:
in DidDiscoverPeripheral
AdvertisementData: [kCBAdvDataIsConnectable: 0]
RSSI: -47
Peripheral Name: nil , State: (Enum Value) , Services:nil, RSSI:nil,ID: <__NSConcreteUUID 0x17002edc0> A91CBF8C-DA69-B2FB-1A9A-CDDB60A48209 , Description:
But the UUID does not match with the given ID :(
I can answer a part of your question: The CBCentralManager's delegate methods (e.g. func centralManagerDidUpdateState(central: CBCentralManager!)) are only called if you instantiate the manager with a queue, i.e. using init(delegate:queue:) or init(delegate:queue:options:) instead of just init()...