didEnterRegion, didExitRegion not being called - ios

I've been experimenting with region monitoring in order to show an alert or a local notification when the user is within the set region. As a first step, I added a print line to see if it works on the debug area. However, while the other lines are being printed, I'm not getting anything for didEnterRegion and didExitRegion.
I am simulating the location to be in/outside of the given region but I am having no luck. It will be great if someone could look at the code below and see what I've missed. Thank you.
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var manager = CLLocationManager?()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
manager = CLLocationManager()
let latitude: CLLocationDegrees = 48.858400
let longitude: CLLocationDegrees = 2.294500
let center: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let radius: CLLocationDistance = CLLocationDistance(100.0)
let identifier: String = "Notre Dame"
let currRegion = CLCircularRegion(center: center, radius: radius, identifier: identifier)
manager?.distanceFilter = 10
manager?.desiredAccuracy = kCLLocationAccuracyBest
currRegion.notifyOnEntry = true
currRegion.notifyOnExit = true
manager?.requestWhenInUseAuthorization()
manager?.delegate = self
manager?.pausesLocationUpdatesAutomatically = true
manager?.startMonitoringForRegion(currRegion)
manager?.startUpdatingLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager, didStartMonitoringForRegion region: CLRegion) {
print("The monitored regions are: \(manager.monitoredRegions)")
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
print("locations = \(locValue.latitude) \(locValue.longitude)")
}
func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {
NSLog("Entered")
}
func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {
NSLog("Exited")
}
}

You can make it work by changing
manager?.requestWhenInUseAuthorization()
to
manager?.requestAlwaysAuthorization()
then add to your info.plist file this key
NSLocationAlwaysUsageDescription with value "This is for testing purpose" or whatever text you want this is what will appear to user requesting to use location

Related

didUpdateLocations called every time when viewWillAppear for Significant Location Change

I am using CLLocationManager and MKMapView in same UIViewController.
I want to call an API only when the significant location change.
import UIKit
import CoreLocation
import MapKit
class ViewController: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.locationManager.requestAlwaysAuthorization()
self.locationManager.delegate = self
self.locationManager.startMonitoringSignificantLocationChanges()
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
self.locationManager.distanceFilter = 500
mapView.showsUserLocation = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locations \(locations)")
}
}
In this, the main issue is whenever I make the app background and foreground didUpdateLocations get called. I want it to be called only when significant location change, not every time when viewWillAppear called.
I found its because of MKMapView, didUpdateLocations is being called.
You can manually check the distance with last saved location. Try this.
var lastLocation: CLLocation?
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let lastLocation = lastLocation, let newLocation = locations.last {
if (lastLocation.distance(from: newLocation) < manager.distanceFilter) {
return
}
}
print("locations \(locations)")
lastLocation = locations.last
}
You can save the last locations and check inside didUpdateLocations method, if not same the take appropriate action.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location : CLLocation = locations.last!
if location.coordinate.latitude != lastLat && location.coordinate.longitude != lastLon{
// take action
}
}

Core Location didEnterRegion method can not work with more than one regions

