Rotate SCNNode to North without permission for location tracking - ios

We would like to rotate a SCNNode so as to match with the North direction.
Arkit allows to align its z-axis with the North but this requires user permission for location tracking, and we don't want to ask for it.
see gravityandheading
As a consequence, we're trying to use the magnetic field property of CMDeviceMotion. But we have no idea how to do that.
There are probably some matrix calculations, but we don't master them for the time being.
see magneticfield
Any help would be highly appreciated! thanks!

You cannot use Location Tracking without user's permission.
Here are some tips on how to setup it properly for AR apps and NON-AR apps:
In iOS 11 and higher here's what you need to do to get location working:
Add a key to your info.plist and request authorisation from the location manager asking it to start. There are two Property List Keys in info.plist for the location authorisation. One or both of these keys is required. In NON-AR apps if neither of the keys are there, you can call startUpdatingLocation method but the location manager won’t actually start. It won’t send a failure message to the delegate either (since it never started, it can’t fail). It will also fail if you add one or both of the keys but forget to explicitly request authorisation.
Use these two Property List Keys in info.plist file. They are used since iOS 11 was released:
<key>NSLocationWhenInUseUsageDescription</key>
<string>App needs an access to your location (in foreground)</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>App needs an access to your location (in background)</string>
And these two Property List Keys were deprecated earlier (DON'T USE THESE KEYS):
<key>NSLocationUsageDescription</key>
<string>App needs an access to your location (in background)</string>
<key>NSLocationAlwaysUsageDescription</key>
<true/>
Here's how your code for AR apps should look like:
let configuration = ARWorldTrackingConfiguration()
func session(_ session: ARSession, didFailWithError error: Error) {
switch error.code {
case 101:
configuration.worldAlignment = .gravity
restartSession()
default:
configuration.worldAlignment = .gravityAndHeading
restartSession()
}
}
func restartSession() {
self.sceneView.session.pause()
self.sceneView.session.run(configuration,
options: [.resetTracking, .removeExistingAnchors])
}
For NON-AR apps use these two instance methods: requestAlwaysAuthorization() (requests permission to use location services whenever the app is running) and requestWhenInUseAuthorization() (requests permission to use location services while the app is in the foreground).
Here's how your code for NON-AR apps should look like:
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
func updateMyLocation() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
if locationManager.respondsToSelector(#selector(CLLocationManager.requestWhenInUseAuthorization)) {
locationManager.requestWhenInUseAuthorization()
} else {
locationManager.startUpdatingLocation()
}
}
}
Also, you can request Always Authorization:
let locationManager = CLLocationManager()
func enableLocationServices() {
locationManager.delegate = self
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
// Request when-in-use authorization initially
locationManager.requestWhenInUseAuthorization()
break
case .restricted, .denied:
// Disable location features
disableMyLocationBasedFeatures()
break
case .authorizedWhenInUse:
// Enable basic location features
enableMyWhenInUseFeatures()
break
case .authorizedAlways:
// Enable any of your app's location features
enableMyAlwaysFeatures()
break
}
}
Hope this helps.

Related

how to prevent mock GPS location (spoofing) from fake GPS app in Swift? [duplicate]

