UNPKG

2.64 kBJavaScriptView Raw
1// @flow
2
3import {
4 NativeEventEmitter,
5 NativeModules,
6 Platform,
7} from 'react-native';
8
9type LocationOptions = {
10 enableHighAccuracy: ?bool,
11 timeInterval: ?number,
12 distanceInterval: ?number,
13}
14
15type LocationData = {
16 coords: {
17 latitude: number,
18 longitude: number,
19 altitude: number,
20 accuracy: number,
21 heading: number,
22 speed: number,
23 },
24 timestamp: number,
25}
26
27type LocationCallback = (data: LocationData) => any;
28
29const LocationEventEmitter = new NativeEventEmitter(NativeModules.ExponentLocation);
30
31let nextWatchId = 0;
32let watchCallbacks: { [watchId: number]: LocationCallback } = {};
33let deviceEventSubscription: ?Function;
34
35export function getCurrentPositionAsync(options: LocationOptions) {
36 // On Android we have a native method for this case.
37 if (Platform.OS === 'android') {
38 return NativeModules.ExponentLocation.getCurrentPositionAsync(options);
39 }
40
41 // On iOS we implement it in terms of `.watchPositionAsync(...)`
42 // TODO: Use separate native method for iOS too?
43 return new Promise(async (resolve, reject) => {
44 try {
45
46 let done = false; // To make sure we only resolve once.
47
48 let subscription;
49 subscription = await watchPositionAsync(options, (location) => {
50 if (!done) {
51 resolve(location);
52 done = true;
53 }
54 if (subscription) {
55 subscription.remove();
56 }
57 });
58
59 // In case the callback is fired before we get here.
60 if (done) {
61 subscription.remove();
62 }
63 } catch (e) {
64 reject(e);
65 }
66 });
67}
68
69export async function watchPositionAsync(options: LocationOptions, callback: LocationCallback) {
70 let { ExponentLocation } = NativeModules;
71
72 if (!deviceEventSubscription) {
73 deviceEventSubscription = LocationEventEmitter.addListener(
74 'Exponent.locationChanged',
75 ({ watchId, location }) => {
76 const callback = watchCallbacks[watchId];
77 if (callback) {
78 callback(location);
79 } else {
80 ExponentLocation.removeWatchAsync(watchId);
81 }
82 },
83 );
84 }
85
86 const watchId = nextWatchId++; // XXX: thread safe?
87 watchCallbacks[watchId] = callback;
88 await ExponentLocation.watchPositionImplAsync(watchId, options);
89
90 let removed = false;
91 return {
92 remove() {
93 if (!removed) {
94 ExponentLocation.removeWatchAsync(watchId);
95 delete watchCallbacks[watchId];
96 if (Object.keys(watchCallbacks).length === 0) {
97 LocationEventEmitter.removeSubscription(deviceEventSubscription);
98 deviceEventSubscription = null;
99 }
100 removed = true;
101 }
102 },
103 };
104}
105