I am planning to start an ios application and was wondering if there is a way to trigger certain action such as finding location using google map on bluetooth connection (or disconnection)?
I know an apple map application has similar feature where it shows where your car is parked. Any references would be appreiciate.
Thanks.
You can try this in your viewController where you want to check:
var manager: CBCentralManager!
override func viewDidLoad(){
super.viewDidLoad()
manager = CBCentralManager()
manager.delegate = self
}
//CBCentralManager Delegate method
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
//poweredOn
case .resetting:
//resetting
case .unauthorized:
//unauthorized
case .unknown:
//unknown
case .unsupported:
//UnSupported
case .poweredOff:
//Bluetooth is not Connected.Please Enable it
}
the status in delegate will tell you what's the status of your Bluetooth.
Hope it helps!
Well there delegate methods which get fired after different states of connection. The best way I suggest you to do is implement the following delegate methods.
func centralManager(_ central: CBCentralManager,
didConnect peripheral: CBPeripheral) {
}
func centralManager(_ central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: Error?) {
}
And call a function to get your location in these cases. Additionally there are other delegate methods such as
func centralManagerDidUpdateState(_ central: CBCentralManager) {
}
func centralManager(_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?) {
}
But these cases does not cover the all the cases of connection and disconnection. But depending on your requirement you can implement either one. These are CBCentralManagerDelegate delegates.
CBCentralManager
CBCentralManagerDelegate
Related
Pre iPadOS 13.4 we needed to read/write to protected characteristic of a peripheral device in order to trigger pairing popup. Starting iPadOS 13.4 - the passcode popup seems to be triggered simply via a successful connection with the peripheral (CBCentralManager().connect(peripheral, options: nil)).
I need to further communicate with the peripheral in order to get the passcode before the pairing popup is displayed. Once the pairing popup is displayed - the peripheral stops responding to any further requests.
Is this a design change or a bug on 13.4? I cannot find anything on the web/apple's release notes for iPadOS 13.4.
If this is a design change - what is an elegant way of handling this?
The following code triggers pairing on didConnect peripheral:
//Sample Code
var centralManager: CBCentralManager?
var peripheral: CBPeripheral?
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
print("CentralManager state: Powered On")
centralManager?.scanForPeripherals(withServices: [advertisingUUID], options: nil)
print("Scanning for peripherals...")
default:
print("CentralManager state: Powered Off")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
self.peripheral = peripheral
self.peripheral?.delegate = self
centralManager?.connect(peripheral, options: nil)
centralManager?.stopScan()
}
func centralManager(_ central: CBCentralManager,
didConnect peripheral: CBPeripheral) {
print("Peripheral Connected")
}
func centralManager(_ central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: Error?){
print("Peripheral Disconnected")
}
Can we be notified in those situations? When iPhone's Bluetooth is on or off. When iPhone connects to or disconnect to another device by Bluetooth.
You can use CBCentralManager and add the CBCentralManagerDelegate methods to see when a peripheral device is connected / disconnected.
centralManagerDidUpdateState will give information about your iOS device's bluetooth state.
didConnectPeripheral and didDisconnectPeripheral can be used for monitoring connected devices when you connect to the device within your app using connect on your centralManager (seen in example below).
If you know the identifier of the device you want to check for, you can use CBCentralManager's retrievePeripheralsWithIdentifiers to check the connection status for devices that are connected independent of your app.
class ViewController: UIViewController, CBCentralManagerDelegate {
var centralManager:CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager.init(delegate: self, queue: DispatchQueue.main)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
centralManager.scanForPeripherals(withServices: nil, options: nil)
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
centralManager.connect(peripheral, options: nil)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("peripheral \(String(describing: peripheral.name)) connected")
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("peripheral \(String(describing: peripheral.name)) disconnected")
}
}
You can detect bluetooth On/Off status change implementing CBCentralManagerDelegate delegate of CoreBluetooth.
declare proparty like #property (nonatomic, strong) CBCentralManager *bluetoothManager;
And function like
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSLog(#"In status update function");
switch(self.bluetoothManager.state)
{
case CBManagerStateResetting:
_isBluetoothOn = NO;
break;
case CBManagerStateUnsupported:
_isBluetoothOn = NO;
break;
case CBManagerStateUnauthorized:
_isBluetoothOn = NO;
break;
case CBManagerStatePoweredOff:
_isBluetoothOn = NO;
break;
case CBManagerStatePoweredOn:
_isBluetoothOn = YES;
break;
default:
_isBluetoothOn = NO;
break;
}
}
I have a device (named later "scanner") and other devices (named later "stone"). Scanner can scan stones and display their information on build in display. Scanner can send stones information via Bluetooth and I want to read this data and use it in my app. I started code connection implementation but I discovered a problem. Here is my code:
import UIKit
import CoreBluetooth
class BluetoothViewController: UIViewController {
var manager:CBCentralManager!
var peripheral:CBPeripheral!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
}
}
extension BluetoothViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
central.scanForPeripherals(withServices: nil, options: nil)
}
else {
print("Bluetooth not available.")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("peripheral \(peripheral)")
print("rssi \(RSSI)")
print("advertisementData: \(advertisementData)")
print("--------")
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print(peripheral)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print(peripheral)
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print(peripheral)
}
}
extension BluetoothViewController: CBPeripheralDelegate {
}
The problem is scanner doesn't appear in
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
and
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
never call.
Note that my iPhone is connected with a scanner and scanner tell me the connection is working.
What I want to achieve?
I want to create viewcontroller which check if scanner is connected.
if connected then
get scan information
else
find device and connect
get scan information
Please help me. :)
Edit
In LightBlue Explorer app my scanner device doesn't appear.
But with this app works perfectly.
Maybe using CoreBluetooth is a wrong way to do this. What is better. If creators of above app can communicate thee is a possibility to do it.
Thanks #Paulw11's comment I realized my "scanner" uses iPod Accessory Protocol. To make sure I import ExternalAccessory framework and check for devices.
EAAccessoryManager.shared().showBluetoothAccessoryPicker(withNameFilter: nil, completion: nil)
After call this function I saw list of accessory devices and my scanner was there.
I'm trying to disconnect from a BLE device. I'm doing cancelPeripheralConnection() and its never calling didDisconnectPeripheral().
I'm setting notify value to one characteristic, so while disconnecting i'm setting it false.
{
BLEOperations.sharedInstance.connectedDevice?.setNotifyValue(false, for: BLEOperations.sharedInstance.peripheralCharacteristics[0])
BLEOperations.sharedInstance.manager.cancelPeripheralConnection(BLEOperations.sharedInstance.connectedDevice!)
}
I'm trying to disconnect connectedPeripheral when user tries to connect to new device. The current device is not disconnected but new device is connected along with old one.
{
BLEOperations.sharedInstance.manager.connect(self.peripheralArray[indexPath.row] as! CBPeripheral , options: nil)
}
What am i doing wrong here? When device connection is lost the method is being called.
It will work fine when the CentralManager has only one instance in the entire flow.
Instead of using centralmanagerdelegates in viewcontroller, you can create a CentralManager operations class (which is a singleton) and perform operations.
I did that and its working fine.
Well, probably we would need more information about your code. But the method you are looking for, is this one.
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
disconnected(central: central)
}
You should set your centralManager's delegate to self, and everytime a peripheral is disconnected it should call the delegate.
Doing some tests, the disconnection process is not as nice as it seems, you can see your peripheral is still disconnecting but the delegate has been called (this can be adjusted with the hardware itself or the firmware on your peripheral).
BTW, you can connect several devices at once.
Cancels an active or pending connection to peripheral
class ViewController: UIViewController, CBCentralManagerDelegate {
var manager: CBCentralManager!
var peripherals: [CBPeripheral]?
#IBAction func actionScanBLEDevice(_ sender: AnyObject) {
manager = CBCentralManager (delegate: self, queue: nil)
}
#IBAction func actionDisconnectBLE(_ sender: AnyObject) {
//Use As per need where you want to disconnect perticular peripheral
manager.cancelPeripheralConnection(peripheral[0]) // Disconnent numbers of BLE Devices
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
//Manage Some Condition then disconnect
print("Disconnected from peripheral")
peripherals?.append(peripheral)
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Discovered peripheral \(peripheral.name,peripheral.identifier.uuidString)")
print("advertisementData\(advertisementData)")
// Use discovered peripheral here
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("Checking")
switch(central.state)
{
case.unsupported:
print("BLE is not supported")
case.unauthorized:
print("BLE is unauthorized")
case.unknown:
print("BLE is Unknown")
case.resetting:
print("BLE is Resetting")
case.poweredOff:
print("BLE service is powered off")
case.poweredOn:
print("BLE service is powered on")
print("Start Scanning")
manager.scanForPeripherals(withServices: nil, options: nil)
}
}
}
I read you can write apps for the new AppleTV. I read it runs a version of iOS. I read too that it has bluetooth capabilities.
Question, very simply, could I turn my AppleTV into an iBeacon, albeit a very expensive one? :)
The way you make an iOS device broadcast is, you create a CLBeaconRegion object with the UUID, major and minor you want to broadcast, call its peripheralDataWithMeasuredPower method, and pass the dictionary you obtain this way to CBPeripheralManager's startAdvertising method.
Now, tvOS lacks the CLBeaconRegion class, but has the CBPeripheralManager complete with the startAdvertising method. This means you should be able to generate the dictionary to pass to startAdvertising on an iOS device, take a loot at its content, and replicate it in your tvOS app.
In fact, people have already been doing it with OS X Mavericks in the past (I think Apple blocked this in Yosemite): http://www.blendedcocoa.com/blog/2013/11/02/mavericks-as-an-ibeacon/
Note: I haven't tried this method myself. It's entirely possible Apple blocked this trick on tvOS just liked they did on OS X.
Seeing as people "jailbreak" (or outright install Linux on) Apple TVs, you can install pretty much anything. Since iBeacon is a standard Apple opened (and for which there is open source code), I'd say the answer is "yes".
Ok, I got around to testing this at last, with the result ok, some promise. Here is the details, tvOS doesn't have CLRegion, will not compile, so the official route for iBeacon don't work.
Did however get it to see the iBeacon with this code; so there is hope... maybe not with iBeacons, but Bluetooth...
This is the BLE code I used...
import Foundation
import CoreBluetooth
class BLEManager {
var centralManager : CBCentralManager!
var bleHandler : BLEHandler // delegate
required init() {
self.bleHandler = BLEHandler()
self.centralManager = CBCentralManager(delegate: self.bleHandler, queue: dispatch_get_main_queue())
}
}
class BLEHandler : NSObject, CBCentralManagerDelegate {
override init() {
super.init()
}
func centralManagerDidUpdateState(central: CBCentralManager) {
switch (central.state)
{
case .Unsupported:
print("BLE is unsupported")
case .Unauthorized:
print("BLE is unauthorized")
case .Unknown:
print("BLE is unknown")
case .Resetting:
print("BLE is reseting")
case .PoweredOff:
print("BLE is powered off")
case .PoweredOn:
print("BLE is powered on")
central.scanForPeripheralsWithServices(nil, options: nil)
default:
print("BLE default")
}
print("centralManagerDidUpdateState")
}
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
print("didConnectPeripheral")
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print("\(peripheral.name) : \(RSSI) dBm")
}
func centralManager(central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?) {
}
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
print("didDiscoverServices")
}
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
print("didDiscoverCharacteristicsForService")
}
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
print("didUpdateValueForCharacteristic")
}
func peripheral(peripheral: CBPeripheral, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
print("didUpdateNotificationStateForCharacteristic")
}
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print("didDisconnectPeripheral")
}
}
With these lines in the viewontroller
var bleManager: BLEManager!
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
bleManager = BLEManager()
Need to say a special thank you to rhythmic-fistman who helped me with the code!