This question already has answers here:
iOS detect mock locations
(5 answers)
Closed 4 years ago.
I am making an app that using CLLocationManager, this app will be used to record the attendee of the employee. to validate the attendee of the employees, we will get GPS Coordinate.
as far as I know, in there is an app that usually used to get fake GPS. I want to prevent this mock GPS to be active when the user using my app.
If I am using Android, I can download a fake GPS app. and when let say I use tinder I can fake my location. let say actually I am in Bangkok, but because I use fake GPS app, I can set my tinder location to be in London, not in Bangkok anymore.
So Basically I want to prevent fake location that comes from that fake GPS when the user using my App. To be honest I don't really know whether iOS allow fake location or not
can I get that function in Swift?
here is the class LocationManager I use to get the coordinate
import UIKit
import CoreLocation
class LocationManager: NSObject {
let manager = CLLocationManager()
var didGetLocation: ((Coordinate?) -> Void)?
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestLocation()
}
func getPermission() {
// to ask permission to the user by showing an alert (the alert message is available on info.plist)
if CLLocationManager.authorizationStatus() == .notDetermined {
manager.requestWhenInUseAuthorization()
}
}
}
extension LocationManager : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
manager.requestLocation()
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error.localizedDescription)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.first else {
didGetLocation?(nil)
return
}
let coordinate = Coordinate(location: location)
if let didGetLocation = didGetLocation {
didGetLocation(coordinate)
}
}
}
private extension Coordinate {
init(location: CLLocation) {
latitude = location.coordinate.latitude
longitude = location.coordinate.longitude
}
}
You can check if the app is jailbroken or not. If it already jailbroken, you can prevent the user to use the app with showing permanent dialog or something else.
If you wanna know how to detect the device is jailbroken or not, you can find it by yourself. There is so many literature that will tell you how.
Cheers :)
Only thing I can tell you and I've been in a similar situation is you need to have a backup method to get the user location. Use an IP location API/service (which is not 100% reliable) and create a logic in your app to compare the data.
PS: THIS IS NOT A SOLUTION TO YOUR PROBLEM it's just an idea you could try to work with. But this would only work best if spoofing the location is happening using different cities/states since IP location is not a high accuracy one. If GPS says you are in San Diego but your IP say you are in San Francisco, then you could block the UI/request until user confirms something.
PS2: in iOS the only way I know a user can spoof it's location is running an app through XCode, using the location feature and then opening your app. (used to do that a lot with pokemon go #notproud :))

continuous iOS location updates in background

I am trying to create a simple iOS app that will continuously track location in the background and notify with high accuracy when the user has entered a specific region (don't want to use region monitoring because it's not accurate or fast enough for what I want).
This app works fine in the foreground but once I go into the background it does not work.
I created a test app to investigate how background location updates work. I made a simple app that just prints out a message when a location update happens (to the log).
What I see is that in foreground mode the updates happen as expected but when I lock my phone and the app switches to background the location updates happen for about 30 seconds and then stop. There is no mention in the Apple docs (that I can find) explaining this behavior.
I made sure that I enabled background processing in the info.plist (done in "capabilities" --> "background modes" --> "location updates")
Here is the code I used to test this:
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var counter = 0
override func viewDidLoad() {
super.viewDidLoad()
// configure location updates
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 0.1
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("location updated! \(counter)")
counter = counter + 1
}
Any ideas on what I might be missing? I tried different location accuracy settings (such as BestForNavigation, etc) and no change.
Thanks.
You have to add this in your plist :
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
add this
locationManager.allowsBackgroundLocationUpdates = true
I think this might be the answer:
allowsBackgroundLocationUpdates.
Apps that want to receive location updates when suspended must include
the UIBackgroundModes key (with the location value) in their app’s
Info.plist file and set the value of this property to true.
...
The
default value of this property is false.
Are you setting that?
You can add these two line to make it working in background mode:
locationManager!.allowsBackgroundLocationUpdates = true
locationManager!.pausesLocationUpdatesAutomatically = false

Unable to get the permission prompt from CLLocationManager

Here is my code from a ViewController implementing CLLocationManagerDelegate:
func startLocationManager() {
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
println("I'm called")
locationManager.requestAlwaysAuthorization()
// locationManager.startMonitoringSignificantLocationChanges()
locationManager.startUpdatingLocation()
let status = CLLocationManager.authorizationStatus()
println(status.rawValue) // This print 0 which stands for kCLAuthorizationStatusNotDetermined
println(CLLocationManager.locationServicesEnabled()) // true
}
func locationManager(manager: CLLocationManager!,
didUpdateLocations locations: [AnyObject]!) {
println("nobody call me ever, and I'm sad")
}
For some reason, I never get the prompt / alter to autorise location updates. I have tried on my device iOS 8.1 and the simulartor. I followed the advices found here: requestAlwaysAuthorization not showing permission alert :
"Add Core Location framework to Project Settings / Targets / Capabilities / Background Modes set "Location Updates" and "Uses Bluetooth LE Accessories" Add key at Info.plist NSLocationAlwaysUsageDescription".
I have also tried to clean up and rebuild, nothing change. I feel clueless.
EDIT: This question seems related: iOS: App is not asking user's permission while installing the app. getting kCLAuthorizationStatusNotDetermined every time - Objective-c & Swift but the selected answer and its article doesn't expose anything new
Your CLLocationManager object is local object and thus will be deallocated immediately after it falls out of scope. Make it a class property and then asynchronous processes like requesting authorization and determining the location will have a chance to run.

core location not asking permission

