Find out if statUpdatingLocation is active in Swift - swift

I have a location based app running in swift. I am trying to detect if the self.locationManager.startUpdatingLocation() is currently active.
I am struggling to find out how to do this nor can I find much on the internet about it. This I am fairly sure is rather simple to achieve. I don't want to set a BOOL as this needs to be global.
if CLLocationManager.locationServicesEnabled() && /* START UPDATE LOCATION GOES HERE */ {
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
//self.locationManager.startMonitoringSignificantLocationChanges()
sender.setTitle("END DAY", forState: UIControlState.Normal)
} else {
}

I know this is a late answer now. But this is possibly one solution if you want to know if the locationManager is updating.
There should only be one instance of CLLocationManager in your app. So creating a Singleton is ideal. Then, you should override the methods startUpdatingLocation and stopUpdatingLocation.
(Swift 3)
import CoreLocation
class LocationManager: CLLocationManager {
var isUpdatingLocation = false
static let shared = LocationManager()
override func startUpdatingLocation() {
super.startUpdatingLocation()
isUpdatingLocation = true
}
override func stopUpdatingLocation() {
super.stopUpdatingLocation()
isUpdatingLocation = false
}
}
Usage:
if LocationManager.shared.isUpdatingLocation {
print("Is currently updating location.")
} else {
print("Location updates have stopped.")
}

You cannot not know whether startUpdatingLocation() is "active" because you are the one who said it.
If you need to keep track of this from elsewhere, make a Bool property and set it to true when you call startUpdatingLocation() and to false when you call stopUpdatingLocation().

Related

How to check location authorization status at the click of a button in iOS 14?

How can I use Core Location's locationManagerDidChangeAuthorization(_:) method to check authorization status and report user location at the press of a button (called in #IBAction) below:
My issue here is that when I run the code in the simulator, CoreLocation doesn't pop up with an alert to ask the user for permission when the button is pressed.
class CurrentLocationViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
// Button to check authorization status and start sending location update to the delegate
#IBAction func getLocation() {
locationManagerDidChangeAuthorization(locationManager)
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
// Delegate method to check authorization status and request "When In Use" authorization
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
let authStatus = manager.authorizationStatus
if authStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
return
}
}
EDIT: Using the deprecated authorizationStatus() class method in the #IBAction method instead of the locationManagerDidChangeAuthorization(_:) method allows me to get the pop up when the button is pressed in the simulator. I'm still trying to figure out why this modification works whereas my code above doesn't.
#IBAction func getLocation() {
let authStatus = CLLocationManager.authorizationStatus()
if authStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
return
}
...
You're code works - but have you remembered to add the privacy usage descriptions to the info.plist file?
Add these two entries in the file with your own explanation in the value field, then it should popup in the simulator:
Privacy - Location Always and When In Use Usage Description
Privacy - Location When In Use Usage Description

Launch Location Updates at specific time in background - Swift (watchOS)

I've developing an indipendent WatchOS app whose aim is identifying when an user leaves a specific area, sending consequentially a notification. In order to do that, the application heavily relies on background location updates.
So far, app is working fine. It fetches position based on distanceFilter property of CLLocationManager. The problem is battery. The approach I followed keep background location updates in execution, even though they're fetched only when a specific distance is "covered".
My idea then was to disable location update when the area is left by the user, and also disable this service during night hours. However, I'm facing serious problem with this type of approach.
My main problem is that disabling location update while in background does not allow me to resume it. I tried doing this with:
A Timer.
scheduleBackgroundRefresh(withPreferredDate:userInfo:scheduledCompletion:) method, calling startLocationUpdates() in the delegate
Nothing seems to work. My question is:
There is a way for resume background location updates if it was previously disabled?
Thank you in advance.
UPDATE n.2: I've tried to execute location updates with WKApplicationRefreshBackgroundTask but it just ignore requestLocation() function (suggested by #RomuloBM)
//In extension delegate handle() function
case let backgroundTask as WKApplicationRefreshBackgroundTask:
// Be sure to complete the background ta
LocMng = LocationManager() // I even tried to create a new element!
LocMng.LocMng.requestLocation()// it is just ignored
backgroundTask.setTaskCompletedWithSnapshot(false)
I call a background task with this function in my LocationManager:
//In didUpdateLocation
if background {
WKExtension.shared().scheduleBackgroundRefresh(withPreferredDate: Date(timeIntervalSinceNow: 30), userInfo: nil){ _ in
print("Done")
self.background = false
self.LocMng.stopUpdatingLocation()
}
}
For reference, here is my LocationManager class:
enum ScanningMode {
case Precise
case Normal
}
class LocationManager : NSObject, CLLocationManagerDelegate, UNUserNotificationCenterDelegate, ObservableObject {
let LocMng = CLLocationManager()
let NotMng = UNUserNotificationCenter.current()
var modeOfScanning: ScanningMode!
var region: CLCircularRegion!
var previousLocation: CLLocation!
// variables for position...
override init() {
super.init()
// stuff for my app...
modeOfScanning = .Precise
setupManager()
setupNotification()
startLocalization()
}
private func startLocalization(){
switch modeOfScanning!{
case ScanningMode.Precise:
LocMng.desiredAccuracy = kCLLocationAccuracyBest
LocMng.distanceFilter = 15
case ScanningMode.Normal:
LocMng.desiredAccuracy = kCLLocationAccuracyHundredMeters
LocMng.distanceFilter = 80
}
LocMng.startUpdatingLocation()
}
private func setupManager(){
LocMng.requestAlwaysAuthorization()
LocMng.delegate = self
LocMng.desiredAccuracy = kCLLocationAccuracyBest
}
private func setupNotification(){
NotMng.delegate = self
NotMng.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
print("NotificationCenter Authorization Granted!")
}
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == CLAuthorizationStatus.authorizedAlways{
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
LocMng.allowsBackgroundLocationUpdates = true
// For the sake of clarity, I will cut out this chunk of code and
// just showing how I execute my action based on the result of location
// This is just an example
actualLocation = locations[length-1]
//find if in a forget
if previousLocation != nil{
if !region.contains(actualLocation!.coordinate) && region.contains(previousLocation!.coordinate){
//Schedule notification
LocMng.stopUpdatingLocation() // <- this does not allow me to resume
}
}
previousLocation = actualLocation
}
}

