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.
0 comments:
Post a Comment