I tried get the coordinates when user launched app.
I setted up the locationManager code in a independent file:
UserLocation.swift:
import Foundation
import CoreLocation
class UserLocation: NSObject, CLLocationManagerDelegate {
var userCurrentLocation: CLLocationCoordinate2D?
let locationManager = CLLocationManager()
func locationSetup() {
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.authorizationStatus() != CLAuthorizationStatus.authorizedWhenInUse {
print("authorization error")
return
}
locationManager.distanceFilter = 300
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.startUpdatingLocation()
print("startUpdatingLocation")
if CLLocationManager.locationServicesEnabled() {
print("locationServicesEnabled")
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locationManager getting start")
if let location = locations.last {
self.userCurrentLocation = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
print("print location in locationManager: \(String(describing: userCurrentLocation?.latitude))")
locationManager.stopUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didFinishDeferredUpdatesWithError error: Error?) {
print(error?.localizedDescription as Any)
return
}
}
then, I call the func in the AppDelegate.swift's application(_::didFinishLaunchingWithOptions:) like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let getUserLocation = UserLocation()
getUserLocation.locationSetup()
}
but , the only calls locationSetup() function successfully , never called the related function locationManager(_::didUpdateLocations:). the print("locationManager getting start") I putted the first line in the locationManager(_::didUpdateLocations:), never printed out
BTW, in the info.plist , I already set Privacy - Location When In Use Usage Description .
can anyone help me out ?
Your getUserLocation is a local variable. It goes out of existence 1 millisecond after you create it. So it never has time to do anything (e.g. location updating). Promote it to an instance variable so that it lives longer:
var getUserLocation : UserLocation?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.getUserLocation = UserLocation()
self.getUserLocation?.locationSetup()
return true
}
(Also please use better variable names. An object reference should not begin with a verb.)
Please cross-check simulator location: Simulator -> Debug -> Locations that shouldn't be None in your case...
Hope this will help you... Thanks :)
Related
I want my iOS app to update it's location when closed and make post requests but location manager didUpdateLocations doesn't get called from the background despite it working fine in normal app use. Below is my SendLocation class. Calling determineCurrentLocation() get it going.
My problem is that if I call determineCurrentLocation() from another class while the app is running - it works perfectly. But when I call it from the App Delegate didUpdateLocations never gets called.
class SendLocation: NSObject, CLLocationManagerDelegate{
var locationManager:CLLocationManager = CLLocationManager()
struct LocationStruct{
var latitude:CLLocationDegrees?, longitude:CLLocationDegrees?
}
var locationStruct = LocationStruct()
var userLocation: CLLocation? = nil
func sendLocationPost(){
// This function makes the POST
}
func determineCurrentLocation(){
locationManager.delegate = self
locationManager.allowsBackgroundLocationUpdates=true
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled(){
DispatchQueue.main.async {
print("test1") // This prints fine from background
self.locationManager.startUpdatingLocation()
}
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
print("test2") // This never gets printed from backgrounf
locationManager.stopUpdatingLocation()
userLocation = locations[0] as CLLocation
locationStruct.latitude=userLocation?.coordinate.latitude
locationStruct.longitude=userLocation?.coordinate.longitude
sendLocationPost()
}
Below are the two functions I edited in my App Delegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
let sendLocation = SendLocation()
sendLocation.determineCurrentLocation()
}
My Info.plist has been changed to be correct, as far as I know.
Here is a picture of my Background Modes
And my privacy settings
Just in case I'm missing something there.
If anyone has any ideas what I've done wrong then I'd be very appreciative of some help.
I am trying to get the users location immediately on start up, and to do this I have implemented a global variable userLocation that will get updated in the AppDelegate's didFinishLaunchingWithOptions function. I have implemented the location manager like so:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
var locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled(){
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestLocation()
}
return true
}
and the extension:
extension AppDelegate: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
usersLocation = locations.last!
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
}
The userLocation never gets updated, and I placed a break point on the userLocation = locations.last! line and it never reaches that.
Thanks for any advice
I think you should keep the locationManager variable too.
var locationManager: CLLocationManager!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled(){
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestLocation()
}
return true
}
I have an app that uses the user's location throughout its various view conrollers, and I've learned that in order to get that location you need to create a CLLocationManger instance and conform to the CLLocationManagerDelegate protocol.
Is it possible to make one CLLocationManager instance and use it's properties like coordinates in my different view controllers or should I make a CLLocationManager in each view controller class?
A quick and somewhat robust hack could be:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startUpdatingLocation()
return true
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
lastLocation = locations.last!
}
In this same source file, at global scope, add:
private var lastLocation: CLLocation? {
didSet {
locationCallback?(lastLocation!)
locationCallback = nil
}
}
private var locationCallback: ((CLLocation) -> Void)?
func getLastLocation(callback: (CLLocationManager) -> Void) {
guard let location = lastLocation else {
locationCallback = callback
return
}
locationCallback(location)
}
Finally, elsewhere in your app, you can get your last known location using just:
getLastLocation { location in
print(location)
}
I have the following:
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
...
let locationManager = CLLocationManager()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.allowsBackgroundLocationUpdates = true
locationManager.distanceFilter = 3000.0
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("my location: \(locations.first?.coordinate)")
locationManager.stopUpdatingLocation()
locationManager.delegate = nil
}
}
But even when the app is turned off i see the location service icon in status bar:
I wonder if there is a way to disable it programmatically. Thanks in advance!
In your plist file, you must make sure the location row is Privacy - LocationWhenInUseUsageDescription not Privacy - LocationAlwaysUsageDescription
I just followed http://www.raywenderlich.com/92428/background-modes-ios-swift-tutorial location update part.
But manager doesn't print location info in background mode.
Then manager print logs to Xcode's console when app enter foreground.
Is this code right?
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
var manager = CLLocationManager()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.delegate = self
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
return true
}
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
if UIApplication.sharedApplication().applicationState != .Active {
NSLog("App is backgrounded. New location is %#", newLocation)
}
}
.....
}
I got answer for myself.
If your app running on iOS 9.0 or above and want to run your location service app on background,
you have to allowsBackgroundLocationUpdates variable set to true.
so here is my code.
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
var manager = CLLocationManager()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.delegate = self
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
if #available(iOS 9.0, *){
manager.allowsBackgroundLocationUpdates = true
}
return true
}
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
if UIApplication.sharedApplication().applicationState != .Active {
NSLog("App is backgrounded. New location is %#", newLocation)
}
}
.....
}