How to transfer a boolean from app delegate to a viewcontroller?

I'm currently trying to transfer a variable from app delegate to a ViewController. Most of the guides I find are in objective-c and I don't have the skill to convert that code into swift. Could someone help me find a way to do this.
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
var isIpad: Bool!
if UIDevice.current.userInterfaceIdiom == .pad {
isIpad = true
print("iPad")
}else{
print("not iPad")
isIpad = false
}
}
Although I would suggest to take a look to #rmaddy's first comment, you could declare a stored property anywhere in the module (it doesn't has to be declared in the app delegate):
let isIpad = UIDevice.current.userInterfaceIdiom == .pad
It means that there is no need to pass a value from the app delegate to the view controller. Thus in the view controller -for example-:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if isIpad {
// ...
}
}
}

OS X save location permission

I'm getting the users GPS Location like this:
var manager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.startUpdatingLocation()
//manager.requestAlwaysAuthorization()
//manager.requestWhenInUseAuthorization()
}
func locationManager(manager:CLLocationManager, didUpdateLocations locations: [AnyObject]) { // Updated to current array syntax [AnyObject] rather than AnyObject[]
println("locations = \(locations)")
}
The commented-out functions seem not to exist for os x applications. It still works for me so that's fine.
But every time I run the code it asks for permission to use location.
Is it possible to store the permission somewhere, so it only asks on the first execution?
Quoting Apple's documentation:
Call the authorizationStatus class method to get the current authorization status for your app.
If the authorization status is kCLAuthorizationStatusRestricted or kCLAuthorizationStatusDenied, your app is not permitted to use location services and you should abort your attempt to use them.
Your code on OS X should look like this:
override func viewDidLoad() {
super.viewDidLoad()
let status = CLLocationManager.authorizationStatus()
if status == .Restricted || status == .Denied {
// User permission not given
return
}
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.startUpdatingLocation()
}
Permission is managed centrally by Mac OS X. The first time you call startUpdatingLocation, it will ask for permission then remembers what the user has decided.

CLLocationManager and tvOS - RequestWhenInUseAuthorization() not prompting

I seem to be having a little trouble getting tvOS to prompt the user for location data authorization. I literally copied and pasted working code from iOS and it seems to not be prompting the user. I am using the code listed below as well as the NSLocationWhenInUseUsageDescription key with a string value. The only difference in the api that I see is on iOS it uses startupdatinglocation() and on tvOS it uses requestLocation() (similar to watchOS) I've stepped through the problem and it is infact hitting requestWhenInUseAuthorization() but simply doesn't prompt the user.
Any idea what is going on?
import UIKit
import CoreLocation
class ViewController: UIViewController {
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
if CLLocationManager.locationServicesEnabled(){
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.NotDetermined{
locationManager.requestWhenInUseAuthorization()
}
else if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse{
locationManager.requestLocation()
}
}
}
It turns out that a CFBundleDisplayName key and $(PRODUCT_NAME)value is needed in order for the prompt to display.