How to check the status of bluetooth (OFF/Disconnect) in iOS programmatically - ios

I am using the centralManagerDidUpdateState in my code.
I can check the bluetooth ON/Off in programming like below:
#interface ViewController ()<CBCentralManagerDelegate,CBPeripheralManagerDelegate>
{
CBCentralManager *bleCentralManager;
CBPeripheralManager *blePeripheralManager;
}
#end
- (void)viewDidLoad {
[super viewDidLoad];
bleCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:#{CBCentralManagerOptionShowPowerAlertKey: #NO}];
blePeripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:#{CBConnectPeripheralOptionNotifyOnDisconnectionKey:#YES}];
bleStatus = #"CBManagerStateUnknown";
}
-(void) centralManagerDidUpdateState:(CBCentralManager *)central{
NSLog(#"centralManagerDidUpdateState:%ld",central.state);
switch (central.state) {
case CBManagerStateUnknown:
bleStatus = #"CBManagerStateUnknown";
break;
case CBManagerStateResetting:
bleStatus = #"CBManagerStateResetting";
break;
case CBManagerStateUnsupported:
bleStatus = #"CBManagerStateUnsupported";
break;
case CBManagerStateUnauthorized:
bleStatus = #"CBManagerStateUnauthorized";
break;
case CBManagerStatePoweredOff:
bleStatus = #"CBManagerStatePoweredOff";
break;
case CBManagerStatePoweredOn:
bleStatus = #"CBManagerStatePoweredOn";
break;
default:
break;
}
}
- (void)peripheralManagerDidUpdateState:(nonnull CBPeripheralManager *)peripheral {
NSLog(#"peripheral:%ld",(long)peripheral.state);
}
But in the iPhone control center, we can change the bluetooth status to disconnect,
the turn off status is can't recognition.
When the bluetooth icon disconnect and bluetooth(go to setting) turn off, I get the status is CBManagerStaePoweredOff.
We can refer the disconnect/off info in control panel below:
https://support.apple.com/en-us/HT208086
How can I check the status is Disconnect from Bluetooth icon or Turn off bluetooth(go to setting bluetooth edit turn off) in the control panel icon?
thank you very much.

Related

How to scan and connect to Bluetooth A2DP device on iOS programmatically

I have built an Android APP which handles the scan, return nearby devices, and connect steps on both BLE and Bluetooth A2DP, and it works well. Now I’m developing the iOS version which is with exactly the same functionalities. For the BLE part, I can use CoreBluetooth to perform what I need without any problems, yet I don’t know how to implement the steps of “scan -> return nearby discoverable devices -> connect” on iOS for Bluetooth A2DP device. The only solution I’ve found so far is to navigate to Settings page from my iOS APP and perform the connection on it. Is there any way to implement the Bluetooth A2DP connection process inside of my iOS APP programmatically?
in iOS, bluetooth works on central peripheral concept. below is the how it scan for nearby devices.
#import <UIKit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>
#interface MyViewController : UIViewController <CBPeripheralDelegate, CBCentralManagerDelegate>
{
CBCentralManager *mgr;
}
#property (readwrite, nonatomic) CBCentralManager *mgr;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
mgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog([NSString stringWithFormat:#"%#",[advertisementData description]]);
}
-(void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals{
NSLog(#"This is it!");
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
NSString *messtoshow;
switch (central.state) {
case CBCentralManagerStateUnknown:
{
messtoshow=[NSString stringWithFormat:#"State unknown, update imminent."];
break;
}
case CBCentralManagerStateResetting:
{
messtoshow=[NSString stringWithFormat:#"The connection with the system service was momentarily lost, update imminent."];
break;
}
case CBCentralManagerStateUnsupported:
{
messtoshow=[NSString stringWithFormat:#"The platform doesn't support Bluetooth Low Energy"];
break;
}
case CBCentralManagerStateUnauthorized:
{
messtoshow=[NSString stringWithFormat:#"The app is not authorized to use Bluetooth Low Energy"];
break;
}
case CBCentralManagerStatePoweredOff:
{
messtoshow=[NSString stringWithFormat:#"Bluetooth is currently powered off."];
break;
}
case CBCentralManagerStatePoweredOn:
{
messtoshow=[NSString stringWithFormat:#"Bluetooth is currently powered on and available to use."];
[mgr scanForPeripheralsWithServices:nil options:nil];
//[mgr retrieveConnectedPeripherals];
//--- it works, I Do get in this area!
break;
}
}
NSLog(messtoshow);
}

CBCentralManager state is Off, even-though the bluetooth is ON

I am trying to check whether the bluetooth is turned on/off with the following code. But it returns CBManagerStatePoweredOff even-though the bluetooth is already on. I checked it in iPhone6s and iOS version 11.2.5(15D60). If i restart bluetooth manually on the settings, It returns CBManagerStatePoweredOn.
- (void)detectBluetooth
{
if(!bluetoothManager)
{
// Put on main queue so we can call UIAlertView from delegate callbacks.
// NSDictionary *options = #{CBCentralManagerOptionShowPowerAlertKey: #NO};
// bluetoothManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:options];
bluetoothManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
[bluetoothManager scanForPeripheralsWithServices:nil options:nil];
}
[self centralManagerDidUpdateState:bluetoothManager]; // Show initial state
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSString *stateString = nil;
switch(central.state)
{
case CBManagerStateResetting:
stateString = #"The connection with the system service was momentarily lost, update imminent.";
break;
case CBManagerStateUnsupported:
stateString = #"The platform doesn't support Bluetooth Low Energy.";
break;
case CBManagerStateUnauthorized:
stateString = #"The app is not authorized to use Bluetooth Low Energy.";
break;
case CBManagerStatePoweredOff:
stateString = #"Bluetooth is currently powered off.";
break;
case CBManagerStatePoweredOn:
[self goToSearchDevices];
break;
default: stateString = #"State unknown, update imminent."; break;
}
}

WatchOS 4 App: CBCentralManager state is always in CBManagerStateUnsupported

I'm developing an app for Apple Watch Series 3, and it seems that the state of CBCentralManager is always CBManagerStateUnsupported.
I'm using the following code:
#import <CoreBluetooth/CoreBluetooth.h>
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSString *stateString = nil;
switch(central.state)
{
case CBManagerStateResetting:
stateString = #"The connection with the system service was momentarily lost, update imminent.";
break;
case CBManagerStateUnsupported:
stateString = #"The platform doesn't support Bluetooth Low Energy.";
break;
case CBManagerStateUnauthorized:
stateString = #"The app is not authorized to use Bluetooth Low Energy.";
break;
case CBManagerStatePoweredOff:
stateString = #"Bluetooth is currently powered off.";
break;
case CBManagerStatePoweredOn:
stateString = #"Bluetooth is currently powered on and available to use.";
[central scanForPeripheralsWithServices:nil options:
[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0]
forKey:CBCentralManagerOptionShowPowerAlertKey]];
break;
default:
stateString = #"State unknown, update imminent.";
break;
}
}
What am I doing wrong?

Detect Siri Remote from iPhone via Bluetooth

Is it possible to detect the Apple TV 4 Siri Remote from an iOS application using CoreBluetooth? I'm able to detect the Apple TV, but I'm not having any luck detecting the Siri Remote. The Siri Remote uses Bluetooth 4.0 so I'm assuming it is detectable. Ideally, I'd like to detect the Siri Remote even if it's already paired with the Apple TV.
Simply being able to detect any signal from the Siri Remote/know it's in the vicinity of the users iPhone is what I'm after.
#import "ViewController.h"
#import CoreBluetooth;
#interface ViewController () <CBPeripheralDelegate, CBCentralManagerDelegate>
#end
#implementation ViewController {
CBCentralManager *btManager;
}
-(void)viewDidLoad {
[super viewDidLoad];
btManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
#pragma mark - CBCentralManagerDelegate Methods
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"peripheral name: %#", peripheral.name);
NSLog(#"peripheral services: %#", peripheral.services);
NSLog(#"peripheral identifier: %#", peripheral.identifier);
NSLog(#"peripheral state: %ld", (long)peripheral.state);
NSLog(#"RSSI: %# \n\n", RSSI);
}
-(void)centralManagerDidUpdateState:(CBCentralManager *)central {
NSString *nsLogMessage;
switch (central.state) {
case CBCentralManagerStateUnknown: {
nsLogMessage = [NSString stringWithFormat:#"State unknown, update imminent."];
break;
}
case CBCentralManagerStateResetting: {
nsLogMessage = [NSString stringWithFormat:#"The connection with the system service was momentarily lost, update imminent."];
break;
}
case CBCentralManagerStateUnsupported: {
nsLogMessage = [NSString stringWithFormat:#"The platform doesn't support Bluetooth Low Energy"];
break;
}
case CBCentralManagerStateUnauthorized: {
nsLogMessage = [NSString stringWithFormat:#"The app is not authorized to use Bluetooth Low Energy"];
break;
}
case CBCentralManagerStatePoweredOff: {
nsLogMessage = [NSString stringWithFormat:#"Bluetooth is currently powered off."];
break;
}
case CBCentralManagerStatePoweredOn: {
nsLogMessage = [NSString stringWithFormat:#"Bluetooth is currently powered on and available to use."];
NSDictionary *scanningOptions = #{CBCentralManagerScanOptionAllowDuplicatesKey: #YES};
[btManager scanForPeripheralsWithServices:nil options:scanningOptions];
break;
}
}
NSLog(#"%#", nsLogMessage);
}

CBCentralManager scanForPeripheralsWithServices:nil is not returning any results

I am trying to display all available BLE beacons. I got some Estimote and Kontakt.io beacons with me and for some reason the below BLE scanning code does not find any of them.
I went through all the possible SO questions relating to BLE discovery and that codes is exactly as in other places.
App source code here
- (void)viewDidLoad {
[super viewDidLoad];
self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
/*
Request CBCentralManager to scan for all available services
*/
- (void) startScan
{
NSLog(#"Start scanning");
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[self.manager scanForPeripheralsWithServices:nil options:options];
}
This delegate method never gets called
/*
Invoked when the central discovers bt peripheral while scanning.
*/
- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)aPeripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(#"THIS NEVER GETS CALLED");
}
iBeacon's aren't accessed as peripherals - they are beacons. They are handled through the Core Location framework, not the Core Bluetooth framework.
There may be vendor specific services advertised by the beacons that can be detected by Core Bluetooth.
Your code doesn't wait until the CBCentralManager is in the powered on state. I made the following changes and it worked on both iOS 7.1 and iOS8 -
- (void)viewDidLoad {
[super viewDidLoad];
self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void) startScan
{
NSLog(#"Start scanning");
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[self.manager scanForPeripheralsWithServices:nil options:options];
}
- (BOOL) isLECapableHardware
{
NSString * state = nil;
switch ([self.manager state])
{
case CBCentralManagerStateUnsupported:
state = #"The platform/hardware doesn't support Bluetooth Low Energy.";
break;
case CBCentralManagerStateUnauthorized:
state = #"The app is not authorized to use Bluetooth Low Energy.";
break;
case CBCentralManagerStatePoweredOff:
state = #"Bluetooth is currently powered off.";
break;
case CBCentralManagerStatePoweredOn:
[self startScan];
return TRUE;
case CBCentralManagerStateUnknown:
default:
return FALSE;
}
NSLog(#"Central manager state: %#", state);
UIAlertView *alert = [[UIAlertView alloc] init];
[alert setMessage:state];
[alert addButtonWithTitle:#"OK"];
[alert show];
return FALSE;
}
The problem was posed by the version of the OS I was testing it with.
Let's just say this version that I was testing was 4+4 (as it is under the NDA)
Apparently that new version will abort scanning if you trigger
[self.manager scanForPeripheralsWithServices:nil options:options];
before
CBCentralManagerStatePoweredOn is ON
So simply starting scanning after that state made it work for me.
#pragma mark - CBCentralManager delegate methods
/*
Invoked whenever the central manager's state is updated.
*/
- (void) centralManagerDidUpdateState:(CBCentralManager *)central
{
[self isLECapableHardware]? NSLog(#"YES"):NSLog(#"NO");
}
- (BOOL) isLECapableHardware
{
NSString * state = nil;
switch ([self.manager state])
{
case CBCentralManagerStateUnsupported:
state = #"The platform/hardware doesn't support Bluetooth Low Energy.";
break;
case CBCentralManagerStateUnauthorized:
state = #"The app is not authorized to use Bluetooth Low Energy.";
break;
case CBCentralManagerStatePoweredOff:
state = #"Bluetooth is currently powered off.";
break;
case CBCentralManagerStatePoweredOn:
//---> HERE
[self startScan];
return TRUE;
case CBCentralManagerStateUnknown:
default:
return FALSE;
}
return FALSE;
}
I downloaded your code and found there was no call to startScan. Once I added that it worked for me. I added some details to the logging like this:
- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)aPeripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"Discovered %# %#", aPeripheral, advertisementData);
}
and I get this output:
2014-09-08 15:17:11.827 BTTest[4266:60b] New state 5
2014-09-08 15:17:11.830 BTTest[4266:60b] YES
2014-09-08 15:17:11.831 BTTest[4266:60b] Start scanning
2014-09-08 15:17:11.842 BTTest[4266:60b] CoreBluetooth[WARNING] <CBCentralManager: 0x17d6e5d0> is disabling duplicate filtering, but is using the default queue (main thread) for delegate events
2014-09-08 15:17:12.438 BTTest[4266:60b] per <CBPeripheral: 0x17d91220 identifier = C6E33BA0-F6E7-5830-0643-A47855AD27B9, Name = "(null)", state = disconnected> {
kCBAdvDataChannel = 37;
kCBAdvDataIsConnectable = 1;
}
2014-09-08 15:17:12.595 BTTest[4266:60b] per <CBPeripheral: 0x17d89b60 identifier = 4FF1E398-E24C-8739-A19B-9DF8A2A5493B, Name = "Flex", state = disconnected> {
kCBAdvDataChannel = 38;
kCBAdvDataIsConnectable = 1;
kCBAdvDataLocalName = Flex;
kCBAdvDataServiceData = {
"Device Information" = <0704>;
};
kCBAdvDataServiceUUIDs = (
"ADABFB00-6E7D-4601-BDA2-BFFAA68956BA"
);
kCBAdvDataTxPowerLevel = "-6";
}

Resources