未经许可将 SCNNode 旋转到北以进行位置跟踪

Rotate SCNNode to North without permission for location tracking

我们想旋转一个 SCNNode 以便与北方向匹配。

Arkit 允许将其 z 轴与北方对齐,但这需要用户许可才能进行位置跟踪,而我们不想要求这样做。 参见 gravityandheading

因此,我们正在尝试使用 CMDeviceMotion 的磁场 属性。但是我们不知道该怎么做。 大概有一些矩阵计算,我们暂时不掌握。 参见 magneticfield

非常感谢任何帮助!谢谢!

You can't use Location Tracking without user's permission.

这里有一些关于如何为 AR 应用程序NON-AR 应用程序 正确设置它的提示:

iOS 11 及更高版本 中,您需要执行以下操作才能使位置正常工作:

  • 向您的 info.plist 添加一个密钥,并向位置管理员请求授权以启动它。 info.plist中有两个Property List Keys用于位置授权。 需要其中一个或两个键。在非 AR 应用程序中,如果两个键都不存在,您可以调用 startUpdatingLocation 方法,但位置管理器不会真正启动。它也不会向委托发送失败消息(因为它从未启动,所以它不会失败)。 如果您添加一个或两个密钥但忘记明确请求授权,它也会失败

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/>

AR 应用的代码 应如下所示:

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])
}

对于非 AR 应用程序,使用这两个实例方法:requestAlwaysAuthorization()(请求在应用程序处于 运行 时使用位置服务的权限)和 requestWhenInUseAuthorization()(请求使用位置的权限应用程序在前台运行时的服务)。

您的代码非 AR 应用程序 应如下所示:

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()
        }
    }
}

此外,您可以请求 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
    }      
}

希望对您有所帮助。