├── .gitignore ├── LICENSE ├── README.md ├── RNLocation.h ├── RNLocation.js ├── RNLocation.m ├── RNLocation.xcodeproj └── project.pbxproj ├── build.gradle ├── index.js ├── package.json └── src └── main ├── AndroidManifest.xml └── java └── com └── syarul └── rnlocation ├── RNLocation.java └── RNLocationModule.java /.gitignore: -------------------------------------------------------------------------------- 1 | ### SublimeText ### 2 | *.sublime-workspace 3 | 4 | ### OSX ### 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | Icon 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear on external disk 14 | .Spotlight-V100 15 | .Trashes 16 | 17 | ### Windows ### 18 | # Windows image file caches 19 | Thumbs.db 20 | ehthumbs.db 21 | 22 | # Folder config file 23 | Desktop.ini 24 | 25 | # Recycle Bin used on file shares 26 | $RECYCLE.BIN/ 27 | 28 | # Webstorm 29 | .idea 30 | 31 | # App specific 32 | 33 | npm-debug.log 34 | node_modules/ 35 | .tmp 36 | old 37 | 38 | # Binaries 39 | *.ipa 40 | *.zip 41 | 42 | # Xcode 43 | build/ 44 | *.pbxuser 45 | !default.pbxuser 46 | *.mode1v3 47 | !default.mode1v3 48 | *.mode2v3 49 | !default.mode2v3 50 | *.perspectivev3 51 | !default.perspectivev3 52 | *.xcworkspace 53 | !default.xcworkspace 54 | xcuserdata 55 | profile 56 | *.moved-aside 57 | DerivedData 58 | 59 | .idea/ 60 | 61 | # Pods - for those of you who use CocoaPods 62 | Pods 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Antonio Grass 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 all 13 | 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 THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-gps 2 | 3 | Native GPS location support for React Native for Android and IOS. This module was inspired in project of [timfpark](https://github.com/timfpark/react-native-location) and [syarul](https://github.com/syarul/react-native-android-location). For the moment is not compatible for a PR back to one of that repositories because some methods are not implemented yet and some structure changed. Only a few methods are implemented so if you want to contribute, any contribution of new missing methods will be appreciated. 4 | 5 | ## Installation 6 | #### Install the npm package 7 | ```bash 8 | npm i --save https://github.com/agrass/react-native-gps 9 | ``` 10 | ## IOS 11 | You then need to add the Objective C part to your XCode project. Drag `RNLocation.xcodeproj` from the `node_modules/react-native-location` folder into your XCode project. Click on the your project in XCode, goto Build Phases then Link Binary With Libraries and add `libRNLocation.a` and `CoreLocation.framework`. 12 | 13 | NOTE: Make sure you don't have the `RNLocation` project open separately in XCode otherwise it won't work. 14 | 15 | ### Android 16 | 17 | * In `android/settings.gradle` 18 | 19 | ```gradle 20 | ... 21 | include ':RNLocation' 22 | project(':RNLocation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gps') 23 | ``` 24 | 25 | * In `android/app/build.gradle` 26 | 27 | ```gradle 28 | ... 29 | dependencies { 30 | ... 31 | compile project(':RNLocation') 32 | } 33 | ``` 34 | 35 | * register module (in MainActivity.java) 36 | 37 | ```java 38 | import com.syarul.rnlocation.RNLocation; // <--- import 39 | 40 | public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { 41 | ...... 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | mReactRootView = new ReactRootView(this); 47 | 48 | mReactInstanceManager = ReactInstanceManager.builder() 49 | .setApplication(getApplication()) 50 | .setBundleAssetName("index.android.bundle") 51 | .setJSMainModuleName("index.android") 52 | .addPackage(new MainReactPackage()) 53 | .addPackage(new RNLocation()) // <-- Register package here 54 | .setUseDeveloperSupport(BuildConfig.DEBUG) 55 | .setInitialLifecycleState(LifecycleState.RESUMED) 56 | .build(); 57 | 58 | mReactRootView.startReactApplication(mReactInstanceManager, "example", null); 59 | 60 | setContentView(mReactRootView); 61 | } 62 | 63 | ...... 64 | 65 | } 66 | ``` 67 | 68 | #### Add permissions to your Project 69 | 70 | Add this to your AndroidManifest file; 71 | 72 | ``` xml 73 | // file: android/app/src/main/AndroidManifest.xml 74 | 75 | 76 | ``` 77 | 78 | ## Location Usage 79 | ```javascript 80 | var React = require('react-native'); 81 | var { DeviceEventEmitter } = React; 82 | 83 | var { RNLocation: Location } = require('NativeModules'); 84 | 85 | Location.startUpdatingLocation(); 86 | 87 | var subscription = DeviceEventEmitter.addListener( 88 | 'locationUpdated', 89 | (location) => { 90 | /* Example location returned 91 | { 92 | speed: -1, 93 | longitude: -0.1337, 94 | latitude: 51.50998, 95 | accuracy: 5, 96 | heading: -1, 97 | altitude: 0, 98 | altitudeAccuracy: -1 99 | } 100 | */ 101 | } 102 | ); 103 | ``` 104 | 105 | 106 | ## Methods 107 | 108 | To access the methods, you need import the `react-native-location` module. 109 | 110 | ### Location.requestWhenInUseAuthorization 111 | ```javascript 112 | Location.requestWhenInUseAuthorization(); 113 | ``` 114 | 115 | This method should be called before anything else. It requests location updates while the application is open. If the application is in the background, you will not get location updates (for the moment, background work not implemented yet). 116 | 117 | ### Location.startUpdatingLocation 118 | ```javascript 119 | Location.startUpdatingLocation(); 120 | var subscription = DeviceEventEmitter.addListener( 121 | 'locationUpdated', 122 | (location) => { 123 | // do something with the location 124 | } 125 | ); 126 | ``` 127 | 128 | ### Location.stopUpdatingLocation 129 | ```javascript 130 | Location.stopUpdatingLocation(); 131 | ``` 132 | ## License 133 | MIT, for more information see `LICENSE` 134 | -------------------------------------------------------------------------------- /RNLocation.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RNLocation : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /RNLocation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Stub of RNLocation for Android. 3 | * 4 | * @providesModule RNLocation 5 | * @flow 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var { NativeModules } = require('react-native'); 11 | module.exports = NativeModules.RNLocation; 12 | -------------------------------------------------------------------------------- /RNLocation.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | #import 5 | #import 6 | 7 | #import "RNLocation.h" 8 | 9 | @interface RNLocation() 10 | 11 | @property (strong, nonatomic) CLLocationManager *locationManager; 12 | 13 | @end 14 | 15 | @implementation RNLocation 16 | 17 | RCT_EXPORT_MODULE() 18 | 19 | @synthesize bridge = _bridge; 20 | 21 | #pragma mark Initialization 22 | 23 | - (instancetype)init 24 | { 25 | if (self = [super init]) { 26 | self.locationManager = [[CLLocationManager alloc] init]; 27 | 28 | self.locationManager.delegate = self; 29 | 30 | self.locationManager.distanceFilter = kCLDistanceFilterNone; 31 | self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; 32 | 33 | self.locationManager.pausesLocationUpdatesAutomatically = NO; 34 | } 35 | 36 | return self; 37 | } 38 | 39 | #pragma mark 40 | 41 | RCT_EXPORT_METHOD(requestAlwaysAuthorization) 42 | { 43 | NSLog(@"react-native-location: requestAlwaysAuthorization"); 44 | [self.locationManager requestAlwaysAuthorization]; 45 | } 46 | 47 | RCT_EXPORT_METHOD(requestWhenInUseAuthorization) 48 | { 49 | NSLog(@"react-native-location: requestWhenInUseAuthorization"); 50 | [self.locationManager requestWhenInUseAuthorization]; 51 | } 52 | 53 | RCT_EXPORT_METHOD(getAuthorizationStatus:(RCTResponseSenderBlock)callback) 54 | { 55 | callback(@[[self nameForAuthorizationStatus:[CLLocationManager authorizationStatus]]]); 56 | } 57 | 58 | RCT_EXPORT_METHOD(setDesiredAccuracy:(double) accuracy) 59 | { 60 | self.locationManager.desiredAccuracy = accuracy; 61 | } 62 | 63 | RCT_EXPORT_METHOD(setDistanceFilter:(double) distance) 64 | { 65 | self.locationManager.distanceFilter = distance; 66 | } 67 | 68 | RCT_EXPORT_METHOD(setAllowsBackgroundLocationUpdates:(BOOL) enabled) 69 | { 70 | self.locationManager.allowsBackgroundLocationUpdates = enabled; 71 | } 72 | 73 | RCT_EXPORT_METHOD(startMonitoringSignificantLocationChanges) 74 | { 75 | NSLog(@"react-native-location: startMonitoringSignificantLocationChanges"); 76 | [self.locationManager startMonitoringSignificantLocationChanges]; 77 | } 78 | 79 | RCT_EXPORT_METHOD(startUpdatingLocation) 80 | { 81 | [self.locationManager startUpdatingLocation]; 82 | } 83 | 84 | RCT_EXPORT_METHOD(startUpdatingHeading) 85 | { 86 | [self.locationManager startUpdatingHeading]; 87 | } 88 | 89 | RCT_EXPORT_METHOD(stopMonitoringSignificantLocationChanges) 90 | { 91 | [self.locationManager stopMonitoringSignificantLocationChanges]; 92 | } 93 | 94 | RCT_EXPORT_METHOD(stopUpdatingLocation) 95 | { 96 | [self.locationManager stopUpdatingLocation]; 97 | } 98 | 99 | RCT_EXPORT_METHOD(stopUpdatingHeading) 100 | { 101 | [self.locationManager stopUpdatingHeading]; 102 | } 103 | 104 | -(NSString *)nameForAuthorizationStatus:(CLAuthorizationStatus)authorizationStatus 105 | { 106 | switch (authorizationStatus) { 107 | case kCLAuthorizationStatusAuthorizedAlways: 108 | NSLog(@"Authorization Status: authorizedAlways"); 109 | return @"authorizedAlways"; 110 | 111 | case kCLAuthorizationStatusAuthorizedWhenInUse: 112 | NSLog(@"Authorization Status: authorizedWhenInUse"); 113 | return @"authorizedWhenInUse"; 114 | 115 | case kCLAuthorizationStatusDenied: 116 | NSLog(@"Authorization Status: denied"); 117 | return @"denied"; 118 | 119 | case kCLAuthorizationStatusNotDetermined: 120 | NSLog(@"Authorization Status: notDetermined"); 121 | return @"notDetermined"; 122 | 123 | case kCLAuthorizationStatusRestricted: 124 | NSLog(@"Authorization Status: restricted"); 125 | return @"restricted"; 126 | } 127 | } 128 | 129 | -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status 130 | { 131 | NSString *statusName = [self nameForAuthorizationStatus:status]; 132 | [self.bridge.eventDispatcher sendDeviceEventWithName:@"authorizationStatusDidChange" body:statusName]; 133 | } 134 | 135 | - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { 136 | NSLog(@"Location manager failed: %@", error); 137 | } 138 | 139 | - (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { 140 | if (newHeading.headingAccuracy < 0) 141 | return; 142 | 143 | // Use the true heading if it is valid. 144 | CLLocationDirection heading = ((newHeading.trueHeading > 0) ? 145 | newHeading.trueHeading : newHeading.magneticHeading); 146 | 147 | NSDictionary *headingEvent = @{ 148 | @"heading": @(heading) 149 | }; 150 | 151 | NSLog(@"heading: %f", heading); 152 | [self.bridge.eventDispatcher sendDeviceEventWithName:@"headingUpdated" body:headingEvent]; 153 | } 154 | 155 | - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { 156 | CLLocation *location = [locations lastObject]; 157 | NSDictionary *locationEvent = @{ 158 | @"latitude": @(location.coordinate.latitude), 159 | @"longitude": @(location.coordinate.longitude), 160 | @"altitude": @(location.altitude), 161 | @"accuracy": @(location.horizontalAccuracy), 162 | @"altitudeAccuracy": @(location.verticalAccuracy), 163 | @"course": @(location.course), 164 | @"speed": @(location.speed), 165 | @"timestamp": @([location.timestamp timeIntervalSince1970] * 1000) // in ms 166 | }; 167 | 168 | NSLog(@"%@: lat: %f, long: %f, altitude: %f", location.timestamp, location.coordinate.latitude, location.coordinate.longitude, location.altitude); 169 | [self.bridge.eventDispatcher sendDeviceEventWithName:@"locationUpdated" body:locationEvent]; 170 | } 171 | @end 172 | -------------------------------------------------------------------------------- /RNLocation.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 13BE3DEE1AC21097009241FE /* RNLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* RNLocation.m */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 58B511D91A9E6C8500147676 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = "include/$(PRODUCT_NAME)"; 18 | dstSubfolderSpec = 16; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 0; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 134814201AA4EA6300B7C361 /* libRNLocation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNLocation.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 13BE3DEC1AC21097009241FE /* RNLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNLocation.h; sourceTree = ""; }; 28 | 13BE3DED1AC21097009241FE /* RNLocation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNLocation.m; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 58B511D81A9E6C8500147676 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 134814211AA4EA7D00B7C361 /* Products */ = { 43 | isa = PBXGroup; 44 | children = ( 45 | 134814201AA4EA6300B7C361 /* libRNLocation.a */, 46 | ); 47 | name = Products; 48 | sourceTree = ""; 49 | }; 50 | 58B511D21A9E6C8500147676 = { 51 | isa = PBXGroup; 52 | children = ( 53 | 13BE3DEC1AC21097009241FE /* RNLocation.h */, 54 | 13BE3DED1AC21097009241FE /* RNLocation.m */, 55 | 134814211AA4EA7D00B7C361 /* Products */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | /* End PBXGroup section */ 60 | 61 | /* Begin PBXNativeTarget section */ 62 | 58B511DA1A9E6C8500147676 /* RNLocation */ = { 63 | isa = PBXNativeTarget; 64 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNLocation" */; 65 | buildPhases = ( 66 | 58B511D71A9E6C8500147676 /* Sources */, 67 | 58B511D81A9E6C8500147676 /* Frameworks */, 68 | 58B511D91A9E6C8500147676 /* CopyFiles */, 69 | ); 70 | buildRules = ( 71 | ); 72 | dependencies = ( 73 | ); 74 | name = RNLocation; 75 | productName = RCTDataManager; 76 | productReference = 134814201AA4EA6300B7C361 /* libRNLocation.a */; 77 | productType = "com.apple.product-type.library.static"; 78 | }; 79 | /* End PBXNativeTarget section */ 80 | 81 | /* Begin PBXProject section */ 82 | 58B511D31A9E6C8500147676 /* Project object */ = { 83 | isa = PBXProject; 84 | attributes = { 85 | LastUpgradeCheck = 0610; 86 | ORGANIZATIONNAME = Facebook; 87 | TargetAttributes = { 88 | 58B511DA1A9E6C8500147676 = { 89 | CreatedOnToolsVersion = 6.1.1; 90 | }; 91 | }; 92 | }; 93 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNLocation" */; 94 | compatibilityVersion = "Xcode 3.2"; 95 | developmentRegion = English; 96 | hasScannedForEncodings = 0; 97 | knownRegions = ( 98 | en, 99 | ); 100 | mainGroup = 58B511D21A9E6C8500147676; 101 | productRefGroup = 58B511D21A9E6C8500147676; 102 | projectDirPath = ""; 103 | projectRoot = ""; 104 | targets = ( 105 | 58B511DA1A9E6C8500147676 /* RNLocation */, 106 | ); 107 | }; 108 | /* End PBXProject section */ 109 | 110 | /* Begin PBXSourcesBuildPhase section */ 111 | 58B511D71A9E6C8500147676 /* Sources */ = { 112 | isa = PBXSourcesBuildPhase; 113 | buildActionMask = 2147483647; 114 | files = ( 115 | 13BE3DEE1AC21097009241FE /* RNLocation.m in Sources */, 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | /* End PBXSourcesBuildPhase section */ 120 | 121 | /* Begin XCBuildConfiguration section */ 122 | 58B511ED1A9E6C8500147676 /* Debug */ = { 123 | isa = XCBuildConfiguration; 124 | buildSettings = { 125 | ALWAYS_SEARCH_USER_PATHS = NO; 126 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 127 | CLANG_CXX_LIBRARY = "libc++"; 128 | CLANG_ENABLE_MODULES = YES; 129 | CLANG_ENABLE_OBJC_ARC = YES; 130 | CLANG_WARN_BOOL_CONVERSION = YES; 131 | CLANG_WARN_CONSTANT_CONVERSION = YES; 132 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 133 | CLANG_WARN_EMPTY_BODY = YES; 134 | CLANG_WARN_ENUM_CONVERSION = YES; 135 | CLANG_WARN_INT_CONVERSION = YES; 136 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 137 | CLANG_WARN_UNREACHABLE_CODE = YES; 138 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 139 | COPY_PHASE_STRIP = NO; 140 | ENABLE_STRICT_OBJC_MSGSEND = YES; 141 | GCC_C_LANGUAGE_STANDARD = gnu99; 142 | GCC_DYNAMIC_NO_PIC = NO; 143 | GCC_OPTIMIZATION_LEVEL = 0; 144 | GCC_PREPROCESSOR_DEFINITIONS = ( 145 | "DEBUG=1", 146 | "$(inherited)", 147 | ); 148 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 149 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 150 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 151 | GCC_WARN_UNDECLARED_SELECTOR = YES; 152 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 153 | GCC_WARN_UNUSED_FUNCTION = YES; 154 | GCC_WARN_UNUSED_VARIABLE = YES; 155 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 156 | MTL_ENABLE_DEBUG_INFO = YES; 157 | ONLY_ACTIVE_ARCH = YES; 158 | SDKROOT = iphoneos; 159 | }; 160 | name = Debug; 161 | }; 162 | 58B511EE1A9E6C8500147676 /* Release */ = { 163 | isa = XCBuildConfiguration; 164 | buildSettings = { 165 | ALWAYS_SEARCH_USER_PATHS = NO; 166 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 167 | CLANG_CXX_LIBRARY = "libc++"; 168 | CLANG_ENABLE_MODULES = YES; 169 | CLANG_ENABLE_OBJC_ARC = YES; 170 | CLANG_WARN_BOOL_CONVERSION = YES; 171 | CLANG_WARN_CONSTANT_CONVERSION = YES; 172 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 173 | CLANG_WARN_EMPTY_BODY = YES; 174 | CLANG_WARN_ENUM_CONVERSION = YES; 175 | CLANG_WARN_INT_CONVERSION = YES; 176 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 177 | CLANG_WARN_UNREACHABLE_CODE = YES; 178 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 179 | COPY_PHASE_STRIP = YES; 180 | ENABLE_NS_ASSERTIONS = NO; 181 | ENABLE_STRICT_OBJC_MSGSEND = YES; 182 | GCC_C_LANGUAGE_STANDARD = gnu99; 183 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 184 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 185 | GCC_WARN_UNDECLARED_SELECTOR = YES; 186 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 187 | GCC_WARN_UNUSED_FUNCTION = YES; 188 | GCC_WARN_UNUSED_VARIABLE = YES; 189 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 190 | MTL_ENABLE_DEBUG_INFO = NO; 191 | SDKROOT = iphoneos; 192 | VALIDATE_PRODUCT = YES; 193 | }; 194 | name = Release; 195 | }; 196 | 58B511F01A9E6C8500147676 /* Debug */ = { 197 | isa = XCBuildConfiguration; 198 | buildSettings = { 199 | HEADER_SEARCH_PATHS = ( 200 | "$(inherited)", 201 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 202 | "$(SRCROOT)/../../React/**", 203 | "$(SRCROOT)/node_modules/react-native/React/**", 204 | "$(SRCROOT)/../react-native/React/**", 205 | ); 206 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 207 | OTHER_LDFLAGS = "-ObjC"; 208 | PRODUCT_NAME = RNLocation; 209 | SKIP_INSTALL = YES; 210 | USER_HEADER_SEARCH_PATHS = ""; 211 | }; 212 | name = Debug; 213 | }; 214 | 58B511F11A9E6C8500147676 /* Release */ = { 215 | isa = XCBuildConfiguration; 216 | buildSettings = { 217 | HEADER_SEARCH_PATHS = ( 218 | "$(inherited)", 219 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 220 | "$(SRCROOT)/../../React/**", 221 | "$(SRCROOT)/node_modules/react-native/React/**", 222 | "$(SRCROOT)/../react-native/React/**", 223 | ); 224 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 225 | OTHER_LDFLAGS = "-ObjC"; 226 | PRODUCT_NAME = RNLocation; 227 | SKIP_INSTALL = YES; 228 | USER_HEADER_SEARCH_PATHS = ""; 229 | }; 230 | name = Release; 231 | }; 232 | /* End XCBuildConfiguration section */ 233 | 234 | /* Begin XCConfigurationList section */ 235 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNLocation" */ = { 236 | isa = XCConfigurationList; 237 | buildConfigurations = ( 238 | 58B511ED1A9E6C8500147676 /* Debug */, 239 | 58B511EE1A9E6C8500147676 /* Release */, 240 | ); 241 | defaultConfigurationIsVisible = 0; 242 | defaultConfigurationName = Release; 243 | }; 244 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNLocation" */ = { 245 | isa = XCConfigurationList; 246 | buildConfigurations = ( 247 | 58B511F01A9E6C8500147676 /* Debug */, 248 | 58B511F11A9E6C8500147676 /* Release */, 249 | ); 250 | defaultConfigurationIsVisible = 0; 251 | defaultConfigurationName = Release; 252 | }; 253 | /* End XCConfigurationList section */ 254 | }; 255 | rootObject = 58B511D31A9E6C8500147676 /* Project object */; 256 | } 257 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 22 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | } 14 | 15 | dependencies { 16 | compile 'com.facebook.react:react-native:0.11.+' 17 | } 18 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Stub of RNLocation for Android. 3 | * 4 | * @providesModule RNLocation 5 | * @flow 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var { NativeModules } = require('react-native'); 11 | module.exports = NativeModules.RNLocation; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-gps", 3 | "version": "0.1.2", 4 | "devDependencies": { 5 | "react-native": "^0.14" 6 | }, 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/agrass/react-native-gps.git" 10 | }, 11 | "license": "MIT", 12 | "keywords": [ 13 | "react-native", 14 | "react-component", 15 | "ios", 16 | "location" 17 | ], 18 | "main": "RNLocation.js" 19 | } 20 | -------------------------------------------------------------------------------- /src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/java/com/syarul/rnlocation/RNLocation.java: -------------------------------------------------------------------------------- 1 | package com.syarul.rnlocation; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | import com.syarul.rnlocation.RNLocationModule; 9 | 10 | import java.util.Arrays; 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | public class RNLocation implements ReactPackage { 15 | @Override 16 | public List createNativeModules( ReactApplicationContext reactContext) { 17 | return Arrays.asList( 18 | new RNLocationModule(reactContext) 19 | ); 20 | } 21 | @Override 22 | public List> createJSModules() { 23 | return Collections.emptyList(); 24 | } 25 | @Override 26 | public List createViewManagers(ReactApplicationContext reactApplicationContext) { 27 | return Collections.emptyList(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/syarul/rnlocation/RNLocationModule.java: -------------------------------------------------------------------------------- 1 | package com.syarul.rnlocation; 2 | 3 | import android.location.Location; 4 | import android.location.LocationManager; 5 | import android.location.LocationListener; 6 | import android.content.Context; 7 | import android.support.annotation.Nullable; 8 | import android.util.Log; 9 | import android.os.Bundle; 10 | 11 | import com.facebook.react.bridge.Arguments; 12 | import com.facebook.react.bridge.ReactApplicationContext; 13 | import com.facebook.react.bridge.ReactContext; 14 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 15 | import com.facebook.react.bridge.ReactMethod; 16 | import com.facebook.react.bridge.ReadableMap; 17 | import com.facebook.react.bridge.WritableMap; 18 | import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; 19 | 20 | public class RNLocationModule extends ReactContextBaseJavaModule{ 21 | 22 | // React Class Name as called from JS 23 | public static final String REACT_CLASS = "RNLocation"; 24 | // Unique Name for Log TAG 25 | public static final String TAG = RNLocationModule.class.getSimpleName(); 26 | 27 | private static final float RCT_DEFAULT_LOCATION_ACCURACY = 1; 28 | public static int POSITION_UNAVAILABLE = 2; 29 | 30 | // Save last Location Provided 31 | private Location mLastLocation; 32 | private LocationListener mLocationListener; 33 | private LocationManager locationManager; 34 | 35 | //The React Native Context 36 | ReactApplicationContext mReactContext; 37 | 38 | 39 | // Constructor Method as called in Package 40 | public RNLocationModule(ReactApplicationContext reactContext) { 41 | super(reactContext); 42 | // Save Context for later use 43 | mReactContext = reactContext; 44 | 45 | locationManager = (LocationManager) mReactContext.getSystemService(Context.LOCATION_SERVICE); 46 | } 47 | 48 | 49 | @Override 50 | public String getName() { 51 | return REACT_CLASS; 52 | } 53 | 54 | private static class LocationOptions { 55 | private final long timeout; 56 | private final double maximumAge; 57 | private final boolean highAccuracy; 58 | private final float distanceFilter; 59 | 60 | private LocationOptions( 61 | long timeout, 62 | double maximumAge, 63 | boolean highAccuracy, 64 | float distanceFilter) { 65 | this.timeout = timeout; 66 | this.maximumAge = maximumAge; 67 | this.highAccuracy = highAccuracy; 68 | this.distanceFilter = distanceFilter; 69 | } 70 | 71 | private static LocationOptions fromReactMap(ReadableMap map) { 72 | // precision might be dropped on timeout (double -> int conversion), but that's OK 73 | long timeout = 74 | map.hasKey("timeout") ? (long) map.getDouble("timeout") : Long.MAX_VALUE; 75 | double maximumAge = 76 | map.hasKey("maximumAge") ? map.getDouble("maximumAge") : Double.POSITIVE_INFINITY; 77 | boolean highAccuracy = !map.hasKey("enableHighAccuracy") || map.getBoolean("enableHighAccuracy"); 78 | float distanceFilter = map.hasKey("distanceFilter") ? 79 | (float) map.getDouble("distanceFilter") : 80 | RCT_DEFAULT_LOCATION_ACCURACY; 81 | 82 | return new LocationOptions(timeout, maximumAge, highAccuracy, distanceFilter); 83 | } 84 | } 85 | 86 | /* 87 | * Location permission request (Not implemented yet) 88 | */ 89 | @ReactMethod 90 | public void requestWhenInUseAuthorization(){ 91 | Log.i(TAG, "Requesting authorization"); 92 | } 93 | 94 | @Nullable 95 | private static String getValidProvider(LocationManager locationManager, boolean highAccuracy) { 96 | String provider = 97 | highAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER; 98 | if (!locationManager.isProviderEnabled(provider)) { 99 | provider = provider.equals(LocationManager.GPS_PROVIDER) 100 | ? LocationManager.NETWORK_PROVIDER 101 | : LocationManager.GPS_PROVIDER; 102 | if (!locationManager.isProviderEnabled(provider)) { 103 | return null; 104 | } 105 | } 106 | return provider; 107 | } 108 | 109 | private void emitError(int code, String message) { 110 | WritableMap error = Arguments.createMap(); 111 | error.putInt("code", code); 112 | 113 | if (message != null) { 114 | error.putString("message", message); 115 | } 116 | 117 | getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class) 118 | .emit("geolocationError", error); 119 | } 120 | 121 | /* 122 | * Location Callback as called by JS 123 | */ 124 | @ReactMethod 125 | public void startUpdatingLocation(ReadableMap options) { 126 | LocationOptions locationOptions = LocationOptions.fromReactMap(options); 127 | String provider = getValidProvider(locationManager, locationOptions.highAccuracy); 128 | 129 | if (provider == null) { 130 | emitError(POSITION_UNAVAILABLE, "No location provider available."); 131 | return; 132 | } 133 | 134 | mLocationListener = new LocationListener(){ 135 | @Override 136 | public void onStatusChanged(String provider,int status,Bundle extras){ 137 | WritableMap params = Arguments.createMap(); 138 | params.putString("provider", provider); 139 | params.putInt("status", status); 140 | 141 | sendEvent(mReactContext, "providerStatusChanged", params); 142 | } 143 | 144 | @Override 145 | public void onProviderEnabled(String provider){ 146 | sendEvent(mReactContext, "providerEnabled", Arguments.createMap()); 147 | } 148 | 149 | @Override 150 | public void onProviderDisabled(String provider){ 151 | sendEvent(mReactContext, "providerDisabled", Arguments.createMap()); 152 | } 153 | 154 | @Override 155 | public void onLocationChanged(Location loc){ 156 | mLastLocation = loc; 157 | if (mLastLocation != null) { 158 | try { 159 | double longitude; 160 | double latitude; 161 | double speed; 162 | double altitude; 163 | double accuracy; 164 | double course; 165 | 166 | // Receive Longitude / Latitude from (updated) Last Location 167 | longitude = mLastLocation.getLongitude(); 168 | latitude = mLastLocation.getLatitude(); 169 | speed = mLastLocation.getSpeed(); 170 | altitude = mLastLocation.getAltitude(); 171 | accuracy = mLastLocation.getAccuracy(); 172 | course = mLastLocation.getBearing(); 173 | 174 | Log.i(TAG, "Got new location. Lng: " +longitude+" Lat: "+latitude); 175 | 176 | // Create Map with Parameters to send to JS 177 | WritableMap params = Arguments.createMap(); 178 | params.putDouble("longitude", longitude); 179 | params.putDouble("latitude", latitude); 180 | params.putDouble("speed", speed); 181 | params.putDouble("altitude", altitude); 182 | params.putDouble("accuracy", accuracy); 183 | params.putDouble("course", course); 184 | 185 | // Send Event to JS to update Location 186 | sendEvent(mReactContext, "locationUpdated", params); 187 | } catch (Exception e) { 188 | e.printStackTrace(); 189 | Log.i(TAG, "Location services disconnected."); 190 | } 191 | } 192 | } 193 | }; 194 | 195 | locationManager.requestLocationUpdates(provider, 1000, locationOptions.distanceFilter, mLocationListener); 196 | } 197 | 198 | @ReactMethod 199 | public void stopUpdatingLocation() { 200 | try { 201 | locationManager.removeUpdates(mLocationListener); 202 | Log.i(TAG, "Location service disabled."); 203 | }catch(Exception e) { 204 | e.printStackTrace(); 205 | } 206 | } 207 | 208 | /* 209 | * Internal function for communicating with JS 210 | */ 211 | private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) { 212 | if (reactContext.hasActiveCatalystInstance()) { 213 | reactContext 214 | .getJSModule(RCTDeviceEventEmitter.class) 215 | .emit(eventName, params); 216 | } else { 217 | Log.i(TAG, "Waiting for CatalystInstance..."); 218 | } 219 | } 220 | } 221 | --------------------------------------------------------------------------------