It seems that my app is not launched and called with location updates when it is in a terminated state.
Since it is a little bit hard for me to test what is not working (using a real device is not really easy when you have to move back and forth inside an office trying to trigger a significant location change), is there a way to simulate location changes in the simulator while the app is closed?
I have already tried using the Simulator > Debug > Location > [City Bicyce Ride, ...] but it seems that it works only when the app is running. I even tried creating a scheme where the app is not launch automatically after compiling.
Do you have any suggestion on how to debug this kind of issues?
(By now I am just logging on separate files at every application launch, even though unfortunately the app gets not launched in background when is in a closed state )
This is the code in my app delegate:
lazy var locationManagerFitness: CLLocationManager! = {
let manager = CLLocationManager()
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.distanceFilter = 1.0
manager.activityType = CLActivityType.Fitness
manager.delegate = self
manager.requestAlwaysAuthorization()
return manager
}()
func startLocationMonitoring()
{
locationManagerFitness.stopMonitoringSignificantLocationChanges()
locationManagerFitness.startUpdatingLocation()
}
func startLocationMonitoringSignificantChanges()
{
locationManagerFitness.stopUpdatingLocation()
locationManagerFitness.startMonitoringSignificantLocationChanges()
}
// MARK: - CLLocationManagerDelegate
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
if manager == locationManagerFitness
{
log.debug("locationManagerFitness:")
}
for newLocation in locations
{
saveLocation(newLocation)
if UIApplication.sharedApplication().applicationState == .Active {
log.debug("App is active. New location is \( newLocation )")
} else {
log.debug("App is in background. New location is \( newLocation )")
}
}
}
func saveLocation(location: CLLocation) -> Location {
let entity = NSEntityDescription.entityForName("Location",
inManagedObjectContext:managedObjectContext)
let locationCD = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext: managedObjectContext) as! Location
locationCD.setValue(location.coordinate.latitude, forKey: "latitude")
locationCD.setValue(location.coordinate.longitude, forKey: "longitude")
locationCD.setValue(NSDate(), forKey: "creationDate")
do {
try managedObjectContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
return locationCD
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?)
-> Bool {
//Logs
let documentDirectoryURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
let dayTimePeriodFormatter = NSDateFormatter()
dayTimePeriodFormatter.dateFormat = "hh:mm_dd-MM-yyyy"
let dateString = dayTimePeriodFormatter.stringFromDate(NSDate())
let logURL = documentDirectoryURL.URLByAppendingPathComponent("log_\( dateString ).txt")
log.setup(.Debug, showThreadName: true, showLogLevel: true, showFileNames: true, showLineNumbers: true, writeToFile: logURL, fileLogLevel: .Debug)
log.debug("Starting app...")
// StatusBar
UIApplication.sharedApplication().statusBarStyle = .LightContent
switch CLLocationManager.authorizationStatus()
{
case .AuthorizedAlways:
if let _ = launchOptions?[UIApplicationLaunchOptionsLocationKey]
{
startLocationMonitoringSignificantChanges()
}
default:
break;
}
log.debug("App started!")
return true
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
log.debug("startLocationMonitoringSignificantChanges")
startLocationMonitoringSignificantChanges()
}
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.
log.debug("startLocationMonitoring")
startLocationMonitoring()
}
The behavior of the above code is that the app is monitoring user location changes only when it is active.
Looking the image below is clear that the simulator seems to continue to move the location of the Bicycle Ride, however the AppDelegate CLLocationManagerDelegate's locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) is not called while the app is terminated or in background:
Did you tried the custom Location instead of City Bycle Ride? One of my app I used Region Monitoring and if I give manually the locations then it is work even if i lock the simulator.
Related
I have created an iOS native module for my React Native application, which invokes the location manager service on iOS.
The purpose of the app is to automatically detect when a user is driving in a vehicle, start recording their trip when they are driving for further processing.
In order to achieve this with background capabilities, I have implemented the location manager and the motion activity manager together. From the location manager, I am using both the startMonitoringSignificantLocation and startUpdatingLocations functions to retrieve the users location.
The significant locations function is used to launch the app in case the user force kills it, and the startUpdatingLocations function is then called to decrease the distance filter between location updates (The significant location updates alone are too inconsistent - There have been times where I would drive a few kilometres without receiving a location update if I was just using the significant location monitoring function).
It is working quite well now, however I've noticed that my app's battery usage is constantly high when the app is started (whether manually or by receiving a location update in the background) - even through the night when there are no locations being sent to the app by iOS.
Here's a screenshot of the app's battery usage.
The light blue bars are when the app had been started in the background with an update from the significant location monitor, and thereafter the startUpdatingLocations function was started.
My understanding is that if there are no location updates, my app is not given any background processing time and so I would expect that there would be no battery usage in those periods, and after I receive a location update then my app will contribute to battery usage for however long iOS allows it to process that location update.
Is this correct? Or am I mistaken in my understanding?
When a location update comes through, the app automatically start listening for motion activity updates and this is stopped after a certain time interval. It's currently set to 5 minutes (which might be long and I will be decreasing it) - however it is still questionable that when the device is idle overnight, no location updates come through and so no motion activity updates will be coming through to the app either, but the battery usage is still maxed out.
I have looked into using the pausesLocationUpdatesAutomatically and activityType flags, however these also are not reliable and I lose a lot of driving data by the time that my app actually receives a location update and starts tracking the trip.
I'm not sure if this would be affecting battery usage, but an important thing to note is that as soon as a location/motion activity update is received in the native module (in the code below), it is sent using a EventEmitter and received by the React Native application for storage into cache and processing. Processing includes using the last +-20 location and motion activity updates in cache (anything older is discarded) and processing these data items in a basic algorithm to help me detect whether a user is in a vehicle or not.
here is the code that I am running in the native module:
import Foundation
import CoreMotion
import CoreLocation
#objc(ActivityRecognitionWrapper)
class ActivityRecognitionWrapper: RCTEventEmitter, CLLocationManagerDelegate{
let motionManager = CMMotionActivityManager()
var locationManager:CLLocationManager = CLLocationManager()
var distanceFilter:Double = 50
var updateDuration: Int = 300000
var activityServiceRunning: Bool = false
public static var shared:ActivityRecognitionWrapper?
override init() {
super.init()
ActivityRecognitionWrapper.shared = self
}
#objc(enableActivityRecognitionTracking:withUpdateDuration:withResolver:withRejecter:) func enableActivityRecognitionTracking(_ distanceFilter: Double,updateDuration: Int, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
locationManager.delegate = self
self.distanceFilter = distanceFilter
self.updateDuration = updateDuration
locationManager.allowsBackgroundLocationUpdates=true
locationManager.distanceFilter = distanceFilter
locationManager.activityType = .automotiveNavigation
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.requestAlwaysAuthorization()
resolve(true)
}
#objc(getLastKnownLocation:reject:)
func getLastKnownLocation(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void{
debugPrint("Requested one location.")
locationManager.requestLocation()
resolve(true)
}
#objc(startSignificantLocationUpdates:reject:)
func startSignificantLocationUpdates(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void{
debugPrint("Starting significant location tracking")
locationManager.allowsBackgroundLocationUpdates=true
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.startMonitoringSignificantLocationChanges()
resolve(true)
}
#objc(startFrequentLocationUpdates:reject:)
func startFrequentLocationUpdates(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void{
debugPrint("Starting frequent location tracking")
debugPrint("Distance Filter: \(distanceFilter)")
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.distanceFilter = distanceFilter
locationManager.allowsBackgroundLocationUpdates=true
locationManager.startUpdatingLocation()
resolve(true)
}
#objc(stop:reject:)
func stop(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void{
debugPrint("Stopping all location tracking")
locationManager.stopUpdatingLocation()
locationManager.stopMonitoringSignificantLocationChanges()
resolve(true)
}
func getConfidence(conf:CMMotionActivityConfidence?) -> String{
if conf == CMMotionActivityConfidence.low {
return "Low"
} else if conf == CMMotionActivityConfidence.medium {
return "Good"
} else if conf == CMMotionActivityConfidence.high {
return "High"
} else {
return "UNKNOWN"
}
}
func getTransformedActivityObject(activity: CMMotionActivity, type:String) -> [String:String] {
let dateFormatter = DateFormatter();
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS Z";
return ["TIMESTAMP": dateFormatter.string(from: (activity.startDate)), "CONFIDENCE": getConfidence(conf: activity.confidence), "TYPE":type]
}
func getTransformedLocationObject(location: CLLocation) -> [String:String] {
let dateFormatter = DateFormatter();
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS Z";
if #available(iOS 13.4, *) {
return ["TIMESTAMP": dateFormatter.string(from: (location.timestamp)),
"LAT":location.coordinate.latitude.description,
"LONG":location.coordinate.longitude.description,
"HORIZONTAL_ACCURACY":location.horizontalAccuracy.description,
"VERTICAL_ACCURACY":location.verticalAccuracy.description,
"SPEED_ACCURACY":location.speedAccuracy.description,
"SPEED":location.speed.description,
"ALTITUDE":location.altitude.description,
"COURSE":location.course.description,
"COURSE_ACCURACY":location.courseAccuracy.description
]
} else {
// Fallback on earlier versions
//courseAccuracy not available pre ios13.4
return ["TIMESTAMP": dateFormatter.string(from: (location.timestamp)),
"LAT":location.coordinate.latitude.description,
"LONG":location.coordinate.longitude.description,
"HORIZONTAL_ACCURACY":location.horizontalAccuracy.description,
"VERTICAL_ACCURACY":location.verticalAccuracy.description,
"SPEED_ACCURACY":location.speedAccuracy.description,
"SPEED":location.speed.description,
"ALTITUDE":location.altitude.description,
"COURSE":location.course.description,
]
}
}
override func supportedEvents() -> [String]! {
return ["ACTIVITY_UPDATE", "LOCATION_UPDATE", "RESET_ACTIVITY_RECOGNITION"]
}
#objc func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
debugPrint("Got status")
switch status {
case .denied: // Setting option: Never
print("LocationManager didChangeAuthorization denied")
case .notDetermined: // Setting option: Ask Next Time
print("LocationManager didChangeAuthorization notDetermined")
case .authorizedWhenInUse: // Setting option: While Using the App
print("LocationManager didChangeAuthorization authorizedWhenInUse")
// Stpe 6: Request a one-time location information
locationManager.requestLocation()
case .authorizedAlways: // Setting option: Always
print("LocationManager didChangeAuthorization authorizedAlways")
// Stpe 6: Request a one-time location information
locationManager.requestLocation()
debugPrint("Starting significant location tracking from authorization status change delegate")
locationManager.allowsBackgroundLocationUpdates=true
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.startMonitoringSignificantLocationChanges()
case .restricted: // Restricted by parental control
print("LocationManager didChangeAuthorization restricted")
default:
print("LocationManager didChangeAuthorization")
}
}
func application(_ application:UIApplication, willFinishLaunchingWithOptions launchOptions:[UIApplication.LaunchOptionsKey:Any]?) ->Bool{
if let keys = launchOptions?.keys{
if(keys.contains(.location)){
locationManager = CLLocationManager()
locationManager.delegate = self
self.distanceFilter = 50
self.updateDuration = 60000
debugPrint("OS invoked package to deliver location in background")
locationManager.allowsBackgroundLocationUpdates=true
locationManager.distanceFilter = distanceFilter
locationManager.activityType = .automotiveNavigation
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.requestAlwaysAuthorization()
}
}
return true
}
#objc func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
locations.forEach { (location) in
ActivityRecognitionWrapper.shared?.sendEvent(withName: "LOCATION_UPDATE", body: getTransformedLocationObject(location:location))
if(CMMotionActivityManager.isActivityAvailable()){
debugPrint("Starting motion updates for \(updateDuration) seconds" )
if(!activityServiceRunning){
activityServiceRunning = true
motionManager.startActivityUpdates(to: OperationQueue.main)
{ [self]
(activity) in
if (activity?.automotive)! {
ActivityRecognitionWrapper.shared?.sendEvent(withName: "ACTIVITY_UPDATE", body: getTransformedActivityObject(activity: activity!, type: "IN_VEHICLE"))
// debugPrint("User using car")
}
if (activity?.cycling)! {
ActivityRecognitionWrapper.shared?.sendEvent(withName: "ACTIVITY_UPDATE", body: getTransformedActivityObject(activity: activity!, type: "CYCLING"))
// debugPrint("User is cycling")
}
if (activity?.running)!{
ActivityRecognitionWrapper.shared?.sendEvent(withName: "ACTIVITY_UPDATE", body: getTransformedActivityObject(activity: activity!, type: "RUNNING"))
// debugPrint("User is running")
}
if (activity?.walking)! {
ActivityRecognitionWrapper.shared?.sendEvent(withName: "ACTIVITY_UPDATE", body: getTransformedActivityObject(activity: activity!, type: "WALKING"))
// debugPrint("User is walking")
}
if (activity?.stationary)! {
ActivityRecognitionWrapper.shared?.sendEvent(withName: "ACTIVITY_UPDATE", body: getTransformedActivityObject(activity: activity!, type: "STILL"))
// debugPrint("User is stationary")
}
if (activity?.unknown)!{
ActivityRecognitionWrapper.shared?.sendEvent(withName: "ACTIVITY_UPDATE", body: getTransformedActivityObject(activity: activity!, type: "UNKNOWN"))
// debugPrint("Unknown activity")
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + DispatchTimeInterval.milliseconds(updateDuration)) { [self] in
motionManager.stopActivityUpdates()
debugPrint("Stopped motion updates after \(updateDuration) seconds" )
activityServiceRunning = false
}
}
}else {
debugPrint("Motion not available")
}
}
}
#objc func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
debugPrint("LocationManager didFailWithError \(error.localizedDescription)")
if let error = error as? CLError, error.code == .denied {
// Location updates are not authorized.
// To prevent forever looping of `didFailWithError` callback
locationManager.stopMonitoringSignificantLocationChanges()
locationManager.stopUpdatingLocation()
return
}
}
}
I would really appreciate some assistance in changing/restructuring my code so that I can still achieve high-accuracy location and activity tracking without reporting so much battery use, especially during the idle times.
Thanks!
I have an iOS application developed in Swift. My app is currently in Swift 2 but I am using Xcode 8 with Swift 3. The app is configured to use the legacy swift language version.
Until recently the app was working correctly.
The app asks for the correct rights for always use the location and the autorisation is correctly set to always.
I renewed the signing identity for the production app and the app stopped to be notified on a location update but was still working in development mode (launched from xcode).
Now I revoked and renew the production and development certificate and the app does not update the location while in background whereas the autorisation is set to always.
The app is correctly installed so I guess that the certificates are okay but I don't understand why the location is not updated in background.
I run the app on an iPhone 7 with IOS 10.2 and xcode automatically manage signing.
Here is my location manager configuration:
public class LocationManager : NSObject, ModuleManager, CLLocationManagerDelegate {
/// The core location manager
let coreLocationManager: CLLocationManager
public var datas: JSONable? {
get {
return LocationDatas(locations: self.locations)
}
set {
self.locations = newValue == nil ? [Location]() : newValue as? [Location]
}
}
/// The list of locations to send
private var locations: [Location]?
/// The last location
public var lastLocation: Location? {
return self.locations?.last
}
public override init() {
self.coreLocationManager = CLLocationManager()
if #available(iOS 9.0, *) {
self.coreLocationManager.allowsBackgroundLocationUpdates = true
}
// The accuracy of the location data.
self.coreLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
// The minimum distance (measured in meters) a device must move horizontally before an update event is generated.
self.coreLocationManager.distanceFilter = 500; // meters
self.locations = [Location]()
super.init()
self.coreLocationManager.delegate = self
self.locationManager(self.coreLocationManager, didChangeAuthorizationStatus: CLLocationManager.authorizationStatus())
}
// MARK: - CLLocationManager Delegate
public func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
NSLog("location update")
guard locations.count > 0 else {
NSLog("Module Location -- no location available")
return
}
// Add all location waiting in the list to send
self.locations?.appendContentsOf(locations.map { Location(cllocation: $0) })
SDKManager.manager?.sendHeartbeat()
}
public func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch CLLocationManager.authorizationStatus() {
case .NotDetermined:
if #available(iOS 8.0, *) {
self.coreLocationManager.requestAlwaysAuthorization()
} else {
self.coreLocationManager.startUpdatingLocation()
}
case .Denied, .Restricted:
NSLog("Module Location -- access denied to use the location")
case .AuthorizedAlways:
NSLog("AuthorizedAlways")
self.coreLocationManager.startUpdatingLocation()
//self.coreLocationManager.startMonitoringSignificantLocationChanges()
default:
break
}
}
public func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
NSLog("Module Location -- error : \(error)")
}
}
The locationManager function is not called in background.
Here is my info.plist:
Here is the authorization on the phone:
The little location arrow is always there but no location update is logged.
I checked your code and it seems to be fine, revise if you have done these required settings
Enable location updates in Background mode
Add NSLocationAlwaysUsageDescription in your info.plist
If you did not do 1st point you app would have crashed but if did not do 2nd point your code will go through but you will never get updates.
Update:
It seems your LocationManager object is released in ARC. Can you try changing your LocationManager class to Singleton by added
static let sharedInstance = LocationManager()
And accessing LocationManager in your code like this
LocationManager.sharedInstance
You don't need to use App background Refresh just for Location update in Background. (It can be used for other maintenance work like DB cleaning, uploading, downloading, etc. while charging)
While initializing coreLocationManager, set the following properties as well
// It will allow app running location updates in background state
coreLocationManager.allowsBackgroundLocationUpdates = true
// It will not pause location automatically, you can set it true if you require it.
coreLocationManager.pausesLocationUpdatesAutomatically = false
I am developing a code that should get my location every 10 minutes and salvation in CoreData. When I walk into background with conectavo app to xcode can not see the log that the service is running, but when I go out walking the streets he simply not saved or saved too few times.
This is part of my code that should do this function.See save in codeData:
var saveLocationInterval = 60.0
func applicationDidEnterBackground(application: UIApplication) {
UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler(nil)
self.timer = NSTimer.scheduledTimerWithTimeInterval(saveLocationInterval, target: self, selector: #selector(AppDelegate.saveLocation), userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(self.timer, forMode: NSRunLoopCommonModes)
locationController.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
saveLocation()
}
func saveLocation(){
print("======")
let logUser = NSEntityDescription.insertNewObjectForEntityForName("LOG_GPS", inManagedObjectContext: self.managedObjectContext) as! LOG_GPS
if locationController.location == nil{
logUser.latitude = ""
logUser.longitude = ""
} else {
logUser.latitude = "\(locationController.location!.coordinate.latitude)"
logUser.longitude = "\(locationController.location!.coordinate.longitude)"
}
logUser.velocidade = userSpeed > 0 ? Int(userSpeed) : 0
logUser.address = "\(userSpeed)"
if _usuario.chave != nil {
logUser.chave_usuario = "\(_usuario.chave!)"
}
if _empresa.chave != nil {
logUser.chave_licenca = "\(_empresa.chave!)"
}
print("localizaƧao salva no bd \(logUser.latitude)")
let date = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd/MM/yy HH:mm:ss"
let dateString = dateFormatter.stringFromDate(date)
logUser.data = dateString
do {
try self.managedObjectContext.save()
} catch {
}
}
Another major error in my code I can not solve is the User's speed. In the method the low I'm trying to save your speed in a variable and then save the CoreData however this is me always returning a negative value:
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
var speed: CLLocationSpeed = CLLocationSpeed()
speed = newLocation.speed
print(speed * 3.6)
userSpeed = speed * 3.6
}
this is my background mode
Possible solution 1
You need a key in your Info.plist that describes why your app needs background location.
Go to your Info.plist, find the Bundle Version key and click the + that appears when you hover over that. Then add the key NSLocationAlwaysUsageDescription, set it to be a string, and set the value as whatever you want the description to be, like "We need your location in the background so we share your location with friends."
Now your app should work. If it doesn't....
Possible solution 2 (more likely solution if you know what you're doing)
With iOS 9, Apple made it so that apps on physical devices need a special line of code to run location services in the background. The change was not widely reported on (if at all?) but I managed to figure this one out a while ago. Here's what you need to do to get location services working in the background on physical devices again:
In your main location tracking view controller's ViewDidLoad put...
if #available(iOS 9.0, *) {
locationManager.allowsBackgroundLocationUpdates = true
} else {
// You don't need anything else on earlier versions.
}
This will (mysteriously enough) likely be all you need to solve your problem.
In my app, I always download async data in app delegate, and when the app arrives to home screen, it checks if that data is downloaded, and pause the main thread while download hasn't finished like this:
repeat{
sleep(1)
}while asyncData == false
The data is downloading in app delegate, in a core location method:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
//Set coordinates to global var
let coordinates : CLLocationCoordinate2D = manager.location!.coordinate
locValue = coordinates
setCoordinatesDetails(coordinates)
if(self.hasBeenLaunched == false){
self.hasBeenLaunched = true
loadCitySlugArray()
}
}
This method is mandatory in my app, if this method is never called then the app freeze forever. Since there is no apparent reason that this method won't get called, because the code works, there is a case in it's not getting called, when I try to skip the login page (initial view controller), because the user has already been logged in.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
//Core Location
// Ask for Authorisation from the User.
self.locationManager.requestAlwaysAuthorization()
//Core Location
// For use in foreground
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.startUpdatingLocation()
}
userComesFromAppDelegate = true
//Check if it is first time the user login
let token = NSUserDefaults.standardUserDefaults().objectForKey("token")
if(token != nil){
if ((token as! String).isEmpty == false)
{
loginToken = token! as! String
userIsLogged = true
// SKIP LOGIN PAGE
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
var storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController : tabBarControler = storyboard.instantiateViewControllerWithIdentifier("tabBarMaster") as! tabBarControler
self.window?.rootViewController = initialViewController
}
}
return true
}
I don't see how I can skip the initial view controller, except doing it this way, so I'm really stuck here, is this a bug or am I doing something wrong here?? Any help would be appreciated
I am developing a location based app which is supposed to fetch user location always.Im using standard location service. But the problem is that the app after keeping idle for some time in background will not fetch the coordinates even after we move to some other locations. As per apple documentation, when a new location arrives, app should wake up automatically, but that is not happening here. I'm sharing the code and using to fetch location and screenshot of my plist.
class SALocation: NSObject,CLLocationManagerDelegate
{
static let sharedInstance : SALocation = SALocation()
var locationManager : CLLocationManager!
var location : CLLocation!
var address : String!
var latitude : NSString?
var longitude : NSString?
var isAdderssLoaded : Bool = false
var locdictionary : NSMutableDictionary = NSMutableDictionary()
func startLocationManager()
{
if self.locationManager == nil
{
self.locationManager = CLLocationManager()
if CLLocationManager.locationServicesEnabled(){
print("location service enabled")
}
self.locationManager.delegate = self
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.distanceFilter = kCLDistanceFilterNone
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
if ( Float (UIDevice.currentDevice().systemVersion) >= 9) {
if #available(iOS 9.0, *) {
self.locationManager.allowsBackgroundLocationUpdates = true
} else {
// Fallback on earlier versions
};
}
self.locationManager.startUpdatingLocation()
//self.locationManager.stopMonitoringSignificantLocationChanges()
}
else
{
self.locationManager.startUpdatingLocation()
}
}
// MARK: CLLocationManagerDelegate
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
UIAlertView(title:"Alert", message:error.description, delegate: nil, cancelButtonTitle:nil, otherButtonTitles:"Ok").show()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
if locations.count > 0
{
self.location = locations[0]
/* storing date and location to plist
*/
let datenow = NSDate()
let dateformatternow = NSDateFormatter ()
dateformatternow.dateFormat = "yyyyMMdd HH:mm:ss"
let timenow:NSString = dateformatternow.stringFromDate(datenow)
let documetsdirectorypath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last
latitude = NSString(format: "%f",self.location.coordinate.latitude)
longitude = NSString (format: "%f",self.location.coordinate.longitude)
let latlong : NSString = NSString(format:"%#~%#",latitude!,longitude!)
NSUserDefaults.standardUserDefaults().setObject(latlong, forKey: "latlong")
let aFilePath = NSString(format: "%#/location.plist",documetsdirectorypath!)
locdictionary.setObject(latlong, forKey: timenow as String)
locdictionary.writeToFile(aFilePath as String, atomically: true)
///////////// ||storing date and location to plist code ends here||\\\\\\
// self.getAddressFromLocation(locations[0] )
// if (NSUserDefaults.standardUserDefaults().objectForKey(SettingAppRefresh) != nil)
// {
// if (NSUserDefaults.standardUserDefaults().objectForKey(SettingAppRefresh) as! NSString).isEqualToString(FalseString)
// {
// // self.locationManager.stopUpdatingLocation()
// }
// }
}
}
}
What i'm doing here is just get location and write it to a plist file. This works in foreground, background etc fine. But when i keep the app idle for 20 minutes, location is not fetched even if i move to some other locations as the app is suspended
Capabilities tab looks like this
To start location in background you must start background service from the following path
Click on your name -> Click on your app name (target) -> goto capabilities -> find the background mode -> enable the location update mode
I am not sure you started that or not because you not put any screenshot about this.
And also check that your user started background refresh in settings.refer below link for this.
Background App Refresh checking, enabling and disabling programatically for whole device and for each particular application in iOS 7
Update::
For location update in background used below link(objective c)
http://www.creativeworkline.com/2014/12/core-location-manager-ios-8-fetching-location-background/
Well, I don't know how you're getting location updates - significant-location change as example and how you exit from background.
I suggest checking if your app is truly in background mode - UIApplication.sharedApplication().applicationState as it can be terminated.
And I also suggest checking out Apple's Execution States for Apps. - especially for your possible use case Implementing Long-Running Tasks part. There is also a good tutorial at rayywenderlich.com called Background modes.
Please use
self.locationManager.requestAlwaysAuthorization()
and don't forget to update your Info.plist to define the NSLocationAlwaysUsageDescription key.