I'm working on a project about location based reminder. I have used CoreLocation's didEnterRegion method. so when I set a location for entering region, I can take a notification but whenever I want to set another location for entry with didEnterRegion method it only see first one. The method cannot be called for second location. Could you help me?
Here is my code:
import UIKit
import CoreLocation
import MapKit
class ViewController: UIViewController,CLLocationManagerDelegate {
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let latitude1: CLLocationDegrees = 78.98
let longitude1: CLLocationDegrees = 90.09
let center1: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude1, longitude1)
let radius1: CLLocationDistance = CLLocationDistance(100.0)
let identifier1: String = "Notre Dame"
let currRegion1 = CLCircularRegion(center: center1, radius: radius1, identifier: identifier1)
let latitude: CLLocationDegrees = 20.2020
let longitude: CLLocationDegrees = 2.2945
let center: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let radius: CLLocationDistance = CLLocationDistance(100.0)
let identifier: String = "Notre Dame"
let currRegion = CLCircularRegion(center: center, radius: radius, identifier: identifier)
locationManager.distanceFilter = 10
locationManager.desiredAccuracy = kCLLocationAccuracyBest
currRegion1.notifyOnEntry = true
currRegion.notifyOnEntry = true
locationManager.delegate=self
locationManager.requestAlwaysAuthorization()
locationManager.startMonitoring(for: currRegion1)
locationManager.startMonitoring(for: currRegion)
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region is CLCircularRegion {
handleEvent(forRegion: region)
}
}
func handleEvent(forRegion region: CLRegion!) {
print("Geofence triggered!")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The official document:
You must call this method once for each region you want to monitor. If
an existing region with the same identifier is already being monitored
by the app, the old region is replaced by the new one.
So make the different identifier:
//...
let identifier1: String = "Notre Dame1"
//...
let identifier: String = "Notre Dame2"
//...

CLLocationManager delegate methods are not getting called(google maps is integrated)

The delegate Methods of CLLocationManager
didChangeAuthorizationStatus
and
didUpdateToLocation
are not getting called.
Location Always Usage Description key is already added in info.plist and I am getting notification also when i launch app for the first time.
I am able to see the google map, but i am not able to see current location, When i change location, its not getting updated. Basicaaly delegate methods are not getting called.
//code
import UIKit
import GoogleMaps
class ViewController: UIViewController,GMSMapViewDelegate {
#IBOutlet weak var mapViewTest: GMSMapView!
let locationManager = CLLocationManager()
var currentLocation :CLLocation = CLLocation(latitude: 0.0, longitude: 0.0)
var currentLatitude : Double = 0.0
var currentLongitude : Double = 0.0
override func viewDidLoad()
{
super.viewDidLoad()``
locationManager.delegate = self
if (CLLocationManager.locationServicesEnabled())
{
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
// Do any additional setup after loading the view, typically from a nib.
}
}
extension ViewController : CLLocationManagerDelegate
{
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus)
{
if status == .authorizedAlways
{
if(CLLocationManager .locationServicesEnabled())
{
locationManager.startUpdatingLocation()
mapViewTest.isMyLocationEnabled = true
mapViewTest.settings.myLocationButton = true
}
}
}
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation)
{
mapViewTest.camera = GMSCameraPosition(target: (newLocation.coordinate), zoom: 15, bearing: 0, viewingAngle: 0)
currentLocation = newLocation
currentLatitude = newLocation.coordinate.latitude
currentLongitude = newLocation.coordinate.longitude
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print("Errors: " + error.localizedDescription)
}
}
From your code you are working with Swift 3, and in Swift 3 CLLocationManagerDelegate method's signature is changed like this.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
}
//func locationManager(_ manager: CLLocationManager, didUpdateTo newLocation: CLLocation,
from oldLocation: CLLocation) is deprecated with below one
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
}
Check Apple Documentation on CLLocationManagerDelegate for more details.
After checking your code i found some changes you needs to do as follow,
note : I have only added the code having issue here that of location manager
import UIKit
import CoreLocation
class ViewController: UIViewController {
let locationManager = CLLocationManager()
var currentLocation :CLLocation = CLLocation(latitude: 0.0, longitude: 0.0)
var currentLatitude : Double = 0.0
var currentLongitude : Double = 0.0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.delegate = self
if (CLLocationManager.locationServicesEnabled())
{
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
func locationManager(_ manager: CLLocationManager, didFinishDeferredUpdatesWithError error: Error?) {
print("Errors: " + (error?.localizedDescription)!)
}
}
Also add below lines in .plist file if not added,
<key>NSLocationWhenInUseUsageDescription</key>
<string>$(PRODUCT_NAME) location use</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>$(PRODUCT_NAME) always uses location </string>
Add these two properties in your info.plist
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
you need to put the mapview delegate to self.
try this:
override func viewDidLoad() {
super.viewDidLoad()
// User Location Settings
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
// Google Maps Delegate
mapView.delegate = self
}
// View will appear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Google maps settings
mapView.isMyLocationEnabled = true
mapView.settings.myLocationButton = true
// Get location if autorized
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse) {
let (latitude, longitude) = self.getLocation()
mapView.camera = GMSCameraPosition.camera(
withLatitude: latitude,
longitude: longitude,
zoom: 14)
}
}
//Get the user location
func getLocation() -> (latitude: CLLocationDegrees, longitude: CLLocationDegrees) {
let latitude = (locationManager.location?.coordinate.latitude)!
let longitude = (locationManager.location?.coordinate.longitude)!
return (latitude, longitude)
}

