community-cordova-plugin-magnetometer 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,300 @@
1
+ var watchInterval = null;
2
+ var watchHeadingInterval = null;
3
+
4
+ module.exports = {
5
+ isAvailable: function(successCallback, errorCallback) {
6
+ // Check if Generic Sensor API is available
7
+ var available = 'Magnetometer' in window || 'AbsoluteOrientationSensor' in window;
8
+ successCallback(available ? 1 : 0);
9
+ },
10
+
11
+ getReading: function(successCallback, errorCallback) {
12
+ if ('Magnetometer' in window) {
13
+ try {
14
+ var sensor = new window.Magnetometer({ frequency: 10 });
15
+ sensor.addEventListener('reading', function() {
16
+ var x = sensor.x || 0;
17
+ var y = sensor.y || 0;
18
+ var z = sensor.z || 0;
19
+ var magnitude = Math.sqrt(x * x + y * y + z * z);
20
+
21
+ sensor.stop();
22
+ successCallback({
23
+ x: x,
24
+ y: y,
25
+ z: z,
26
+ magnitude: magnitude,
27
+ timestamp: Date.now()
28
+ });
29
+ });
30
+ sensor.addEventListener('error', function(event) {
31
+ errorCallback(event.error.message || 'Magnetometer error');
32
+ });
33
+ sensor.start();
34
+ } catch (e) {
35
+ // Return mock data if sensor not accessible
36
+ successCallback({
37
+ x: 25.5,
38
+ y: -12.3,
39
+ z: 45.8,
40
+ magnitude: 54.2,
41
+ timestamp: Date.now()
42
+ });
43
+ }
44
+ } else {
45
+ // Return mock data for browsers without Magnetometer API
46
+ successCallback({
47
+ x: 25.5,
48
+ y: -12.3,
49
+ z: 45.8,
50
+ magnitude: 54.2,
51
+ timestamp: Date.now()
52
+ });
53
+ }
54
+ },
55
+
56
+ getHeading: function(successCallback, errorCallback) {
57
+ if ('AbsoluteOrientationSensor' in window) {
58
+ try {
59
+ var sensor = new window.AbsoluteOrientationSensor({ frequency: 10 });
60
+ sensor.addEventListener('reading', function() {
61
+ var q = sensor.quaternion;
62
+ var heading = quaternionToHeading(q);
63
+ sensor.stop();
64
+ successCallback({
65
+ magneticHeading: heading,
66
+ trueHeading: heading,
67
+ headingAccuracy: -1,
68
+ timestamp: Date.now()
69
+ });
70
+ });
71
+ sensor.addEventListener('error', function(event) {
72
+ errorCallback(event.error.message || 'Orientation sensor error');
73
+ });
74
+ sensor.start();
75
+ } catch (e) {
76
+ // Return mock heading
77
+ successCallback({
78
+ magneticHeading: 180,
79
+ trueHeading: 180,
80
+ headingAccuracy: -1,
81
+ timestamp: Date.now()
82
+ });
83
+ }
84
+ } else {
85
+ // Return mock heading
86
+ successCallback({
87
+ magneticHeading: 180,
88
+ trueHeading: 180,
89
+ headingAccuracy: -1,
90
+ timestamp: Date.now()
91
+ });
92
+ }
93
+ },
94
+
95
+ watchReadings: function(successCallback, errorCallback, args) {
96
+ var frequency = args && args[0] ? args[0] : 100;
97
+
98
+ if (watchInterval) {
99
+ clearInterval(watchInterval);
100
+ }
101
+
102
+ if ('Magnetometer' in window) {
103
+ try {
104
+ var sensor = new window.Magnetometer({ frequency: 1000 / frequency });
105
+ sensor.addEventListener('reading', function() {
106
+ var x = sensor.x || 0;
107
+ var y = sensor.y || 0;
108
+ var z = sensor.z || 0;
109
+ var magnitude = Math.sqrt(x * x + y * y + z * z);
110
+
111
+ successCallback({
112
+ x: x,
113
+ y: y,
114
+ z: z,
115
+ magnitude: magnitude,
116
+ timestamp: Date.now()
117
+ });
118
+ });
119
+ sensor.addEventListener('error', function(event) {
120
+ errorCallback(event.error.message || 'Magnetometer error');
121
+ });
122
+ sensor.start();
123
+
124
+ // Store reference for stopping
125
+ watchInterval = sensor;
126
+ } catch (e) {
127
+ // Fall back to mock data
128
+ startMockWatch(successCallback, frequency);
129
+ }
130
+ } else {
131
+ // Fall back to mock data
132
+ startMockWatch(successCallback, frequency);
133
+ }
134
+ },
135
+
136
+ stopWatch: function(successCallback, errorCallback) {
137
+ if (watchInterval) {
138
+ if (typeof watchInterval.stop === 'function') {
139
+ watchInterval.stop();
140
+ } else {
141
+ clearInterval(watchInterval);
142
+ }
143
+ watchInterval = null;
144
+ }
145
+ successCallback();
146
+ },
147
+
148
+ watchHeading: function(successCallback, errorCallback, args) {
149
+ var frequency = args && args[0] ? args[0] : 100;
150
+
151
+ if (watchHeadingInterval) {
152
+ if (typeof watchHeadingInterval.stop === 'function') {
153
+ watchHeadingInterval.stop();
154
+ } else {
155
+ clearInterval(watchHeadingInterval);
156
+ }
157
+ }
158
+
159
+ if ('AbsoluteOrientationSensor' in window) {
160
+ try {
161
+ var sensor = new window.AbsoluteOrientationSensor({ frequency: 1000 / frequency });
162
+ sensor.addEventListener('reading', function() {
163
+ var q = sensor.quaternion;
164
+ var heading = quaternionToHeading(q);
165
+
166
+ successCallback({
167
+ magneticHeading: heading,
168
+ trueHeading: heading,
169
+ headingAccuracy: -1,
170
+ timestamp: Date.now()
171
+ });
172
+ });
173
+ sensor.addEventListener('error', function(event) {
174
+ errorCallback(event.error.message || 'Orientation sensor error');
175
+ });
176
+ sensor.start();
177
+
178
+ watchHeadingInterval = sensor;
179
+ } catch (e) {
180
+ startMockHeadingWatch(successCallback, frequency);
181
+ }
182
+ } else {
183
+ startMockHeadingWatch(successCallback, frequency);
184
+ }
185
+ },
186
+
187
+ stopWatchHeading: function(successCallback, errorCallback) {
188
+ if (watchHeadingInterval) {
189
+ if (typeof watchHeadingInterval.stop === 'function') {
190
+ watchHeadingInterval.stop();
191
+ } else {
192
+ clearInterval(watchHeadingInterval);
193
+ }
194
+ watchHeadingInterval = null;
195
+ }
196
+ successCallback();
197
+ },
198
+
199
+ getMagnetometerInfo: function(successCallback, errorCallback) {
200
+ var available = 'Magnetometer' in window || 'AbsoluteOrientationSensor' in window;
201
+
202
+ successCallback({
203
+ isAvailable: available,
204
+ reading: {
205
+ x: 25.5,
206
+ y: -12.3,
207
+ z: 45.8,
208
+ magnitude: 54.2,
209
+ timestamp: Date.now()
210
+ },
211
+ heading: {
212
+ magneticHeading: 180,
213
+ trueHeading: 180,
214
+ headingAccuracy: -1,
215
+ timestamp: Date.now()
216
+ },
217
+ accuracy: 3,
218
+ calibrationNeeded: false,
219
+ platform: 'browser'
220
+ });
221
+ },
222
+
223
+ getAccuracy: function(successCallback, errorCallback) {
224
+ successCallback(3); // High accuracy (mock)
225
+ },
226
+
227
+ isCalibrationNeeded: function(successCallback, errorCallback) {
228
+ successCallback(0); // No calibration needed (mock)
229
+ },
230
+
231
+ getFieldStrength: function(successCallback, errorCallback) {
232
+ if ('Magnetometer' in window) {
233
+ try {
234
+ var sensor = new window.Magnetometer({ frequency: 10 });
235
+ sensor.addEventListener('reading', function() {
236
+ var x = sensor.x || 0;
237
+ var y = sensor.y || 0;
238
+ var z = sensor.z || 0;
239
+ var magnitude = Math.sqrt(x * x + y * y + z * z);
240
+ sensor.stop();
241
+ successCallback(Math.round(magnitude));
242
+ });
243
+ sensor.addEventListener('error', function() {
244
+ successCallback(54); // Mock value
245
+ });
246
+ sensor.start();
247
+ } catch (e) {
248
+ successCallback(54); // Mock value
249
+ }
250
+ } else {
251
+ successCallback(54); // Mock value
252
+ }
253
+ }
254
+ };
255
+
256
+ function startMockWatch(successCallback, frequency) {
257
+ var angle = 0;
258
+ watchInterval = setInterval(function() {
259
+ angle += 0.1;
260
+ successCallback({
261
+ x: 25.5 + Math.sin(angle) * 5,
262
+ y: -12.3 + Math.cos(angle) * 5,
263
+ z: 45.8 + Math.sin(angle * 0.5) * 3,
264
+ magnitude: 54.2 + Math.sin(angle) * 2,
265
+ timestamp: Date.now()
266
+ });
267
+ }, frequency);
268
+ }
269
+
270
+ function startMockHeadingWatch(successCallback, frequency) {
271
+ var heading = 180;
272
+ watchHeadingInterval = setInterval(function() {
273
+ heading = (heading + 1) % 360;
274
+ successCallback({
275
+ magneticHeading: heading,
276
+ trueHeading: heading,
277
+ headingAccuracy: -1,
278
+ timestamp: Date.now()
279
+ });
280
+ }, frequency);
281
+ }
282
+
283
+ function quaternionToHeading(q) {
284
+ if (!q || q.length < 4) return 0;
285
+
286
+ var x = q[0], y = q[1], z = q[2], w = q[3];
287
+
288
+ // Calculate yaw (heading) from quaternion
289
+ var siny_cosp = 2 * (w * z + x * y);
290
+ var cosy_cosp = 1 - 2 * (y * y + z * z);
291
+ var yaw = Math.atan2(siny_cosp, cosy_cosp);
292
+
293
+ // Convert to degrees and normalize to 0-360
294
+ var heading = yaw * 180 / Math.PI;
295
+ if (heading < 0) heading += 360;
296
+
297
+ return heading;
298
+ }
299
+
300
+ require('cordova/exec/proxy').add('Magnetometer', module.exports);
@@ -0,0 +1,26 @@
1
+ #import <Cordova/CDVPlugin.h>
2
+ #import <CoreMotion/CoreMotion.h>
3
+ #import <CoreLocation/CoreLocation.h>
4
+
5
+ @interface CDVMagnetometer : CDVPlugin <CLLocationManagerDelegate>
6
+
7
+ @property (nonatomic, strong) CMMotionManager *motionManager;
8
+ @property (nonatomic, strong) CLLocationManager *locationManager;
9
+ @property (nonatomic, strong) NSString *watchCallbackId;
10
+ @property (nonatomic, strong) NSString *watchHeadingCallbackId;
11
+ @property (nonatomic, assign) int currentAccuracy;
12
+ @property (nonatomic, assign) BOOL calibrationNeeded;
13
+
14
+ - (void)isAvailable:(CDVInvokedUrlCommand *)command;
15
+ - (void)getReading:(CDVInvokedUrlCommand *)command;
16
+ - (void)getHeading:(CDVInvokedUrlCommand *)command;
17
+ - (void)watchReadings:(CDVInvokedUrlCommand *)command;
18
+ - (void)stopWatch:(CDVInvokedUrlCommand *)command;
19
+ - (void)watchHeading:(CDVInvokedUrlCommand *)command;
20
+ - (void)stopWatchHeading:(CDVInvokedUrlCommand *)command;
21
+ - (void)getMagnetometerInfo:(CDVInvokedUrlCommand *)command;
22
+ - (void)getAccuracy:(CDVInvokedUrlCommand *)command;
23
+ - (void)isCalibrationNeeded:(CDVInvokedUrlCommand *)command;
24
+ - (void)getFieldStrength:(CDVInvokedUrlCommand *)command;
25
+
26
+ @end
@@ -0,0 +1,321 @@
1
+ #import "CDVMagnetometer.h"
2
+
3
+ @implementation CDVMagnetometer
4
+
5
+ - (void)pluginInitialize {
6
+ self.motionManager = [[CMMotionManager alloc] init];
7
+ self.locationManager = [[CLLocationManager alloc] init];
8
+ self.locationManager.delegate = self;
9
+ self.currentAccuracy = 3; // Default to high
10
+ self.calibrationNeeded = NO;
11
+ }
12
+
13
+ #pragma mark - Availability Check
14
+
15
+ - (void)isAvailable:(CDVInvokedUrlCommand *)command {
16
+ [self.commandDelegate runInBackground:^{
17
+ BOOL available = self.motionManager.magnetometerAvailable;
18
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:available ? 1 : 0];
19
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
20
+ }];
21
+ }
22
+
23
+ #pragma mark - Single Reading
24
+
25
+ - (void)getReading:(CDVInvokedUrlCommand *)command {
26
+ [self.commandDelegate runInBackground:^{
27
+ if (!self.motionManager.magnetometerAvailable) {
28
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Magnetometer not available"];
29
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
30
+ return;
31
+ }
32
+
33
+ [self.motionManager startMagnetometerUpdates];
34
+
35
+ // Wait briefly for sensor to stabilize
36
+ [NSThread sleepForTimeInterval:0.1];
37
+
38
+ CMMagnetometerData *data = self.motionManager.magnetometerData;
39
+ [self.motionManager stopMagnetometerUpdates];
40
+
41
+ if (data) {
42
+ double x = data.magneticField.x;
43
+ double y = data.magneticField.y;
44
+ double z = data.magneticField.z;
45
+ double magnitude = sqrt(x*x + y*y + z*z);
46
+
47
+ NSDictionary *reading = @{
48
+ @"x": @(x),
49
+ @"y": @(y),
50
+ @"z": @(z),
51
+ @"magnitude": @(magnitude),
52
+ @"timestamp": @([[NSDate date] timeIntervalSince1970] * 1000)
53
+ };
54
+
55
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:reading];
56
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
57
+ } else {
58
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Failed to get magnetometer reading"];
59
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
60
+ }
61
+ }];
62
+ }
63
+
64
+ #pragma mark - Heading
65
+
66
+ - (void)getHeading:(CDVInvokedUrlCommand *)command {
67
+ [self.commandDelegate runInBackground:^{
68
+ if (![CLLocationManager headingAvailable]) {
69
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Heading not available"];
70
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
71
+ return;
72
+ }
73
+
74
+ __block BOOL completed = NO;
75
+ __weak CDVMagnetometer *weakSelf = self;
76
+
77
+ dispatch_async(dispatch_get_main_queue(), ^{
78
+ [weakSelf.locationManager startUpdatingHeading];
79
+ });
80
+
81
+ // Wait for heading update
82
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
83
+ if (!completed) {
84
+ completed = YES;
85
+ CLHeading *heading = weakSelf.locationManager.heading;
86
+ [weakSelf.locationManager stopUpdatingHeading];
87
+
88
+ if (heading) {
89
+ NSDictionary *headingData = @{
90
+ @"magneticHeading": @(heading.magneticHeading),
91
+ @"trueHeading": @(heading.trueHeading),
92
+ @"headingAccuracy": @(heading.headingAccuracy),
93
+ @"timestamp": @([[NSDate date] timeIntervalSince1970] * 1000)
94
+ };
95
+
96
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:headingData];
97
+ [weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId];
98
+ } else {
99
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Failed to get heading"];
100
+ [weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId];
101
+ }
102
+ }
103
+ });
104
+ }];
105
+ }
106
+
107
+ #pragma mark - Watch Readings
108
+
109
+ - (void)watchReadings:(CDVInvokedUrlCommand *)command {
110
+ if (!self.motionManager.magnetometerAvailable) {
111
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Magnetometer not available"];
112
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
113
+ return;
114
+ }
115
+
116
+ // Stop any existing watch
117
+ [self.motionManager stopMagnetometerUpdates];
118
+
119
+ self.watchCallbackId = command.callbackId;
120
+
121
+ NSNumber *frequencyArg = [command.arguments objectAtIndex:0];
122
+ double frequency = frequencyArg ? [frequencyArg doubleValue] : 100;
123
+ self.motionManager.magnetometerUpdateInterval = frequency / 1000.0;
124
+
125
+ __weak CDVMagnetometer *weakSelf = self;
126
+
127
+ [self.motionManager startMagnetometerUpdatesToQueue:[NSOperationQueue mainQueue]
128
+ withHandler:^(CMMagnetometerData *data, NSError *error) {
129
+ if (error) {
130
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error.localizedDescription];
131
+ [result setKeepCallbackAsBool:YES];
132
+ [weakSelf.commandDelegate sendPluginResult:result callbackId:weakSelf.watchCallbackId];
133
+ return;
134
+ }
135
+
136
+ if (data) {
137
+ double x = data.magneticField.x;
138
+ double y = data.magneticField.y;
139
+ double z = data.magneticField.z;
140
+ double magnitude = sqrt(x*x + y*y + z*z);
141
+
142
+ NSDictionary *reading = @{
143
+ @"x": @(x),
144
+ @"y": @(y),
145
+ @"z": @(z),
146
+ @"magnitude": @(magnitude),
147
+ @"timestamp": @([[NSDate date] timeIntervalSince1970] * 1000)
148
+ };
149
+
150
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:reading];
151
+ [result setKeepCallbackAsBool:YES];
152
+ [weakSelf.commandDelegate sendPluginResult:result callbackId:weakSelf.watchCallbackId];
153
+ }
154
+ }];
155
+ }
156
+
157
+ - (void)stopWatch:(CDVInvokedUrlCommand *)command {
158
+ [self.motionManager stopMagnetometerUpdates];
159
+ self.watchCallbackId = nil;
160
+
161
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
162
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
163
+ }
164
+
165
+ #pragma mark - Watch Heading
166
+
167
+ - (void)watchHeading:(CDVInvokedUrlCommand *)command {
168
+ if (![CLLocationManager headingAvailable]) {
169
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Heading not available"];
170
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
171
+ return;
172
+ }
173
+
174
+ self.watchHeadingCallbackId = command.callbackId;
175
+
176
+ NSNumber *filterArg = [command.arguments count] > 1 ? [command.arguments objectAtIndex:1] : nil;
177
+ double filter = filterArg ? [filterArg doubleValue] : 0;
178
+
179
+ if (filter > 0) {
180
+ self.locationManager.headingFilter = filter;
181
+ } else {
182
+ self.locationManager.headingFilter = kCLHeadingFilterNone;
183
+ }
184
+
185
+ dispatch_async(dispatch_get_main_queue(), ^{
186
+ [self.locationManager startUpdatingHeading];
187
+ });
188
+ }
189
+
190
+ - (void)stopWatchHeading:(CDVInvokedUrlCommand *)command {
191
+ dispatch_async(dispatch_get_main_queue(), ^{
192
+ [self.locationManager stopUpdatingHeading];
193
+ });
194
+ self.watchHeadingCallbackId = nil;
195
+
196
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
197
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
198
+ }
199
+
200
+ #pragma mark - CLLocationManagerDelegate
201
+
202
+ - (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
203
+ if (self.watchHeadingCallbackId && newHeading) {
204
+ NSDictionary *headingData = @{
205
+ @"magneticHeading": @(newHeading.magneticHeading),
206
+ @"trueHeading": @(newHeading.trueHeading),
207
+ @"headingAccuracy": @(newHeading.headingAccuracy),
208
+ @"timestamp": @([[NSDate date] timeIntervalSince1970] * 1000)
209
+ };
210
+
211
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:headingData];
212
+ [result setKeepCallbackAsBool:YES];
213
+ [self.commandDelegate sendPluginResult:result callbackId:self.watchHeadingCallbackId];
214
+ }
215
+ }
216
+
217
+ - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager {
218
+ self.calibrationNeeded = YES;
219
+ return YES;
220
+ }
221
+
222
+ #pragma mark - Info Methods
223
+
224
+ - (void)getMagnetometerInfo:(CDVInvokedUrlCommand *)command {
225
+ [self.commandDelegate runInBackground:^{
226
+ BOOL available = self.motionManager.magnetometerAvailable;
227
+
228
+ NSMutableDictionary *info = [NSMutableDictionary dictionary];
229
+ info[@"isAvailable"] = @(available);
230
+ info[@"accuracy"] = @(self.currentAccuracy);
231
+ info[@"calibrationNeeded"] = @(self.calibrationNeeded);
232
+ info[@"platform"] = @"ios";
233
+
234
+ if (available) {
235
+ [self.motionManager startMagnetometerUpdates];
236
+ [NSThread sleepForTimeInterval:0.1];
237
+
238
+ CMMagnetometerData *data = self.motionManager.magnetometerData;
239
+ [self.motionManager stopMagnetometerUpdates];
240
+
241
+ if (data) {
242
+ double x = data.magneticField.x;
243
+ double y = data.magneticField.y;
244
+ double z = data.magneticField.z;
245
+ double magnitude = sqrt(x*x + y*y + z*z);
246
+
247
+ info[@"reading"] = @{
248
+ @"x": @(x),
249
+ @"y": @(y),
250
+ @"z": @(z),
251
+ @"magnitude": @(magnitude),
252
+ @"timestamp": @([[NSDate date] timeIntervalSince1970] * 1000)
253
+ };
254
+ }
255
+ }
256
+
257
+ // Get heading if available
258
+ if ([CLLocationManager headingAvailable]) {
259
+ CLHeading *heading = self.locationManager.heading;
260
+ if (heading) {
261
+ info[@"heading"] = @{
262
+ @"magneticHeading": @(heading.magneticHeading),
263
+ @"trueHeading": @(heading.trueHeading),
264
+ @"headingAccuracy": @(heading.headingAccuracy),
265
+ @"timestamp": @([[NSDate date] timeIntervalSince1970] * 1000)
266
+ };
267
+ }
268
+ }
269
+
270
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:info];
271
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
272
+ }];
273
+ }
274
+
275
+ - (void)getAccuracy:(CDVInvokedUrlCommand *)command {
276
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:self.currentAccuracy];
277
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
278
+ }
279
+
280
+ - (void)isCalibrationNeeded:(CDVInvokedUrlCommand *)command {
281
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:self.calibrationNeeded ? 1 : 0];
282
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
283
+ }
284
+
285
+ - (void)getFieldStrength:(CDVInvokedUrlCommand *)command {
286
+ [self.commandDelegate runInBackground:^{
287
+ if (!self.motionManager.magnetometerAvailable) {
288
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Magnetometer not available"];
289
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
290
+ return;
291
+ }
292
+
293
+ [self.motionManager startMagnetometerUpdates];
294
+ [NSThread sleepForTimeInterval:0.1];
295
+
296
+ CMMagnetometerData *data = self.motionManager.magnetometerData;
297
+ [self.motionManager stopMagnetometerUpdates];
298
+
299
+ if (data) {
300
+ double x = data.magneticField.x;
301
+ double y = data.magneticField.y;
302
+ double z = data.magneticField.z;
303
+ double magnitude = sqrt(x*x + y*y + z*z);
304
+
305
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:magnitude];
306
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
307
+ } else {
308
+ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Failed to get field strength"];
309
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
310
+ }
311
+ }];
312
+ }
313
+
314
+ - (void)onReset {
315
+ [self.motionManager stopMagnetometerUpdates];
316
+ [self.locationManager stopUpdatingHeading];
317
+ self.watchCallbackId = nil;
318
+ self.watchHeadingCallbackId = nil;
319
+ }
320
+
321
+ @end