diff --git a/CapacitorGeolocation.podspec b/CapacitorGeolocation.podspec
index 385b369..999fafc 100644
--- a/CapacitorGeolocation.podspec
+++ b/CapacitorGeolocation.podspec
@@ -13,6 +13,6 @@ Pod::Spec.new do |s|
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
s.ios.deployment_target = '15.0'
s.dependency 'Capacitor'
- s.dependency 'IONGeolocationLib', spec='2.0.0'
+ s.dependency 'IONGeolocationLib', '2.1.0'
s.swift_version = '5.1'
end
diff --git a/Package.swift b/Package.swift
index a39585e..2e69ab6 100644
--- a/Package.swift
+++ b/Package.swift
@@ -11,7 +11,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"),
- .package(url: "https://github.com/ionic-team/ion-ios-geolocation.git", from: "2.0.0")
+ .package(url: "https://github.com/ionic-team/ion-ios-geolocation.git", from: "2.1.0")
],
targets: [
.target(
diff --git a/README.md b/README.md
index 79709af..f9652fe 100644
--- a/README.md
+++ b/README.md
@@ -159,10 +159,10 @@ Not available on web.
#### Position
-| Prop | Type | Description | Since |
-| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----- |
-| **`timestamp`** | number | Creation timestamp for coords | 1.0.0 |
-| **`coords`** | { latitude: number; longitude: number; accuracy: number; altitudeAccuracy: number \| null; altitude: number \| null; speed: number \| null; heading: number \| null; } | The GPS coordinates along with the accuracy of the data | 1.0.0 |
+| Prop | Type | Description | Since |
+| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----- |
+| **`timestamp`** | number | Creation timestamp for coords | 1.0.0 |
+| **`coords`** | { latitude: number; longitude: number; accuracy: number; altitudeAccuracy: number \| null; altitude: number \| null; speed: number \| null; heading: number \| null; magneticHeading: number \| null; trueHeading: number \| null; headingAccuracy: number \| null; course: number \| null; } | The GPS coordinates along with the accuracy of the data | 1.0.0 |
#### PositionOptions
diff --git a/android/build.gradle b/android/build.gradle
index 35f4a12..d4d955b 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -81,7 +81,7 @@ dependencies {
implementation project(':capacitor-android')
}
- implementation("io.ionic.libs:iongeolocation-android:2.1.0")
+ implementation("io.ionic.libs:iongeolocation-android:2.2.0")
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation 'com.google.code.gson:gson:2.13.2'
diff --git a/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt b/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt
index 4a0b2ad..8b8c1a5 100644
--- a/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt
+++ b/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt
@@ -254,7 +254,11 @@ class GeolocationPlugin : Plugin() {
put("altitude", locationResult.altitude)
locationResult.altitudeAccuracy?.let { put("altitudeAccuracy", it) }
put("speed", locationResult.speed)
- put("heading", locationResult.heading)
+ put("heading", if (locationResult.heading != -1f) locationResult.heading else null)
+ put("magneticHeading", locationResult.magneticHeading)
+ put("trueHeading", locationResult.trueHeading)
+ put("headingAccuracy", locationResult.headingAccuracy)
+ put("course", locationResult.course)
}
return JSObject().apply {
put("timestamp", locationResult.timestamp)
diff --git a/example-app/src/js/capacitor-welcome.js b/example-app/src/js/capacitor-welcome.js
index 764a282..1e1acc7 100644
--- a/example-app/src/js/capacitor-welcome.js
+++ b/example-app/src/js/capacitor-welcome.js
@@ -207,13 +207,46 @@ window.customElements.define(
}
const timeRepresentation = location.timestamp ? new Date(location.timestamp).toISOString() : '-';
stringRepresentation += `- Time: ${timeRepresentation}\n`;
- stringRepresentation += `- Latitute: ${location?.coords.latitude}\n- Longitude: ${location?.coords.longitude}\n`;
- if (location?.coords.altitude || location?.coords.heading || location?.coords.speed) {
- stringRepresentation += `- Altitude: ${location?.coords.altitude}\n- Heading: ${location?.coords.heading}\n- Speed: ${location?.coords.speed}\n`;
- }
+ stringRepresentation += `- Latitude: ${location?.coords.latitude}\n- Longitude: ${location?.coords.longitude}\n`;
stringRepresentation += `- Accuracy: ${location?.coords.accuracy}\n`;
- if (location?.coords.altitudeAccuracy) {
- stringRepresentation += `- Altitude accuracy: ${location?.coords.altitudeAccuracy}\n`;
+ stringRepresentation += `- Altitude: ${location?.coords.altitude}\n`;
+ stringRepresentation += `- Altitude accuracy: ${location?.coords.altitudeAccuracy}\n`;
+ stringRepresentation += `- Speed: ${location?.coords.speed}\n`;
+
+ if (
+ location?.coords.heading !== null &&
+ location?.coords.heading !== undefined &&
+ location?.coords.heading !== -1
+ ) {
+ stringRepresentation += `- Heading: ${location.coords.heading}\n`;
+ }
+ if (
+ location?.coords.magneticHeading !== null &&
+ location?.coords.magneticHeading !== undefined &&
+ location?.coords.magneticHeading !== -1
+ ) {
+ stringRepresentation += `- Magnetic Heading: ${location.coords.magneticHeading}\n`;
+ }
+ if (
+ location?.coords.trueHeading !== null &&
+ location?.coords.trueHeading !== undefined &&
+ location?.coords.trueHeading !== -1
+ ) {
+ stringRepresentation += `- True Heading: ${location.coords.trueHeading}\n`;
+ }
+ if (
+ location?.coords.headingAccuracy !== null &&
+ location?.coords.headingAccuracy !== undefined &&
+ location?.coords.headingAccuracy !== -1
+ ) {
+ stringRepresentation += `- Heading Accuracy: ${location.coords.headingAccuracy}\n`;
+ }
+ if (
+ location?.coords.course !== null &&
+ location?.coords.course !== undefined &&
+ location?.coords.course !== -1
+ ) {
+ stringRepresentation += `- Course: ${location.coords.course}\n`;
}
return stringRepresentation;
}
diff --git a/ios/Sources/GeolocationPlugin/GeolocationConstants.swift b/ios/Sources/GeolocationPlugin/GeolocationConstants.swift
index 2f1b18a..6664760 100644
--- a/ios/Sources/GeolocationPlugin/GeolocationConstants.swift
+++ b/ios/Sources/GeolocationPlugin/GeolocationConstants.swift
@@ -33,5 +33,9 @@ enum Constants {
static let speed: String = "speed"
static let timestamp: String = "timestamp"
static let altitudeAccuracy: String = "altitudeAccuracy"
+ static let magneticHeading: String = "magneticHeading"
+ static let trueHeading: String = "trueHeading"
+ static let headingAccuracy: String = "headingAccuracy"
+ static let course: String = "course"
}
}
diff --git a/ios/Sources/GeolocationPlugin/IONGLOCPositionModel+JSONTransformer.swift b/ios/Sources/GeolocationPlugin/IONGLOCPositionModel+JSONTransformer.swift
index 31ce9c8..64f8583 100644
--- a/ios/Sources/GeolocationPlugin/IONGLOCPositionModel+JSONTransformer.swift
+++ b/ios/Sources/GeolocationPlugin/IONGLOCPositionModel+JSONTransformer.swift
@@ -10,9 +10,14 @@ extension IONGLOCPositionModel {
}
private var coordsJSObject: JSObject {
- [
+ let headingValue = trueHeading ?? magneticHeading ?? (course != -1.0 ? course : nil)
+ return [
Constants.Position.altitude: altitude,
- Constants.Position.heading: course,
+ Constants.Position.heading: headingValue ?? NSNull(),
+ Constants.Position.magneticHeading: magneticHeading ?? NSNull(),
+ Constants.Position.trueHeading: trueHeading ?? NSNull(),
+ Constants.Position.headingAccuracy: headingAccuracy ?? NSNull(),
+ Constants.Position.course: course != -1.0 ? course : NSNull(),
Constants.Position.accuracy: horizontalAccuracy,
Constants.Position.latitude: latitude,
Constants.Position.longitude: longitude,
diff --git a/package.json b/package.json
index 5348003..8f38a19 100644
--- a/package.json
+++ b/package.json
@@ -88,4 +88,4 @@
"src": "android"
}
}
-}
+}
\ No newline at end of file
diff --git a/src/definitions.ts b/src/definitions.ts
index e564f92..7ad4281 100644
--- a/src/definitions.ts
+++ b/src/definitions.ts
@@ -140,11 +140,51 @@ export interface Position {
speed: number | null;
/**
- * The heading the user is facing (if available)
+ * The heading the user is facing (if available).
+ *
+ * Historically, this field returned the direction of travel (course) on iOS and Android.
+ * It now prioritizes the compass heading (true or magnetic) if available, falling back
+ * to the direction of travel (course).
*
* @since 1.0.0
*/
heading: number | null;
+
+ /**
+ * The heading (measured in degrees) relative to magnetic north.
+ *
+ * Only available when using `watchPosition`.
+ *
+ * @since 8.2.0
+ */
+ magneticHeading: number | null | undefined;
+
+ /**
+ * The heading (measured in degrees) relative to true north.
+ *
+ * Only available when using `watchPosition`.
+ *
+ * @since 8.2.0
+ */
+ trueHeading: number | null | undefined;
+
+ /**
+ * The maximum deviation (measured in degrees) between the reported heading and the true geomagnetic heading.
+ *
+ * Only available when using `watchPosition`.
+ *
+ * @since 8.2.0
+ */
+ headingAccuracy: number | null | undefined;
+
+ /**
+ * The direction in which the device is travelling, measured in degrees and relative to due north.
+ *
+ * Only available when using `watchPosition`.
+ *
+ * @since 8.2.0
+ */
+ course: number | null | undefined;
};
}
diff --git a/src/web.ts b/src/web.ts
index 697c95d..98bc555 100644
--- a/src/web.ts
+++ b/src/web.ts
@@ -10,11 +10,79 @@ import type {
} from './definitions';
export class GeolocationWeb extends WebPlugin implements GeolocationPlugin {
+ private latestOrientation: {
+ magneticHeading: number | null;
+ trueHeading: number | null;
+ headingAccuracy: number | null;
+ } | null = null;
+
+ constructor() {
+ super();
+ if (typeof window !== 'undefined') {
+ const win = window as any;
+ if ('ondeviceorientationabsolute' in win) {
+ win.addEventListener('deviceorientationabsolute', (event: any) => this.updateOrientation(event, true), true);
+ } else if ('ondeviceorientation' in win) {
+ win.addEventListener('deviceorientation', (event: any) => this.updateOrientation(event, false), true);
+ }
+ }
+ }
+
+ private updateOrientation(event: any, isAbsolute: boolean) {
+ let trueHeading: number | null = null;
+ let magneticHeading: number | null = null;
+ let headingAccuracy: number | null = null;
+
+ if (isAbsolute && event.alpha !== null) {
+ trueHeading = (360 - event.alpha) % 360;
+ } else if (event.webkitCompassHeading !== undefined && event.webkitCompassHeading !== null) {
+ magneticHeading = event.webkitCompassHeading;
+ headingAccuracy = event.webkitCompassAccuracy;
+ } else if (event.alpha !== null && event.absolute === true) {
+ trueHeading = (360 - event.alpha) % 360;
+ } else if (event.alpha !== null) {
+ magneticHeading = (360 - event.alpha) % 360;
+ }
+
+ if (trueHeading !== null || magneticHeading !== null) {
+ this.latestOrientation = {
+ trueHeading,
+ magneticHeading,
+ headingAccuracy,
+ };
+ }
+ }
+
+ private augmentPosition(pos: globalThis.GeolocationPosition, isWatch = false): Position {
+ const coords = pos.coords;
+ const orientation = isWatch ? this.latestOrientation : null;
+
+ const heading =
+ orientation?.trueHeading ?? orientation?.magneticHeading ?? (isWatch ? coords.heading : null) ?? null;
+
+ return {
+ timestamp: pos.timestamp,
+ coords: {
+ latitude: coords.latitude,
+ longitude: coords.longitude,
+ accuracy: coords.accuracy,
+ altitude: coords.altitude,
+ altitudeAccuracy: (coords as any).altitudeAccuracy,
+ speed: coords.speed,
+ heading: heading,
+ magneticHeading: orientation?.magneticHeading ?? null,
+ trueHeading: orientation?.trueHeading ?? null,
+ headingAccuracy: orientation?.headingAccuracy ?? null,
+ course: (isWatch ? coords.heading : null) ?? null,
+ },
+ };
+ }
+
async getCurrentPosition(options?: PositionOptions): Promise {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(pos) => {
- resolve(pos);
+ resolve(this.augmentPosition(pos, false));
},
(err) => {
reject(err);
@@ -32,7 +100,7 @@ export class GeolocationWeb extends WebPlugin implements GeolocationPlugin {
async watchPosition(options: PositionOptions, callback: WatchPositionCallback): Promise {
const id = navigator.geolocation.watchPosition(
(pos) => {
- callback(pos);
+ callback(this.augmentPosition(pos, true));
},
(err) => {
callback(null, err);