problem :
For some reason, the app I’m working on is not asking for permission to use location services. This used to work before. Also, I created a new project in which I followed the steps described below EXACTLY in which this worked immediately.
One difference is I know the authorization status in the main app I’m working on is .Denied, it was .NotDetermined in the test project.
I read this answe on stack overflow :
Core Location not requesting user permission
'
Not many people know this, but after you uninstall an application, that application's documents and preferences are still stored on the device, here:
/var/mobile/Library/Safe Harbor/myappidentifier/Container/
in my opinion, this was not a wise move by apple, as that could have security risks, as the one you have explained above.
If an app is re-installed, iOS automatically copies those preferences back into the appropriate folder. That is the cause of the behavior you are seeing.
'
This could explain it because I did reinstall the app but it doesn't say how to solve it.
Thank you
Here’s the relevant code i wrote in the App :
I set the NSLocationAlwaysUsageDescription key in info.plist
I imported core location :
import CoreLocation
implemented the right protocol:
CLLocationManagerDelegate
set this property :
var locationManager = CLLocationManager()
set the delegate in ViewDidLoad
locationManager.delegate = self
and wrote a test function to test this :
if CLLocationManager.locationServicesEnabled() {
println("Location Services Enabled")
if CLLocationManager.authorizationStatus() == .Authorized {
println("Location Services Authorized")
} else if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse {
println("Location Services Authorized WHEN IN USE")
} else if CLLocationManager.authorizationStatus() == .NotDetermined {
println("Location Services NOT Authorized: NOT DETERMINED")
} else if CLLocationManager.authorizationStatus() == .Restricted {
println("Location Services NOT Authorized: RESTRICTED")
} else if CLLocationManager.authorizationStatus() == .Denied {
println("Location Services NOT Authorized: DENIED")
} else {
println("Location Services NOT Authorized")
locationManager.requestAlwaysAuthorization()
}
} else {
println("!!! Location Services NOT Enabled !!!")
}
Console Output :
Location Services Enabled
Location Services NOT Authorized
You can go into the Settings app, General, and reset Location & Privacy to get the initial permission dialog for your app again. Otherwise, iOS saves the first answer without ever asking again.

CoreLocation Authorization issues - never prompted for authorization

I was testing out CoreLocation to learn how to capture and record the location of the user. I built a simple Master-Detail app which, in the detail pane, showed the user's live location. Everything worked as expected.
Next, I moved on to making my real app which also uses CoreLocation. I built the app with a Master-Detail style and also made it so that when the user opens the detail pane, it should show their current, live, location. However, nothing happens at all.
What I determined after a LOT of debugging and research is that as soon as my locationManager is created and I call locationManager.startUpdatingLocation() the authorization to get the location is changed to denied (or false, or whatever its called). The only way I can get live tracking is build and run the app in Xcode, once it opens in the simulator, open up Location Services and change the app setting to allow location tracking to "Always". Then I can see in the console that locations are being acquired.
I don't understand why I have to keep changing the authorization to "Always" over and over. I have deleted the app on the simulator, done a "clean" from XCode to start fresh, and still it starts on the simulator without authorization.
Anyone have ideas?
UPDATE Now I see that, when I build and it runs in the simulator, I get ONE location, then the authorization is changed to not allow location services.
Here's my code (which worked on another app):
import UIKit
import CoreLocation
class DetailViewController: UIViewController, CLLocationManagerDelegate {
var locationManager : CLLocationManager!
func startTrackingLocation() {
println("tracking engaged")
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization() // <-- this was originally commented out
locationManager.startUpdatingLocation()
println("and we're tracking")
println(locationManager.location)
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
println("location acquired") // <--- Only see this when I manually allow location when app is running
self.newLongLabel?.text = "\(locations[0].coordinate.longitude)"
self.newLatLabel?.text = "\(locations[0].coordinate.latitude)"
}
override func viewDidLoad() {
super.viewDidLoad()
self.startTrackingLocation()
self.configureView()
}
// more class stuff...
If you're certain you have added the key to plist file try checking for it in the didChangeAuthorizationStatus: location manager delegate method.
Be sure you have both keys in plist as type string and with the values you would like to display to the user:
NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
- (void) locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways){
if ([CLLocationManager locationServicesEnabled]) {
[yourLocationManager startMonitoringSignificantLocationChanges];
//run your code here
}
}
}

Resources