We receive a complaint from a user that the compass heading in our paragliding app differs from the heading in Compass app (preinstalled on iOS). During our research, it was found that third-party apps show the wrong compass heading.
We get the compass heading according to the documentation (https://developer.apple.com/documentation/corelocation/getting-heading-and-course-information#Get-the-current-heading):
func locationManager(_ manager: CLLocationManager, didUpdateHeading heading: CLHeading) {
magneticHeading = heading.magneticHeading
trueHeading = heading.trueHeading
}
The video linked below shows our app and the third-party app getting the compass heading of 270 degrees, and Compass app (preinstalled) getting the compass heading of 30 degrees. https://drive.google.com/file/d/1HPMRWWq1E_bFYZVyCeqB2Fo-AfG4q9J7/view?usp=share_link
This problem appears to the user unpredictably and the correct compass heading is shown by Compass app (preinstalled). He has iPhone 15 Pro Max and iOS 17.4.1.
The presence of this problem is very critical as it can cause fatal accidents.
A couple things here. First of all, you are showing here is that you are grabbing the heading values from the CLHeading object. But:
- which value (magnetic or true) are you showing as incorrect in your video?
- which value (magnetic or true north) is the Compass app set to use? If you are comparing the two, make sure they are displaying the same thing
- what is the
.headingOrientation
set to for CLLocationManager before you callstartUpdatingHeading()?
The device orientation needs to be set correctly for accurate results - have you been checking the
.headingAccuracy
property of theCLHeading
object to determine if the reported heading is considered accurate or some error is expected. Heading accuracy will depend on factors like GPS location accuracy, the speed of movement, and so on. You may want to correct the heading you are displaying based on this value as well - furthermore what have you set the CLLocationManager's
.activityType
property? For your use case you would want to set it to.airborne
so the system does not try to make corrections not appropriate to the motion patterns which might occur in the air
Alternatively, you can look into the CMDeviceMotion
class, and obtain heading and magnetic field information using the startDeviceMotionUpdates()
call, and see if the results will be more suitable for your use case.
It is important to understand that there are a lot of factors into determining the heading, and a number of things to set and check to get results suitable for each use case. Just using the .heading
value from a heading update may not get you the results you expect, and in a complicated use case like paragliding, where you may or may not have any information of the device orientation and other factors, some additional engineering might be required on the app side.