I want to find Bluetooth devices and get RSSI values using certain period time. I can scan iBeacons. But I also want to find the other Bluetooth devices (like an iPhone device). How can I scan for all devices using CoreLocation?
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
if CLLocationManager.isRangingAvailable() {
startScanning()
}
}
}
}
func startScanning() {
let uuid = UUID(uuidString: "XXXXX")!
let beaconRegion = CLBeaconRegion(proximityUUID: uuid, major: 0, minor: 0, identifier: "XXXXX")
locationManager.startMonitoring(for: beaconRegion)
locationManager.startRangingBeacons(in: beaconRegion)
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
extendBackgroundRunningTime()
if beacons.count > 0 {
print(beacons)
updateDistance(beacons[0].proximity)
} else {
updateDistance(.unknown)
}
}
You Cannot scan Bluetooth device with this method.You can only scan bluetooth device with Core Bluetooth Frame work.
Go through the below tutorial for bluetooth.
Press here for link
Related
I'm building an app which detect Beacon device proximity using locate beacon app in iPhone 6 and my app in iPhone 7 but app is unable to detect the Beacon transmitter. I have entered correct UUID and Major Minor number but it is not working. I'm running on iPhone 7 with iOS 13.5 and iPhone 6 with iOS 12 it is not detecting.
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var distancestatuslbl: UILabel!
var locationmanager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationmanager = CLLocationManager()
locationmanager.delegate = self
locationmanager.requestAlwaysAuthorization()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways
{
print("Allowed any time")
startScanning()
}
else if status == .authorizedWhenInUse
{
print("Allowed only during run time")
startScanning()
}
}
func startScanning() {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self)
{
let uuid = UUID(uuidString: "2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6")
let majornumber: CLBeaconMajorValue = 123
let minornumber: CLBeaconMinorValue = 456
let beaconregion = CLBeaconRegion(uuid: uuid!, major: majornumber, minor: minornumber, identifier: "com.mybeacon")
locationmanager.startMonitoring(for: beaconregion)
print("Started scanning")
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region is CLBeaconRegion
{
if CLLocationManager.isRangingAvailable()
{
locationmanager.startRangingBeacons(in: region as! CLBeaconRegion)
print("Starting ranging...")
}
}
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
let nearestbeacon = beacons.first!
switch nearestbeacon.proximity {
case .near:
distancestatuslbl.text = "Near"
break
case .immediate:
distancestatuslbl.text = "Immediate"
break
case .far:
distancestatuslbl.text = "Far"
break
default:
print("sdf")
}
}
}
You probably need to call startScanning() in viewDidLoad. As written, it is only called after permission is first granted meaning it only starts the first time you run the app and grant permission, then never again.
Also, check that the beacon actually is transmitting by running the Locate app on the same phone as your app. Does Locate detect?
Hello i trying to detect and ranging beacons following by apple's docs article
but in my case CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) always gave me false thus i couldn't start monitoring
Of course i set Privacy for location and Location updates on background mode
this is my codes
func initializeLocationManager(){
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func rangeBeacons(){
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
let region = CLBeaconRegion(proximityUUID: UUID(uuidString: beacons[0].uuid)!, identifier: beacons[0].identifier)
locationManager.startMonitoring(for: region)
}else {
print("CLLocation Monitoring is unavailable")
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways {
rangeBeacons()
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region is CLBeaconRegion {
// start monitoring
if CLLocationManager.isRangingAvailable() {
locationManager.startRangingBeacons(in: region as! CLBeaconRegion)
}
}
print("didEnter at \(region.identifier)")
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("didExit at \(region.identifier)")
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
if beacons.count > 0 {
let nearestBeacon = beacons.first!
switch nearestBeacon.proximity {
case .far:
print("far")
break
case .near:
print("near")
break
case .immediate:
print("It's behind yout")
break
case .unknown:
print("unknown")
}
}
}
but if i use locationManager.startRangingBeacons directly instead locationManager.startMonitoring(for: region), it works
but still problem didEnterRegion and didExitRegion are not called
what is the problem in my case
i want to follow exactly same with apple's docs article
It's unclear from the code shown what CLBeaconRegion.self means in context. Try instead using the defined region to see if monitoring is available.
func rangeBeacons(){
let region = CLBeaconRegion(proximityUUID: UUID(uuidString: beacons[0].uuid)!, identifier: beacons[0].identifier)
if CLLocationManager.isMonitoringAvailable(for: region) {
locationManager.startMonitoring(for: region)
}else {
print("CLLocation Monitoring is unavailable")
}
}
In practice, there is no real reason to call isMonitoringAvailable. Just start monitoring without this check. If for some reason it fails, you will get a callback to: locationManager:monitoringDidFailForRegion:withError
I believe the only reason why isMonitoringAvailable can be false for iBeacon (CLBeaconRegion) is when the device you're running the app on doesn't support Bluetooth 4.0.
This includes:
the simulator,
iPhone: 1st-gen, 3G and 3GS,
iPad: 1st-gen and 2nd-gen,
iPod Touch: 1st through 4th gen.
If you're running your app on any device newer than these, then the only remaining thing I can think of is, there's a problem with Bluetooth on your device. In which case, a reboot might help.
I'm currently working on developing an app that is heavily dependent on iBceaons.
I managed to create a beacon region which wakes up the app process in the background for 10 seconds when entering the region.
The next step is making phone it self advertise when it enters the region while in background
Currently while the app is open it keeps ranging and transmits as a beacon while its in a region
where as when the app is in the background , it ranges for 10 seconds but doesn't transmit as a beacon when it enters a region
so is there a way to allow the phone to transmit as a beacon when its in the background when it enters a region ?
I already had a look into Apple's background Bluetooth which mentioned that the advertising packet is differs when transmitting in the background. I have also looked at This Solution but this solution doesn't use core location so it can't wake the app when entering a region
import UIKit
import CoreLocation
import CoreBluetooth
class ViewController:
UIViewController,CLLocationManagerDelegate,CBPeripheralManagerDelegate {
var locationManager: CLLocationManager!
var localBeacon: CLBeaconRegion!
var beaconPeripheralData: NSDictionary!
var peripheralManager: CBPeripheralManager!
let myCustomServiceUUID = CBUUID(string:"5A4BCFCE-174E-4BAC-A814-092E77F6B7E5")
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
if CLLocationManager.isRangingAvailable() {
startScanning()
}
}
}
}
func startScanning() {
let uuid = UUID(uuidString: "48de4980-968d-11e4-b4a9-0800200c9a66")!
let beaconRegion = CLBeaconRegion(proximityUUID: uuid, major: 1, minor: 1, identifier: "region1")
beaconRegion.notifyEntryStateOnDisplay=true;
locationManager.startMonitoring(for: beaconRegion)
locationManager.startRangingBeacons(in: beaconRegion)
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
if(beacons.count > 0) {
let nearestBeacon:CLBeacon = beacons[0] as CLBeacon
NSLog("RSSI value is %ld", nearestBeacon.rssi);
initLocalBeacon() // Here I'm transmitting as a beacon along with ranging when entering or within a region which works fine the app is open but not transmitting while in background
}
}
func locationManager(_ manager: CLLocationManager,didDetermineState state: CLRegionState,for region: CLRegion) {
switch state {
case .inside:
NSLog("locationManager didDetermineState INSIDE %#", region.identifier);
case .outside:
NSLog("locationManager didDetermineState OUTSIDE %#", region.identifier);
case .unknown:
NSLog("locationManager didDetermineState OTHER %#", region.identifier);
}
}
func initLocalBeacon() {
if localBeacon != nil {
stopLocalBeacon()
}
let localBeaconUUID = "5A4BCFCE-174E-4BAC-A814-092E77F6B7E5"
let localBeaconMajor: CLBeaconMajorValue = 2
let localBeaconMinor: CLBeaconMinorValue = 1
let uuid = UUID(uuidString: localBeaconUUID)!
localBeacon = CLBeaconRegion(proximityUUID: uuid, major: localBeaconMajor, minor: localBeaconMinor, identifier: "identifer here")
beaconPeripheralData = localBeacon.peripheralData(withMeasuredPower: -59)
peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: nil)
}
func stopLocalBeacon() {
peripheralManager.stopAdvertising()
peripheralManager = nil
beaconPeripheralData = nil
localBeacon = nil
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
peripheralManager.startAdvertising(beaconPeripheralData as! [String: AnyObject]!)
} else if peripheral.state == .poweredOff {
//peripheralManager.stopAdvertising()
}
}
}
I have the act as a BLE Accessory selected in the background modes in capabilities and the Privacy - Bluetooth Peripheral Usage Description added in the playlist
Sorry, iOS will not let your app advertise a BLE packet matching the iBeacon spec when it is in the background. As you have mentioned in your question, Apple alters the way background advertisements emitted in the background look, and as a result, they will not trigger CoreLocation enter events to wake up receiving apps in the background.
There are a few imperfect alternatives:
You can use other beacon advertisements in the background and wake up your app. This won't be as quick as iBeacon, but it will wake up your app within a few minutes. Here is a setup that does that: https://github.com/Decemberlabs/AltBeacon
You can advertise iBeacon whenever the app is in the foreground, and try to get the user to bring the app to the foreground through a local notification.
If there are other foreground copies of your app in the vicinity (based on background beacon detection), you can use a web service to notify them of your presence during the 10 seconds your app runs in the background. This notification can tell them to start advertising on your behalf.
is it possible to use GPS with iBeacon when app is in background?
I need to start update gps location when iPhone detect iBeacon only through 180s, I do something like this but it doesn't work :/
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
if !isInForeground {
extendBackgroundTime()
}
print(wasBeaconDetected)
for beacon in beacons {
if beacon.rssi < -10 {
wasBeaconDetected = true
nearbyBeacons.append(beacon)
}
}
print(beacons)
currentLocation = manager.location!.coordinate
if firstRegionDetected == "" {
firstRegionDetected = region.identifier
} else if firstRegionDetected == region.identifier {
analyzeScan(nearbyBeacons, currentLocation)
}
}
of course I start monitoring when determine State
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
if isInBackground {
extendBackgroundTime()
}
}
I had did beacon searching code as per Kontakt SDK Sample code as below. But I am getting beacon count always 0, while I am having 11 beacons near by my iPhone. Can any body help me over this?
I have initialise KTKBeaconManager in viewDidLoad method and then create region object and stopped any previous ranging service and then started new monitoring and ranging services.
And all time it calls didRangeBeacons with beacons count = 0. Not sure what exactly the issue. Its same code from their example code.
import UIKit
import KontaktSDK
class ViewController: UIViewController {
var beaconManager: KTKBeaconManager!
#IBOutlet var statusLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Initiate Beacon Manager
beaconManager = KTKBeaconManager(delegate: self)
beaconManager.requestLocationAlwaysAuthorization()
// Region
let proximityUUID = NSUUID(uuidString: "f7826da6-4fa2-4e98-8024-bc5b71e0893e")
let region = KTKBeaconRegion(proximityUUID: proximityUUID! as UUID, identifier: "com.weenggs.KontaktDemo")
// Region Properties
region.notifyEntryStateOnDisplay = true
beaconManager.stopMonitoringForAllRegions()
// Start Ranging
beaconManager.startMonitoring(for: region)
beaconManager.startRangingBeacons(in: region)
beaconManager.requestState(for: region)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController: KTKBeaconManagerDelegate {
func beaconManager(_ manager: KTKBeaconManager, didDetermineState state: CLRegionState, for region: KTKBeaconRegion) {
print("Did determine state \"\(state.rawValue)\" for region: \(region)")
statusLabel.text = "Did determine state \"\(state.rawValue)\" for region: \(region)"
}
func beaconManager(_ manager: KTKBeaconManager, didChangeLocationAuthorizationStatus status: CLAuthorizationStatus) {
print("Did change location authorization status to: \(status.rawValue)")
statusLabel.text = "Did change location authorization status to: \(status.rawValue)"
if status == .authorizedAlways{
// Region
let proximityUUID = NSUUID(uuidString: "f7826da6-4fa2-4e98-8024-bc5b71e0893e")
let region = KTKBeaconRegion(proximityUUID: proximityUUID! as UUID, identifier: "com.weenggs.KontaktDemo")
// Region Properties
region.notifyEntryStateOnDisplay = true
beaconManager.startMonitoring(for: region)
beaconManager.startRangingBeacons(in: region)
beaconManager.requestState(for: region)
}
}
func beaconManager(_ manager: KTKBeaconManager, monitoringDidFailFor region: KTKBeaconRegion?, withError error: Error?) {
print("Monitoring did fail for region: \(region)")
print("Error: \(error)")
statusLabel.text = "Monitoring did fail for region: \(region)"
}
func beaconManager(_ manager: KTKBeaconManager, didStartMonitoringFor region: KTKBeaconRegion) {
print("Did start monitoring for region: \(region)")
statusLabel.text = "Did start monitoring for region: \(region)"
}
func beaconManager(_ manager: KTKBeaconManager, didEnter region: KTKBeaconRegion) {
print("Did enter region: \(region)")
statusLabel.text = "Did enter region: \(region)"
}
func beaconManager(_ manager: KTKBeaconManager, didExitRegion region: KTKBeaconRegion) {
print("Did exit region \(region)")
statusLabel.text = "Did exit region \(region)"
}
func beaconManager(_ manager: KTKBeaconManager, didRangeBeacons beacons: [CLBeacon], in region: KTKBeaconRegion) {
print("Did ranged \"\(beacons.count)\" beacons inside region: \(region)")
statusLabel.text = "Did ranged \"\(beacons.count)\" beacons inside region: \(region)"
if let closestBeacon = beacons.sorted(by: { $0.0.accuracy < $0.1.accuracy }).first , closestBeacon.accuracy > 0 {
print("Closest Beacon is M: \(closestBeacon.major), m: \(closestBeacon.minor) ~ \(closestBeacon.accuracy) meters away.")
statusLabel.text = "\(statusLabel.text) Closest Beacon is M: \(closestBeacon.major), m: \(closestBeacon.minor) ~ \(closestBeacon.accuracy) meters away."
}
}
}
I reckon the common issue is that you forgot to set
Kontakt.setAPIKey("yourSuperSecretAPIKey")
and either one of those two permissions
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
If it's not the case then your beacons' batteries could be drained out.
Finally I was able to detect beacons using CBPeripheral class and identify uniquely based on received UUID with instance id( last 12 characters are instance id which are unique)