Tuesday, March 13, 2018

App Crashes When Background Location Received

Leave a Comment

I am trying to send location update to server in the background

Here is my locationmanager delegate

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {              if let lat = manager.location?.coordinate.latitude,                 let long = manager.location?.coordinate.longitude {                 glat = String(lat)                 glong = String(long)                  if UIApplication.shared.applicationState == .background {                 self.updatebackloc(lat, long: long)                 }                  if UIApplication.shared.applicationState == .active {                 self.updateloc(lat, long: long)                     locationManager.stopUpdatingLocation()                     let status = CLLocationManager.authorizationStatus()                     if (status == CLAuthorizationStatus.authorizedAlways) {                     locationManager.startMonitoringSignificantLocationChanges()                     }                 }             }             } 

This is the updatebacklog function

func updatebackloc(_ lat: CLLocationDegrees, long: CLLocationDegrees) {         let userID = TegKeychain.get("userID")!         let parameters: Parameters = ["userID": userID, "lat": lat, "long":long]         Alamofire.request("https://xxxxx.com/ios/updatebackloc.php", method: .post, parameters: parameters).validate().responseJSON { response in             switch response.result {             case .success:                 if let json = response.result.value {                     var success = 0                     if let dictJSON = json as? [String: AnyObject] {                         if let successInteger = dictJSON["success"] as? Int {                             success = successInteger                             if success == 1                             {                              }                         }                     }                 }             case .failure(_):                 return             }         }     } 

didFinishLaunchingWithOptions part

if let _ = launchOptions?[UIApplicationLaunchOptionsKey.location] {                     startSignificationLocation()                 } 

startSignificationLocation function triggered on didFinishLaunchingWithOptions

func startSignificationLocation() {         let locationManager = CLLocationManager()         locationManager.delegate = self         locationManager.desiredAccuracy = kCLLocationAccuracyBest         locationManager.requestAlwaysAuthorization()         locationManager.allowsBackgroundLocationUpdates = true         locationManager.startMonitoringSignificantLocationChanges()     } 

Here is the crash log

Crashed: com.apple.main-thread 0 libswiftCore.dylib
0x10294b1ac specialized fatalErrorMessage(:_:file:line:flags:) + 120 1 Jemiyet 0x100e20824 AppDelegate.updatebackloc(Double, long : Double) -> () (AppDelegate.swift:436) 2 Jemiyet 0x100e1fa78 AppDelegate.locationManager(CLLocationManager, didUpdateLocations : [CLLocation]) -> () (AppDelegate.swift:396) 3 Jemiyet
0x100e1fd7c @objc AppDelegate.locationManager(CLLocationManager, didUpdateLocations : [CLLocation]) -> () (AppDelegate.swift) 4 CoreLocation 0x1891ad7bc (null) + 77412 5 CoreLocation 0x1891ad01c (null) + 75460 6 CoreLocation 0x1891956b4 (null) + 1004 7 CoreFoundation 0x182b57590 CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK + 20 8 CoreFoundation 0x182b56e60 __CFRunLoopDoBlocks + 288 9 CoreFoundation
0x182b550c8 __CFRunLoopRun + 2436 10 CoreFoundation
0x182a74c58 CFRunLoopRunSpecific + 436 11 GraphicsServices
0x184920f84 GSEventRunModal + 100 12 UIKit
0x18c1cd5c4 UIApplicationMain + 236 13 Jemiyet
0x100e21598 main (AppDelegate.swift:30) 14 libdyld.dylib
0x18259456c start + 4

3 Answers

Answers 1

I highly suspect you are trying to force-unwrap a nil value in this line:

let userID = TegKeychain.get("userID")! 

To figure out if I am correct, try if this fixes the crash (but still does not do what you want obviously):

guard let userID = TegKeychain.get("userID") else {     return } 

Assuming TegKeychain.get("userID") is trying to get a value for a key from the system KeyChain, this value has most probably been written to the KeyChain with a non-suitable accessibility. Thus you are not allowed to access it in background and nil is returned.

To fix this, set a value that fits your needs for key kSecAttrAccessible when saving the credential to the KeyChain.

kSecAttrAccessibleAfterFirstUnlock is recommended by Apple and probably fits your needs.

In code:

let userIdToSave = "secretString" guard let secretAsData = userIdToSave.data(using: String.Encoding.utf8) else {     return } let keyChainKey = "userID" let query = [     kSecClass as String: kSecClassGenericPassword as String,     kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock as String,     kSecAttrService as String: yourService,     kSecAttrAccount as String: keyChainKey,     kSecValueData as String: secretAsData] as [String : Any]  SecItemDelete(query as CFDictionary)  let status = SecItemAdd(query as CFDictionary, nil) 

For details check Apples Documentation.

Answers 2

I guess you need to configure an Alamofire Session Manager with the background configuration in order to perform a request in the background. Then in order to make the request use the properly configured session manager.

e.g.

let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.app.background") let sessionManager = Alamofire.SessionManager(configuration: configuration) 

Answers 3

Have you enabled the location services for background modes? If yes then try to reinitialise location manager when you enter background it actually worked for me but the best practise is to save the coordinates in data-base whenever user became active sync unsynced records to the server. enter image description here

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment