3

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!

Bhavesh Nayi
  • 3,626
  • 1
  • 27
  • 42
Gogo123
  • 655
  • 1
  • 4
  • 11
  • If you need the node to precisely align with the north axis; keep in mind that using only the device sensors to find the direction would not be enough in a lot of situations, as interference of electromagnetic fields would be too strong creating a sizable error. – A. Claesson May 07 '19 at 10:52
  • No you can't get it without location permission !! , If you need to rotate any node to north you must know the where the device facing and for that you need location permission – Prashant Tukadiya May 08 '19 at 04:57

1 Answers1

0

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.

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220