4 | * Copyright (c) 2019 Douglas Nassif Roma Junior
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.github.douglasjunior.reactNativeGetLocation.util;
26 |
27 | import android.location.Criteria;
28 | import android.location.Location;
29 | import android.location.LocationListener;
30 | import android.location.LocationManager;
31 | import android.os.Bundle;
32 | import android.os.Looper;
33 | import android.util.Log;
34 |
35 | import com.facebook.react.bridge.Promise;
36 | import com.facebook.react.bridge.ReadableMap;
37 | import com.facebook.react.bridge.WritableNativeMap;
38 |
39 | import java.util.Timer;
40 | import java.util.TimerTask;
41 |
42 | public class GetLocation {
43 |
44 | private final LocationManager locationManager;
45 |
46 | private Timer timer;
47 | private LocationListener listener;
48 | private Promise promise;
49 |
50 | public GetLocation(LocationManager locationManager) {
51 | this.locationManager = locationManager;
52 | }
53 |
54 | public void get(ReadableMap options, final Promise promise) {
55 | this.promise = promise;
56 | try {
57 | if (!isLocationEnabled()) {
58 | promise.reject("UNAVAILABLE", "Location not available");
59 | return;
60 | }
61 |
62 | boolean enableHighAccuracy = options.hasKey("enableHighAccuracy") && options.getBoolean("enableHighAccuracy");
63 | long timeout = options.hasKey("timeout") ? (long) options.getDouble("timeout") : 0;
64 |
65 | Criteria criteria = new Criteria();
66 | criteria.setAccuracy(enableHighAccuracy ? Criteria.ACCURACY_FINE : Criteria.ACCURACY_COARSE);
67 |
68 | listener = new LocationListener() {
69 | private boolean locationFound = false;
70 |
71 | @Override
72 | public synchronized void onLocationChanged(Location location) {
73 | if (location != null && !locationFound) {
74 | locationFound = true;
75 | WritableNativeMap resultLocation = new WritableNativeMap();
76 | resultLocation.putString("provider", location.getProvider());
77 | resultLocation.putDouble("latitude", location.getLatitude());
78 | resultLocation.putDouble("longitude", location.getLongitude());
79 | resultLocation.putDouble("accuracy", location.getAccuracy());
80 | resultLocation.putDouble("altitude", location.getAltitude());
81 | resultLocation.putDouble("speed", location.getSpeed());
82 | resultLocation.putDouble("bearing", location.getBearing());
83 | resultLocation.putDouble("time", location.getTime());
84 | promise.resolve(resultLocation);
85 | stop();
86 | clearReferences();
87 | }
88 | }
89 |
90 | @Override
91 | public void onStatusChanged(String provider, int status, Bundle extras) {
92 |
93 | }
94 |
95 | @Override
96 | public void onProviderEnabled(String provider) {
97 |
98 | }
99 |
100 | @Override
101 | public void onProviderDisabled(String provider) {
102 |
103 | }
104 | };
105 |
106 | locationManager.requestLocationUpdates(0L, 0F, criteria, listener, Looper.myLooper());
107 |
108 | if (timeout > 0) {
109 | timer = new Timer();
110 | timer.schedule(new TimerTask() {
111 | @Override
112 | public void run() {
113 | try {
114 | promise.reject("TIMEOUT", "Location timed out");
115 | stop();
116 | clearReferences();
117 | } catch (Exception ex) {
118 | ex.printStackTrace();
119 | }
120 | }
121 | }, timeout);
122 | }
123 | } catch (SecurityException ex) {
124 | ex.printStackTrace();
125 | stop();
126 | promise.reject("UNAUTHORIZED", "Location permission denied", ex);
127 | } catch (Exception ex) {
128 | ex.printStackTrace();
129 | stop();
130 | promise.reject("UNAVAILABLE", "Location not available", ex);
131 | }
132 | }
133 |
134 | public synchronized void cancel() {
135 | if (promise == null) {
136 | return;
137 | }
138 | try {
139 | promise.reject("CANCELLED", "Location cancelled by another request");
140 | stop();
141 | clearReferences();
142 | } catch (Exception ex) {
143 | ex.printStackTrace();
144 | }
145 | }
146 |
147 | private void stop() {
148 | if (timer != null) {
149 | timer.cancel();
150 | }
151 | if (listener != null) {
152 | locationManager.removeUpdates(listener);
153 | }
154 | }
155 |
156 | private void clearReferences() {
157 | promise = null;
158 | timer = null;
159 | listener = null;
160 | }
161 |
162 | private boolean isLocationEnabled() {
163 | try {
164 | return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
165 | locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
166 | } catch (Exception ex) {
167 | ex.printStackTrace();
168 | }
169 | return false;
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/android/src/main/java/com/github/douglasjunior/reactNativeGetLocation/util/SettingsUtil.java:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Douglas Nassif Roma Junior
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.github.douglasjunior.reactNativeGetLocation.util;
26 |
27 | import android.content.ComponentName;
28 | import android.content.Context;
29 | import android.content.Intent;
30 | import android.net.Uri;
31 | import android.provider.Settings;
32 |
33 | public final class SettingsUtil {
34 |
35 | private SettingsUtil() {
36 | }
37 |
38 | public static void openWifiSettings(final Context context) {
39 | Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
40 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
41 | context.startActivity(intent);
42 | }
43 |
44 | public static void openCelularSettings(final Context context) {
45 | Intent intent = new Intent(Intent.ACTION_MAIN);
46 | intent.setComponent(new ComponentName("com.android.settings",
47 | "com.android.settings.Settings$DataUsageSummaryActivity"));
48 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
49 | context.startActivity(intent);
50 | }
51 |
52 | public static void openGpsSettings(final Context context) {
53 | final String action = Settings.ACTION_LOCATION_SOURCE_SETTINGS;
54 | Intent intent = new Intent(action);
55 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
56 | context.startActivity(intent);
57 | }
58 |
59 | public static void openAppSettings(final Context context) {
60 | Intent intent = new Intent();
61 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
62 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
63 | Uri uri = Uri.fromParts("package", context.getPackageName(), null);
64 | intent.setData(uri);
65 | context.startActivity(intent);
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/ios/ReactNativeGetLocation.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | A5165E1C2201E22100EE2B48 /* LocationModule.m in Sources */ = {isa = PBXBuildFile; fileRef = A5165E1B2201E22100EE2B48 /* LocationModule.m */; };
11 | A5AF7D071FAA182100C5BDC0 /* SettingsUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = A5AF7D031FAA182000C5BDC0 /* SettingsUtil.m */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXCopyFilesBuildPhase section */
15 | A5AF7CE01FAA17C900C5BDC0 /* CopyFiles */ = {
16 | isa = PBXCopyFilesBuildPhase;
17 | buildActionMask = 2147483647;
18 | dstPath = "include/$(PRODUCT_NAME)";
19 | dstSubfolderSpec = 16;
20 | files = (
21 | );
22 | runOnlyForDeploymentPostprocessing = 0;
23 | };
24 | /* End PBXCopyFilesBuildPhase section */
25 |
26 | /* Begin PBXFileReference section */
27 | A5165E1A2201E22100EE2B48 /* LocationModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocationModule.h; sourceTree = ""; };
28 | A5165E1B2201E22100EE2B48 /* LocationModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocationModule.m; sourceTree = ""; };
29 | A5AF7CE21FAA17C900C5BDC0 /* libReactNativeGetLocationLibrary.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativeGetLocationLibrary.a; sourceTree = BUILT_PRODUCTS_DIR; };
30 | A5AF7D031FAA182000C5BDC0 /* SettingsUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsUtil.m; sourceTree = ""; };
31 | A5AF7D041FAA182100C5BDC0 /* SettingsUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsUtil.h; sourceTree = ""; };
32 | /* End PBXFileReference section */
33 |
34 | /* Begin PBXFrameworksBuildPhase section */
35 | A5AF7CDF1FAA17C900C5BDC0 /* Frameworks */ = {
36 | isa = PBXFrameworksBuildPhase;
37 | buildActionMask = 2147483647;
38 | files = (
39 | );
40 | runOnlyForDeploymentPostprocessing = 0;
41 | };
42 | /* End PBXFrameworksBuildPhase section */
43 |
44 | /* Begin PBXGroup section */
45 | 83CBB9F61A601CBA00E9B192 = {
46 | isa = PBXGroup;
47 | children = (
48 | A5AF7D591FAA2D7B00C5BDC0 /* Resources */,
49 | A5AF7D581FAA2D3800C5BDC0 /* Products */,
50 | A5AF7CE31FAA17C900C5BDC0 /* ReactNativeGetLocationLibrary */,
51 | );
52 | indentWidth = 2;
53 | sourceTree = "";
54 | tabWidth = 2;
55 | usesTabs = 0;
56 | };
57 | A5AF7CE31FAA17C900C5BDC0 /* ReactNativeGetLocationLibrary */ = {
58 | isa = PBXGroup;
59 | children = (
60 | A5AF7D041FAA182100C5BDC0 /* SettingsUtil.h */,
61 | A5AF7D031FAA182000C5BDC0 /* SettingsUtil.m */,
62 | A5165E1A2201E22100EE2B48 /* LocationModule.h */,
63 | A5165E1B2201E22100EE2B48 /* LocationModule.m */,
64 | );
65 | path = ReactNativeGetLocationLibrary;
66 | sourceTree = "";
67 | };
68 | A5AF7D581FAA2D3800C5BDC0 /* Products */ = {
69 | isa = PBXGroup;
70 | children = (
71 | A5AF7CE21FAA17C900C5BDC0 /* libReactNativeGetLocationLibrary.a */,
72 | );
73 | name = Products;
74 | sourceTree = "";
75 | };
76 | A5AF7D591FAA2D7B00C5BDC0 /* Resources */ = {
77 | isa = PBXGroup;
78 | children = (
79 | );
80 | name = Resources;
81 | sourceTree = "";
82 | };
83 | /* End PBXGroup section */
84 |
85 | /* Begin PBXNativeTarget section */
86 | A5AF7CE11FAA17C900C5BDC0 /* ReactNativeGetLocationLibrary */ = {
87 | isa = PBXNativeTarget;
88 | buildConfigurationList = A5AF7CE81FAA17C900C5BDC0 /* Build configuration list for PBXNativeTarget "ReactNativeGetLocationLibrary" */;
89 | buildPhases = (
90 | A5AF7CDE1FAA17C900C5BDC0 /* Sources */,
91 | A5AF7CDF1FAA17C900C5BDC0 /* Frameworks */,
92 | A5AF7CE01FAA17C900C5BDC0 /* CopyFiles */,
93 | );
94 | buildRules = (
95 | );
96 | dependencies = (
97 | );
98 | name = ReactNativeGetLocationLibrary;
99 | productName = ReactNativeGetLocationLibrary;
100 | productReference = A5AF7CE21FAA17C900C5BDC0 /* libReactNativeGetLocationLibrary.a */;
101 | productType = "com.apple.product-type.library.static";
102 | };
103 | /* End PBXNativeTarget section */
104 |
105 | /* Begin PBXProject section */
106 | 83CBB9F71A601CBA00E9B192 /* Project object */ = {
107 | isa = PBXProject;
108 | attributes = {
109 | LastUpgradeCheck = 1310;
110 | ORGANIZATIONNAME = Facebook;
111 | TargetAttributes = {
112 | A5AF7CE11FAA17C900C5BDC0 = {
113 | CreatedOnToolsVersion = 8.3.3;
114 | ProvisioningStyle = Automatic;
115 | };
116 | };
117 | };
118 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeGetLocation" */;
119 | compatibilityVersion = "Xcode 12.0";
120 | developmentRegion = en;
121 | hasScannedForEncodings = 0;
122 | knownRegions = (
123 | en,
124 | Base,
125 | );
126 | mainGroup = 83CBB9F61A601CBA00E9B192;
127 | productRefGroup = 83CBB9F61A601CBA00E9B192;
128 | projectDirPath = "";
129 | projectRoot = "";
130 | targets = (
131 | A5AF7CE11FAA17C900C5BDC0 /* ReactNativeGetLocationLibrary */,
132 | );
133 | };
134 | /* End PBXProject section */
135 |
136 | /* Begin PBXSourcesBuildPhase section */
137 | A5AF7CDE1FAA17C900C5BDC0 /* Sources */ = {
138 | isa = PBXSourcesBuildPhase;
139 | buildActionMask = 2147483647;
140 | files = (
141 | A5165E1C2201E22100EE2B48 /* LocationModule.m in Sources */,
142 | A5AF7D071FAA182100C5BDC0 /* SettingsUtil.m in Sources */,
143 | );
144 | runOnlyForDeploymentPostprocessing = 0;
145 | };
146 | /* End PBXSourcesBuildPhase section */
147 |
148 | /* Begin XCBuildConfiguration section */
149 | 83CBBA201A601CBA00E9B192 /* Debug */ = {
150 | isa = XCBuildConfiguration;
151 | buildSettings = {
152 | ALWAYS_SEARCH_USER_PATHS = NO;
153 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
154 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
155 | CLANG_CXX_LIBRARY = "libc++";
156 | CLANG_ENABLE_MODULES = YES;
157 | CLANG_ENABLE_OBJC_ARC = YES;
158 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
159 | CLANG_WARN_BOOL_CONVERSION = YES;
160 | CLANG_WARN_COMMA = YES;
161 | CLANG_WARN_CONSTANT_CONVERSION = YES;
162 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
163 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
164 | CLANG_WARN_EMPTY_BODY = YES;
165 | CLANG_WARN_ENUM_CONVERSION = YES;
166 | CLANG_WARN_INFINITE_RECURSION = YES;
167 | CLANG_WARN_INT_CONVERSION = YES;
168 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
169 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
170 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
171 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
172 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
173 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
174 | CLANG_WARN_STRICT_PROTOTYPES = YES;
175 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
176 | CLANG_WARN_UNREACHABLE_CODE = YES;
177 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
178 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
179 | COPY_PHASE_STRIP = NO;
180 | ENABLE_STRICT_OBJC_MSGSEND = YES;
181 | ENABLE_TESTABILITY = YES;
182 | GCC_C_LANGUAGE_STANDARD = gnu99;
183 | GCC_DYNAMIC_NO_PIC = NO;
184 | GCC_NO_COMMON_BLOCKS = YES;
185 | GCC_OPTIMIZATION_LEVEL = 0;
186 | GCC_PREPROCESSOR_DEFINITIONS = (
187 | "DEBUG=1",
188 | "$(inherited)",
189 | );
190 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
191 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
192 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
193 | GCC_WARN_UNDECLARED_SELECTOR = YES;
194 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
195 | GCC_WARN_UNUSED_FUNCTION = YES;
196 | GCC_WARN_UNUSED_VARIABLE = YES;
197 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
198 | MTL_ENABLE_DEBUG_INFO = YES;
199 | ONLY_ACTIVE_ARCH = YES;
200 | SDKROOT = iphoneos;
201 | };
202 | name = Debug;
203 | };
204 | 83CBBA211A601CBA00E9B192 /* Release */ = {
205 | isa = XCBuildConfiguration;
206 | buildSettings = {
207 | ALWAYS_SEARCH_USER_PATHS = NO;
208 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
209 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
210 | CLANG_CXX_LIBRARY = "libc++";
211 | CLANG_ENABLE_MODULES = YES;
212 | CLANG_ENABLE_OBJC_ARC = YES;
213 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
214 | CLANG_WARN_BOOL_CONVERSION = YES;
215 | CLANG_WARN_COMMA = YES;
216 | CLANG_WARN_CONSTANT_CONVERSION = YES;
217 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
218 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
219 | CLANG_WARN_EMPTY_BODY = YES;
220 | CLANG_WARN_ENUM_CONVERSION = YES;
221 | CLANG_WARN_INFINITE_RECURSION = YES;
222 | CLANG_WARN_INT_CONVERSION = YES;
223 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
224 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
225 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
226 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
227 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
228 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
229 | CLANG_WARN_STRICT_PROTOTYPES = YES;
230 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
231 | CLANG_WARN_UNREACHABLE_CODE = YES;
232 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
233 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
234 | COPY_PHASE_STRIP = YES;
235 | ENABLE_NS_ASSERTIONS = NO;
236 | ENABLE_STRICT_OBJC_MSGSEND = YES;
237 | GCC_C_LANGUAGE_STANDARD = gnu99;
238 | GCC_NO_COMMON_BLOCKS = YES;
239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
241 | GCC_WARN_UNDECLARED_SELECTOR = YES;
242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
243 | GCC_WARN_UNUSED_FUNCTION = YES;
244 | GCC_WARN_UNUSED_VARIABLE = YES;
245 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
246 | MTL_ENABLE_DEBUG_INFO = NO;
247 | SDKROOT = iphoneos;
248 | VALIDATE_PRODUCT = YES;
249 | };
250 | name = Release;
251 | };
252 | A5AF7CE91FAA17C900C5BDC0 /* Debug */ = {
253 | isa = XCBuildConfiguration;
254 | buildSettings = {
255 | CLANG_ANALYZER_NONNULL = YES;
256 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
257 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
258 | CLANG_WARN_INFINITE_RECURSION = YES;
259 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
260 | DEBUG_INFORMATION_FORMAT = dwarf;
261 | ENABLE_TESTABILITY = YES;
262 | FRAMEWORK_SEARCH_PATHS = (
263 | "$(inherited)",
264 | "$(PROJECT_DIR)",
265 | "$(PROJECT_DIR)/Frameworks",
266 | );
267 | GCC_NO_COMMON_BLOCKS = YES;
268 | HEADER_SEARCH_PATHS = "$(inherited)";
269 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
270 | LIBRARY_SEARCH_PATHS = "";
271 | OTHER_LDFLAGS = "-ObjC";
272 | PRODUCT_NAME = "$(TARGET_NAME)";
273 | SKIP_INSTALL = YES;
274 | };
275 | name = Debug;
276 | };
277 | A5AF7CEA1FAA17C900C5BDC0 /* Release */ = {
278 | isa = XCBuildConfiguration;
279 | buildSettings = {
280 | CLANG_ANALYZER_NONNULL = YES;
281 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
282 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
283 | CLANG_WARN_INFINITE_RECURSION = YES;
284 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
285 | COPY_PHASE_STRIP = NO;
286 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
287 | FRAMEWORK_SEARCH_PATHS = (
288 | "$(inherited)",
289 | "$(PROJECT_DIR)",
290 | "$(PROJECT_DIR)/Frameworks",
291 | );
292 | GCC_NO_COMMON_BLOCKS = YES;
293 | HEADER_SEARCH_PATHS = "$(inherited)";
294 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
295 | LIBRARY_SEARCH_PATHS = "";
296 | OTHER_LDFLAGS = "-ObjC";
297 | PRODUCT_NAME = "$(TARGET_NAME)";
298 | SKIP_INSTALL = YES;
299 | };
300 | name = Release;
301 | };
302 | /* End XCBuildConfiguration section */
303 |
304 | /* Begin XCConfigurationList section */
305 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeGetLocation" */ = {
306 | isa = XCConfigurationList;
307 | buildConfigurations = (
308 | 83CBBA201A601CBA00E9B192 /* Debug */,
309 | 83CBBA211A601CBA00E9B192 /* Release */,
310 | );
311 | defaultConfigurationIsVisible = 0;
312 | defaultConfigurationName = Release;
313 | };
314 | A5AF7CE81FAA17C900C5BDC0 /* Build configuration list for PBXNativeTarget "ReactNativeGetLocationLibrary" */ = {
315 | isa = XCConfigurationList;
316 | buildConfigurations = (
317 | A5AF7CE91FAA17C900C5BDC0 /* Debug */,
318 | A5AF7CEA1FAA17C900C5BDC0 /* Release */,
319 | );
320 | defaultConfigurationIsVisible = 0;
321 | defaultConfigurationName = Release;
322 | };
323 | /* End XCConfigurationList section */
324 | };
325 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
326 | }
327 |
--------------------------------------------------------------------------------
/ios/ReactNativeGetLocation.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/ReactNativeGetLocation.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/ReactNativeGetLocationLibrary/LocationModule.h:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2019 Douglas Nassif Roma Junior
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in
13 | // all copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | // THE SOFTWARE.
22 |
23 | #import
24 | #import
25 | #import
26 | #import "SettingsUtil.h"
27 |
28 | @interface LocationModule : NSObject
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/ios/ReactNativeGetLocationLibrary/LocationModule.m:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2019 Douglas Nassif Roma Junior
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in
13 | // all copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | // THE SOFTWARE.
22 |
23 | #import "LocationModule.h"
24 | #import
25 |
26 | @implementation LocationModule
27 |
28 | RCT_EXPORT_MODULE(ReactNativeGetLocation);
29 |
30 | NSTimer* mTimer;
31 | CLLocationManager* mLocationManager;
32 | RCTPromiseResolveBlock mResolve;
33 | RCTPromiseRejectBlock mReject;
34 | double mTimeout;
35 |
36 | RCT_EXPORT_METHOD(getCurrentPosition: (NSDictionary*) options
37 | promise: (RCTPromiseResolveBlock) resolve
38 | rejecter: (RCTPromiseRejectBlock) reject) {
39 | dispatch_async(dispatch_get_main_queue(), ^{
40 | @try {
41 | [self cancelPreviousRequest];
42 |
43 | if (@available(iOS 14.0, *)) {
44 | // should use locationManagerDidChangeAuthorization
45 | } else {
46 | if (![CLLocationManager locationServicesEnabled]) {
47 | [[NSException
48 | exceptionWithName:@"Unavailable"
49 | reason:@"Location service is unavailable"
50 | userInfo:nil]
51 | raise];
52 | }
53 | }
54 |
55 | bool enableHighAccuracy = [RCTConvert BOOL:options[@"enableHighAccuracy"]];
56 | double timeout = [RCTConvert double:options[@"timeout"]];
57 |
58 | CLLocationManager *locationManager = [[CLLocationManager alloc] init];
59 | locationManager.delegate = self;
60 | locationManager.distanceFilter = kCLDistanceFilterNone;
61 | locationManager.desiredAccuracy = enableHighAccuracy ? kCLLocationAccuracyBest : kCLLocationAccuracyNearestTenMeters;
62 |
63 | mResolve = resolve;
64 | mReject = reject;
65 | mLocationManager = locationManager;
66 | mTimeout = timeout;
67 |
68 | [self startUpdatingLocation];
69 | }
70 | @catch (NSException *exception) {
71 | NSMutableDictionary * info = [NSMutableDictionary dictionary];
72 | [info setValue:exception.name forKey:@"ExceptionName"];
73 | [info setValue:exception.reason forKey:@"ExceptionReason"];
74 | [info setValue:exception.callStackReturnAddresses forKey:@"ExceptionCallStackReturnAddresses"];
75 | [info setValue:exception.callStackSymbols forKey:@"ExceptionCallStackSymbols"];
76 | [info setValue:exception.userInfo forKey:@"ExceptionUserInfo"];
77 |
78 | NSError *error = [[NSError alloc] initWithDomain:@"Location not available." code:1 userInfo:info];
79 | reject(@"UNAVAILABLE", @"Location not available", error);
80 | }
81 | });
82 | }
83 |
84 | RCT_EXPORT_METHOD(openAppSettings: (RCTPromiseResolveBlock)resolve
85 | rejecter:(RCTPromiseRejectBlock)reject) {
86 | dispatch_async(dispatch_get_main_queue(), ^{
87 | @try {
88 | [SettingsUtil openAppSettings];
89 | resolve(nil);
90 | }
91 | @catch (NSException *exception) {
92 | NSMutableDictionary * info = [NSMutableDictionary dictionary];
93 | [info setValue:exception.name forKey:@"ExceptionName"];
94 | [info setValue:exception.reason forKey:@"ExceptionReason"];
95 | [info setValue:exception.callStackReturnAddresses forKey:@"ExceptionCallStackReturnAddresses"];
96 | [info setValue:exception.callStackSymbols forKey:@"ExceptionCallStackSymbols"];
97 | [info setValue:exception.userInfo forKey:@"ExceptionUserInfo"];
98 |
99 | NSError *error = [[NSError alloc] initWithDomain:@"openAppSettings" code:0 userInfo:info];
100 | reject(@"openAppSettings", @"Could not open settings.", error);
101 | }
102 | });
103 | }
104 |
105 | - (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
106 | if (locations.count > 0 && mResolve != nil) {
107 | CLLocation* location = locations[0];
108 |
109 | NSDictionary* locationResult = @{
110 | @"latitude": @(location.coordinate.latitude),
111 | @"longitude": @(location.coordinate.longitude),
112 | @"altitude": @(location.altitude),
113 | @"speed": @(location.speed),
114 | @"accuracy": @(location.horizontalAccuracy),
115 | @"time": @(location.timestamp.timeIntervalSince1970 * 1000),
116 | @"verticalAccuracy": @(location.verticalAccuracy),
117 | @"course": @(location.course),
118 | };
119 |
120 | mResolve(locationResult);
121 | }
122 | [self clearReferences];
123 | }
124 |
125 | - (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
126 | if (mReject != nil) {
127 | mReject(@"UNAVAILABLE", @"Location not available", error);
128 | }
129 | [self clearReferences];
130 | }
131 |
132 | - (void) runTimeout:(id)sender {
133 | if (mReject != nil) {
134 | mReject(@"TIMEOUT", @"Location timed out", nil);
135 | }
136 | [self clearReferences];
137 | }
138 |
139 | - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
140 | if ([self isAuthorized]) {
141 | [self startUpdatingLocation];
142 | } else if ([self isAuthorizationDenied]) {
143 | mReject(@"UNAUTHORIZED", @"Authorization denied", nil);
144 | [self clearReferences];
145 | }
146 | }
147 |
148 | - (void) clearReferences {
149 | if (mTimer != nil) {
150 | [mTimer invalidate];
151 | }
152 | if (mLocationManager != nil) {
153 | [mLocationManager stopUpdatingLocation];
154 | }
155 | mResolve = nil;
156 | mReject = nil;
157 | mLocationManager = nil;
158 | mTimer = nil;
159 | mTimeout = 0;
160 | }
161 |
162 | - (void) cancelPreviousRequest {
163 | if (mLocationManager != nil) {
164 | mReject(@"CANCELLED", @"Location cancelled by another request", nil);
165 | }
166 | [self clearReferences];
167 | }
168 |
169 | - (void) startUpdatingLocation {
170 | if (![self isAuthorized]) {
171 | NSLog(@"[locationManager requestWhenInUseAuthorization]");
172 | [mLocationManager requestWhenInUseAuthorization];
173 | return;
174 | }
175 |
176 | NSLog(@"[locationManager startUpdatingLocation]");
177 | [mLocationManager startUpdatingLocation];
178 |
179 | if (mTimeout > 0) {
180 | NSTimeInterval timeoutInterval = mTimeout / 1000.0;
181 | mTimer = [NSTimer scheduledTimerWithTimeInterval:timeoutInterval
182 | target:self
183 | selector:@selector(runTimeout:)
184 | userInfo:nil
185 | repeats:NO];
186 | }
187 | }
188 |
189 | - (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {
190 | if (@available(iOS 14.0, *)) {
191 | if (![CLLocationManager locationServicesEnabled]) {
192 | mReject(@"UNAVAILABLE", @"Location not available", nil);
193 | [self clearReferences];
194 | return;
195 | }
196 |
197 | switch ([manager authorizationStatus]) {
198 | case kCLAuthorizationStatusAuthorizedAlways:
199 | case kCLAuthorizationStatusAuthorizedWhenInUse: {
200 | [self startUpdatingLocation];
201 | break;
202 | }
203 | case kCLAuthorizationStatusNotDetermined: {
204 | // do nothing
205 | break;
206 | }
207 | case kCLAuthorizationStatusDenied:
208 | case kCLAuthorizationStatusRestricted:
209 | default: {
210 | mReject(@"UNAUTHORIZED", @"Authorization denied", nil);
211 | [self clearReferences];
212 | break;
213 | }
214 | }
215 | }
216 | }
217 |
218 | - (BOOL) isAuthorizationDenied {
219 | int authorizationStatus = [CLLocationManager authorizationStatus];
220 |
221 | return authorizationStatus == kCLAuthorizationStatusDenied;
222 | }
223 |
224 | - (BOOL) isAuthorized {
225 | int authorizationStatus = [CLLocationManager authorizationStatus];
226 |
227 | return authorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse
228 | || authorizationStatus == kCLAuthorizationStatusAuthorizedAlways;
229 | }
230 |
231 | @end
232 |
--------------------------------------------------------------------------------
/ios/ReactNativeGetLocationLibrary/SettingsUtil.h:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2019 Douglas Nassif Roma Junior
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in
13 | // all copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | // THE SOFTWARE.
22 |
23 | #import
24 | #import
25 |
26 | @interface SettingsUtil : NSObject
27 |
28 | + (void) openAppSettings;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/ios/ReactNativeGetLocationLibrary/SettingsUtil.m:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2019 Douglas Nassif Roma Junior
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in
13 | // all copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | // THE SOFTWARE.
22 |
23 | #import "SettingsUtil.h"
24 |
25 | @implementation SettingsUtil
26 |
27 | + (void) openAppSettings {
28 | if ([[[UIDevice currentDevice] systemVersion] floatValue] < 10.0) {
29 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
30 | } else {
31 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
32 | }
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-get-location",
3 | "displayName": "React-Native Get Location",
4 | "version": "5.0.0",
5 | "description": "⚛ Simple to use React Native library to get device location for Android and iOS.",
6 | "main": "src",
7 | "license": "MIT",
8 | "private": false,
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/douglasjunior/react-native-get-location.git"
12 | },
13 | "keywords": [
14 | "react-native",
15 | "android",
16 | "ios",
17 | "geolocation",
18 | "location",
19 | "gps"
20 | ],
21 | "author": {
22 | "name": "Douglas Nassif Roma Junior",
23 | "email": "nassifrroma@gmail.com",
24 | "url": "http://douglasjunior.me"
25 | },
26 | "bugs": {
27 | "url": "https://github.com/douglasjunior/react-native-get-location/issues"
28 | },
29 | "homepage": "https://github.com/douglasjunior/react-native-get-location",
30 | "scripts": {
31 | "build": "tsc",
32 | "publish-script": "node scripts/publish.js"
33 | },
34 | "peerDependencies": {
35 | "react-native": ">=0.60"
36 | },
37 | "devDependencies": {
38 | "@babel/core": "^7.20.0",
39 | "@babel/preset-env": "^7.20.0",
40 | "@babel/runtime": "^7.20.0",
41 | "@react-native-community/eslint-config": "^3.2.0",
42 | "@tsconfig/react-native": "^2.0.2",
43 | "@types/jest": "^29.2.1",
44 | "@types/react": "^18.0.24",
45 | "@types/react-test-renderer": "^18.0.0",
46 | "babel-jest": "^29.2.1",
47 | "eslint": "^8.19.0",
48 | "jest": "^29.2.1",
49 | "metro-react-native-babel-preset": "0.73.8",
50 | "prettier": "^2.4.1",
51 | "react": "18.2.0",
52 | "react-native": "0.71.4",
53 | "react-test-renderer": "18.2.0",
54 | "typescript": "4.8.4"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/scripts/publish.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs');
3 | const child_process = require('child_process');
4 |
5 | const packageJson = require('../package.json');
6 |
7 | packageJson.main = 'dist';
8 | packageJson.types = 'dist';
9 |
10 | const packageJsonPath = path.resolve(__dirname, '..', 'package.json');
11 |
12 | const content = JSON.stringify(packageJson, null, 2) + '\n';
13 |
14 | child_process.execSync('npm run build');
15 |
16 | fs.writeFileSync(packageJsonPath, content, {
17 | encoding: 'utf-8',
18 | });
19 |
20 | try {
21 | child_process.execSync('npm publish');
22 | } catch (err) {
23 | console.error(err);
24 | }
25 |
26 | child_process.execSync('git checkout -- "' + packageJsonPath + '"');
27 |
--------------------------------------------------------------------------------
/src/LocationError.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Douglas Nassif Roma Junior
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | export type LocationErrorCode =
26 | | 'CANCELLED'
27 | | 'UNAVAILABLE'
28 | | 'TIMEOUT'
29 | | 'UNAUTHORIZED';
30 |
31 | export default class LocationError extends Error {
32 | code: LocationErrorCode;
33 |
34 | constructor(code: LocationErrorCode, message: string) {
35 | super(message);
36 | this.code = code;
37 | }
38 | }
39 |
40 | export const isLocationError = (error: unknown): error is LocationError => {
41 | return Boolean(
42 | typeof error === 'object' && error && 'code' in error && 'message' in error,
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Douglas Nassif Roma Junior
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import {Linking, NativeModules, Platform} from 'react-native';
26 |
27 | import {
28 | GetCurrentPositionOptions,
29 | Location,
30 | requestAndroidPermission,
31 | } from './utils';
32 | import LocationError, {isLocationError} from './LocationError';
33 |
34 | export {default as LocationError, isLocationError} from './LocationError';
35 | export type {LocationErrorCode} from './LocationError';
36 | export type {GetCurrentPositionOptions, Location} from './utils';
37 |
38 | const {OS} = Platform;
39 | const {ReactNativeGetLocation} = NativeModules;
40 |
41 | const DEFAULT_OPTIONS: GetCurrentPositionOptions = {
42 | enableHighAccuracy: false,
43 | timeout: 60000,
44 | };
45 |
46 | const GetLocation = {
47 | async getCurrentPosition(
48 | options: GetCurrentPositionOptions = DEFAULT_OPTIONS,
49 | ): Promise {
50 | const opts = {...DEFAULT_OPTIONS, ...options};
51 | if (OS === 'android') {
52 | await requestAndroidPermission(opts.enableHighAccuracy, opts.rationale);
53 | }
54 |
55 | try {
56 | return ReactNativeGetLocation.getCurrentPosition(opts);
57 | } catch (error) {
58 | if (isLocationError(error)) {
59 | throw new LocationError(error.code, error.message);
60 | }
61 | throw error;
62 | }
63 | },
64 |
65 | openSettings() {
66 | return Linking.openSettings();
67 | },
68 | };
69 |
70 | export default GetLocation;
71 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Douglas Nassif Roma Junior
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import { PermissionsAndroid, Rationale } from 'react-native';
26 |
27 | import LocationError from './LocationError';
28 |
29 | const { PERMISSIONS, RESULTS } = PermissionsAndroid;
30 |
31 | export type Location = {
32 | /**
33 | * The latitude, in degrees
34 | */
35 | latitude: number;
36 | /**
37 | * The longitude, in degrees
38 | */
39 | longitude: number;
40 | /**
41 | * The altitude if available, in meters above the WGS 84 reference ellipsoid
42 | */
43 | altitude: number;
44 | /**
45 | * The estimated horizontal accuracy of this location, radial, in meters
46 | */
47 | accuracy: number;
48 | /**
49 | * The speed if it is available, in meters/second over ground
50 | */
51 | speed: any;
52 | /**
53 | * The UTC time of this fix, in milliseconds since January 1, 1970.
54 | */
55 | time: number;
56 | /**
57 | * (Android only) The bearing, in degrees
58 | */
59 | bearing?: number;
60 | /**
61 | * (Android only) The name of the provider that generated this fix
62 | */
63 | provider?: number;
64 | /**
65 | * (iOS only) The vertical accuracy of the location. Negative if the altitude is invalid
66 | */
67 | verticalAccuracy?: number;
68 | /**
69 | * (iOS only) The course of the location in degrees true North. Negative if course is invalid. (0.0 - 359.9 degrees, 0 being true North)
70 | */
71 | course?: number;
72 | };
73 |
74 | export type GetCurrentPositionOptions = {
75 | /**
76 | * Set `true` to use 'fine location' (GPS) our `false` to use 'course location' (Wifi, Bluetooth, 3G).
77 | *
78 | * Default: false
79 | */
80 | enableHighAccuracy: boolean;
81 | /**
82 | * The max time (in milliseconds) that you want to wait to receive a location.
83 | *
84 | * Default: 60000 (60 seconds)
85 | */
86 | timeout: number;
87 | /**
88 | * Android only
89 | * See the [React Native docs](https://reactnative.dev/docs/permissionsandroid#request)
90 | */
91 | rationale?: Rationale;
92 | };
93 |
94 | export async function requestAndroidPermission(
95 | enableHighAccuracy: boolean = false,
96 | rationale?: Rationale,
97 | ) {
98 | const permission = enableHighAccuracy
99 | ? PERMISSIONS.ACCESS_FINE_LOCATION
100 | : PERMISSIONS.ACCESS_COARSE_LOCATION
101 |
102 | const alreadyGranted = await PermissionsAndroid.check(permission);
103 |
104 | if (alreadyGranted) return true;
105 |
106 | const granted = await PermissionsAndroid.request(permission, rationale);
107 |
108 | if (granted !== RESULTS.GRANTED) {
109 | throw new LocationError('UNAUTHORIZED', 'Authorization denied');
110 | }
111 |
112 | return true;
113 | }
114 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@tsconfig/react-native/tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "noEmit": false,
6 | "declaration": true,
7 | "jsx": "react",
8 | "sourceMap": true,
9 | "removeComments": false
10 | },
11 | "include": ["src"],
12 | "exclude": ["node_modules", "**/__tests__/*"]
13 | }
14 |
--------------------------------------------------------------------------------