How to save coordinates to Firebase Swift 2

I want to save a set of latitude and longitude coordinates to Firebase, but whenever my app runs through this code it crashes!
let userID: String = (FIRAuth.auth()?.currentUser?.uid)!
let lat: Double = (locationManager.location?.coordinate.latitude)!
let lon: Double = (locationManager.location?.coordinate.longitude)!
self.ref.child("Location").child(userID).setValue(["Latitude": lat, "Longitude": lon])
Is there anyway I can fix this and save it properly and efficiently?
Make sure of two things :-
1.) your viewController inherits from CLLocationManagerDelegate and has its delegate set to self in viewDidLoad
2.) your info.plist has these keys added to them :-
NSLocationAlwaysUsageDescription --- I need Location
NSLocationWhenInUseUsageDescription --- I need Location
privacy - location usage description --- I need Location
class MapViewController: UIViewController , CLLocationManagerDelegate...{
...
..
let locationManager = CLLocationManager()
func viewDidLoad(){
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.requestWhenInUseAuthorization()
locationManager.startMonitoringSignificantLocationChanges()
locationManager.startUpdatingLocation()
}
//Call these functions for updating the getting the values of current location
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedWhenInUse {
print("authorised call came . . . . ")
mapView.myLocationEnabled = true
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
print("target position : = \(location.coordinate)")
print(locationManager.location!.coordinate.latitude)
mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
locationManager.stopUpdatingLocation()
self.FIRDatabase.database().reference().child("Location").child(FIRAuth.auth()!.currentUser!.uid).setValue(["Latitude": locationManager.location!.coordinate.latitude, "Longitude": locationManager.location!.coordinate.longitude])
}
}
}

Swift 2 CLLocationManager Error updating

i updated Xcode 6 to Xcode 7 beta with Swift 2. I get this error and i can't find out how to fix it, please help me. Thanks. This is my code :
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]) {
let location = locations.last as! CLLocation
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.map.setRegion(region, animated: true)
}
and i get this error :
Objective-C method 'locationManager:didUpdateLocations:' provided by method 'locationManager(_:didUpdateLocations:)' conflicts with optional requirement method 'locationManager(_:didUpdateLocations:)' in protocol 'CLLocationManagerDelegate'
Just had the same issue as you, change
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject])
to
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
Click on your project - go to Build Phases->Link Binary With Libraries and add CoreLocation.framework
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var LatitudeGPS = NSString()
var LongitudeGPS = NSString()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
updateLocation()
func updateLocation() {
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
//self.locationManager.distanceFilter = 10
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]) {
locationManager.stopUpdatingLocation() // Stop Location Manager - keep here to run just once
LatitudeGPS = String(format: "%.6f", manager.location!.coordinate.latitude)
LongitudeGPS = String(format: "%.6f", manager.location!.coordinate.longitude)
print("Latitude - \(LatitudeGPS)")
}
This is my code which works on xcode 7, also I did have to clean my code (Product->Clean)
You need to mark your class or method with #objc attribute. So either:
#objc class MyManagerDelegate: NSObject, CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]) {
...
}
}
Or:
class MyManagerDelegate: CLLocationManagerDelegate {
#objc func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]) {
...
}
}
I solved this by following code:
//CLLocationManagerDelegate
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]) {
let location:CLLocation = locations[locations.count-1] as! CLLocation
if (location.horizontalAccuracy > 0) {
self.locationManager.stopUpdatingLocation()
print(location.coordinate, terminator: "")
updateWeatherInfo(location.coordinate.latitude, longitude: location.coordinate.longitude)
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last as! CLLocation!
manager.stopUpdatingLocation()
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude), span: MKCoordinateSpan(latitudeDelta: 0.001, longitudeDelta: 0.001))
mapView.setRegion(region, animated: true)
}

Resources