├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation-issue.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .watchmanconfig ├── CHANGELOG.md ├── README.md ├── RNLaunchNavigator.podspec ├── RNLogger.js ├── android.js ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── uk │ └── co │ └── workingedge │ ├── ILogger.java │ ├── LaunchNavigator.java │ └── RNLaunchNavigator │ ├── RNLaunchNavigatorModule.java │ ├── RNLaunchNavigatorPackage.java │ ├── RNLogger.java │ └── RNUtils.java ├── constants.js ├── index.d.ts ├── index.js ├── ios.js ├── ios ├── RNLaunchNavigator.xcodeproj │ └── project.pbxproj └── RNLaunchNavigator │ ├── LN_LaunchNavigator.h │ ├── LN_LaunchNavigator.m │ ├── LN_Reachability.h │ ├── LN_Reachability.m │ ├── RNLaunchNavigator.h │ ├── RNLaunchNavigator.m │ ├── WE_Logger.h │ ├── WE_Logger.m │ ├── WE_ReactNativeLogger.h │ └── WE_ReactNativeLogger.m ├── package.json └── react-native.config.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ dpa99c ] 4 | custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZRD3W47HQ3EMJ&source=url 5 | patreon: dpa99c 6 | ko_fi: davealden -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a problem 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 28 | 29 | 30 | 31 | # Bug report 32 | 33 | **Current behavior:** 34 | 35 | 36 | 37 | 41 | 42 | **Expected behavior:** 43 | 44 | 45 | **Steps to reproduce:** 46 | 47 | 48 | **Screenshots** 49 | 50 | 51 | **Environment information** 52 | 53 | - Cordova CLI version 54 | - `cordova -v` 55 | - Cordova platform version 56 | - `cordova platform ls` 57 | - Plugins & versions installed in project (including this plugin) 58 | - `cordova plugin ls` 59 | - Dev machine OS and version, e.g. 60 | - OSX 61 | - `sw_vers` 62 | - Windows 10 63 | - `winver` 64 | 65 | _Runtime issue_ 66 | - Device details 67 | - _e.g. iPhone X, Samsung Galaxy S8, iPhone X Simulator, Pixel XL Emulator_ 68 | - OS details 69 | - _e.g. iOS 12.2, Android 9.0_ 70 | 71 | _Android build issue:_ 72 | - Node JS version 73 | - `node -v` 74 | - Gradle version 75 | - `ls platforms/android/.gradle` 76 | - Target Android SDK version 77 | - `android:targetSdkVersion` in `AndroidManifest.xml` 78 | - Android SDK details 79 | - `sdkmanager --list | sed -e '/Available Packages/q'` 80 | 81 | _iOS build issue:_ 82 | - Node JS version 83 | - `node -v` 84 | - XCode version 85 | 86 | 87 | **Related code:** 88 | ``` 89 | insert any relevant code here such as plugin API calls / input parameters 90 | ``` 91 | 92 | **Console output** 93 |
94 | console output 95 | 96 | ``` 97 | 98 | // Paste any relevant JS/native console output here 99 | 100 | ``` 101 | 102 |


103 | 104 | **Other information:** 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation issue 3 | about: Describe an issue with the documentation 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 16 | 17 | 18 | # Documentation issue 19 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 15 | 16 | 17 | # Feature request 18 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## PR Type 2 | What kind of change does this PR introduce? 3 | 4 | 5 | - [ ] Bugfix 6 | - [ ] Feature 7 | - [ ] Code style update (formatting, local variables) 8 | - [ ] Refactoring (no functional changes, no api changes) 9 | - [ ] Documentation changes 10 | - [ ] Other... Please describe: 11 | 12 | 13 | 14 | ## PR Checklist 15 | For bug fixes / features, please check if your PR fulfills the following requirements: 16 | 17 | - [ ] Testing has been carried out for the changes have been added 18 | - [ ] Regression testing has been carried out for existing functionality 19 | - [ ] Docs have been added / updated 20 | 21 | ## What is the purpose of this PR? 22 | 23 | 24 | 25 | ## Does this PR introduce a breaking change? 26 | - [ ] Yes 27 | - [ ] No 28 | 29 | 30 | 31 | ## What testing has been done on the changes in the PR? 32 | 33 | 34 | ## What testing has been done on existing functionality? 35 | 36 | 37 | ## Other information -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | /package-lock.json 58 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": [ 3 | ".git", 4 | "node_modules" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | 4 | ## 1.0.9 5 | - (types) bugfix: Apply patch to fix `index.d.ts` 6 | - Merge [PR#38](https://github.com/dpa99c/react-native-launch-navigator/pull/38): Android 11 (API 30) target support 7 | 8 | ## 1.0.8 9 | - Merge [PR#30](https://github.com/dpa99c/react-native-launch-navigator/pull/30): Fix for Android X 10 | - Merge [PR#31](https://github.com/dpa99c/react-native-launch-navigator/pull/30): (Android) discover apps on `getAvailableApps()` call 11 | - (iOS) Rework hook scripts to detect development platform and projects so as to only run iOS-specific hooks if iOS platform project exists and development platform is OSX. 12 | - Resolves [#36](https://github.com/dpa99c/react-native-launch-navigator/issues/36) 13 | - (Doc): Remove erroneous reference to native picker UI and make it clear that none is provided out-of-the-box. 14 | - Resolves [#33](https://github.com/dpa99c/react-native-launch-navigator/issues/33) 15 | - (iOS): Remove postinstall/postlink scripts and document manual process to replace them. 16 | - Resolves [#34](https://github.com/dpa99c/react-native-launch-navigator/issues/34) 17 | 18 | ## 1.0.7 19 | - Merge [PR#18](https://github.com/dpa99c/react-native-launch-navigator/pull/18): Use project's minSdkVersion if available 20 | - Merge [PR#20](https://github.com/dpa99c/react-native-launch-navigator/pull/20): Update `build.gradle` to use `implementation` instead of deprecated `compile` directive. 21 | 22 | ## 1.0.6 23 | - Support for React Native 0.60.x 24 | - Fixes [#15](https://github.com/dpa99c/react-native-launch-navigator/issues/15) and [#16](https://github.com/dpa99c/react-native-launch-navigator/issues/16). 25 | 26 | ## 1.0.5 27 | - Pass `navigate=yes` to Waze on Android if input type is an address. See https://github.com/dpa99c/phonegap-launch-navigator/issues/213. 28 | - Fix checks for empty strings/objects on iOS. 29 | - iOS fix: Make LNEmptyCoord static to scope it to the class. 30 | - Merge [PR#10](https://github.com/dpa99c/react-native-launch-navigator/pull/10): Fixed `LaunchNavigator.navigate` never resolving the returned promise when AppleMaps/MapKit is used on iOS 31 | 32 | ## 1.0.4 33 | Fix check for empty extras parameter on iOS. See [dpa99c/phonegap-launch-navigator#212](https://github.com/dpa99c/phonegap-launch-navigator/issues/212). 34 | 35 | ## 1.0.3 36 | Enable specification of Google API key for geocoding on Android. See [dpa99c/phonegap-launch-navigator#211](https://github.com/dpa99c/phonegap-launch-navigator/issues/211). 37 | 38 | ## 1.0.2 39 | Fix auto-linking scripts to prevent multiple linking/unlinking attempts. Resolves [#2](https://github.com/dpa99c/react-native-launch-navigator/issues/2). 40 | 41 | ## 1.0.1 42 | Set FLAG_ACTIVITY_NEW_TASK on Android when launching intent to invoke navigation apps. Resolves [#1](https://github.com/dpa99c/react-native-launch-navigator/issues/1). 43 | 44 | ## 1.0.0 45 | Initial release: functionality ported from [phonegap-launch-navigator](https://github.com/dpa99c/phonegap-launch-navigator) 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | React Native Launch Navigator [![Latest Stable Version](https://img.shields.io/npm/v/react-native-launch-navigator.svg)](https://www.npmjs.com/package/react-native-launch-navigator) [![Total Downloads](https://img.shields.io/npm/dt/react-native-launch-navigator.svg)](https://npm-stat.com/charts.html?package=react-native-launch-navigator) 2 | =================================================================================================================================================================================================================================================================================================================================================================================================================================== 3 | 4 | A React Native module for launching today's most popular navigation/ride apps to navigate to a destination. 5 | 6 | Platforms: Android and iOS. 7 | 8 | Key features: 9 | 10 | - Single, clean API to abstract away the gory details of each 3rd party app's custom URI scheme 11 | - Detects which supported apps are installed/available on the user's device 12 | - API to detect which features are supported by which apps on which platforms 13 | - Growing list of [supported apps](#supported-navigation-apps) 14 | 15 | 16 | 17 |

18 | 19 |   20 | 21 |

22 | 23 | Launch Navigator functionality is also available as a [Cordova/Phonegap plugin](https://github.com/dpa99c/phonegap-launch-navigator). 24 | 25 | 26 | [![donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG_global.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZRD3W47HQ3EMJ) 27 | 28 | I dedicate a considerable amount of my free time to developing and maintaining my Open Source software. 29 | To help ensure this module is kept updated, new features are added and bugfixes are implemented quickly, please donate a couple of dollars (or a little more if you can stretch) as this will help me to afford to dedicate time to its maintenance. Please consider donating if you're using this software in an app that makes you money, if you're being paid to make the app, if you're asking for new features or priority bug fixes. 30 | 31 | 32 | 33 | 34 | **Table of Contents** 35 | 36 | - [General concepts](#general-concepts) 37 | - [App detection, selection and launching](#app-detection-selection-and-launching) 38 | - [Geocoding and input format of start/destination locations](#geocoding-and-input-format-of-startdestination-locations) 39 | - [Supported navigation apps](#supported-navigation-apps) 40 | - [Adding support for more apps](#adding-support-for-more-apps) 41 | - [Installation](#installation) 42 | - [Add iOS URL schemes](#add-ios-url-schemes) 43 | - [Usage](#usage) 44 | - [Simple usage](#simple-usage) 45 | - [Navigate to a destination address from current location.](#navigate-to-a-destination-address-from-current-location) 46 | - [Navigate to a destination with specified start location](#navigate-to-a-destination-with-specified-start-location) 47 | - [Navigate using latitude/longitude coordinates](#navigate-using-latitudelongitude-coordinates) 48 | - [Advanced usage](#advanced-usage) 49 | - [Navigate using a specific app](#navigate-using-a-specific-app) 50 | - [List all of the apps supported by the current platform](#list-all-of-the-apps-supported-by-the-current-platform) 51 | - [List apps available on the current device](#list-apps-available-on-the-current-device) 52 | - [Supported parameters](#supported-parameters) 53 | - [Transport modes](#transport-modes) 54 | - [Module API](#module-api) 55 | - [Constants](#constants) 56 | - [PLATFORM](#platform) 57 | - [APP](#app) 58 | - [APP_NAMES](#app_names) 59 | - [TRANSPORT_MODE](#transport_mode) 60 | - [LAUNCH_MODE](#launch_mode) 61 | - [API methods](#api-methods) 62 | - [navigate()](#navigate) 63 | - [Parameters](#parameters) 64 | - [Returns](#returns) 65 | - [isAppAvailable()](#isappavailable) 66 | - [Parameters](#parameters-1) 67 | - [Returns](#returns-1) 68 | - [getAvailableApps()](#getavailableapps) 69 | - [Returns](#returns-2) 70 | - [getAppDisplayName()](#getappdisplayname) 71 | - [Parameters](#parameters-2) 72 | - [Returns](#returns-3) 73 | - [getAppsForPlatform()](#getappsforplatform) 74 | - [Parameters](#parameters-3) 75 | - [Returns](#returns-4) 76 | - [supportsTransportMode()](#supportstransportmode) 77 | - [Parameters](#parameters-4) 78 | - [Returns](#returns-5) 79 | - [getTransportModes()](#gettransportmodes) 80 | - [Parameters](#parameters-5) 81 | - [Returns](#returns-6) 82 | - [supportsDestName()](#supportsdestname) 83 | - [Parameters](#parameters-6) 84 | - [Returns](#returns-7) 85 | - [supportsStart()](#supportsstart) 86 | - [Parameters](#parameters-7) 87 | - [Returns](#returns-8) 88 | - [supportsStartName()](#supportsstartname) 89 | - [Parameters](#parameters-8) 90 | - [Returns](#returns-9) 91 | - [supportsLaunchMode()](#supportslaunchmode) 92 | - [Parameters](#parameters-9) 93 | - [Returns](#returns-10) 94 | - [enableDebug()](#enabledebug) 95 | - [Parameters](#parameters-10) 96 | - [setGoogleApiKey()](#setgoogleapikey) 97 | - [Parameters](#parameters-11) 98 | - [Example project](#example-project) 99 | - [Platform-specifics](#platform-specifics) 100 | - [Android](#android) 101 | - [Google API key for Android](#google-api-key-for-android) 102 | - [`geo:` URI scheme](#geo-uri-scheme) 103 | - [Google Maps launch modes](#google-maps-launch-modes) 104 | - [iOS](#ios) 105 | - ["Removing" Apple Maps](#removing-apple-maps) 106 | - [Apple Maps launch modes](#apple-maps-launch-modes) 107 | - [URI scheme launch method](#uri-scheme-launch-method) 108 | - [MapKit class launch method](#mapkit-class-launch-method) 109 | - [App-specifics](#app-specifics) 110 | - [Lyft](#lyft) 111 | - [99 Taxi](#99-taxi) 112 | - [Reporting issues](#reporting-issues) 113 | - [License](#license) 114 | 115 | 116 | 117 | # General concepts 118 | 119 | ## App detection, selection and launching 120 | - The module will detect which supported navigation apps are available on the device. 121 | - The API allows you to programmatically: 122 | - check which apps are available on the current device 123 | - check which apps support which navigation options 124 | - launch a specific app for navigation 125 | 126 | ## Geocoding and input format of start/destination locations 127 | - Some navigation apps require that destination/start locations be specified as coordinates, and others require an address. 128 | - See [App location support type wiki page](https://github.com/dpa99c/phonegap-launch-navigator/wiki/App-location-type-support) for details of which apps support which location types. 129 | - By default, this module will appropriately geocode or reverse-geocode the locations you provide to ensure the app receives the location in the required format. 130 | - However, geocoding requires use of a remote service, so an internet connection is required. 131 | - If `navigate()` is passed a location type which the selected app doesn't support, the error callback will be invoked if: 132 | - geocoding is disabled by passing `enableGeocoding: false` in the options object 133 | - there is no internet connection to perform the remote geocode operation 134 | - geocoding fails (e.g. an address cannot be found for the given lat/long coords) 135 | 136 | # Supported navigation apps 137 | 138 | The module currently supports launching the following navigation apps: 139 | 140 | Android 141 | 142 | * [Google Maps](https://play.google.com/store/apps/details?id=com.google.android.apps.maps) 143 | * [Waze](https://play.google.com/store/apps/details?id=com.waze) 144 | * [Citymapper](https://play.google.com/store/apps/details?id=com.citymapper.app.release) 145 | * [Uber](https://play.google.com/store/apps/details?id=com.ubercab) 146 | * [Yandex Navigator](https://play.google.com/store/apps/details?id=ru.yandex.yandexnavi) 147 | * [Sygic](https://play.google.com/store/apps/details?id=com.sygic.aura) 148 | * [HERE Maps](https://play.google.com/store/apps/details?id=com.here.app.maps) 149 | * [Moovit](https://play.google.com/store/apps/details?id=com.tranzmate) 150 | * [Lyft](https://play.google.com/store/apps/details?id=me.lyft.android) 151 | * [MAPS.ME](https://play.google.com/store/apps/details?id=com.mapswithme.maps.pro) 152 | * [Cabify](https://play.google.com/store/apps/details?id=com.cabify.rider) 153 | * [99 Taxi](https://play.google.com/store/apps/details?id=com.taxis99&hl=en) 154 | * [Baidu Maps](https://play.google.com/store/apps/details?id=com.baidu.BaiduMap) 155 | * [Gaode](https://play.google.com/store/apps/details?id=com.autonavi.minimap&hl=en) 156 | * _Any installed app that supports the [`geo:` URI scheme](http://developer.android.com/guide/components/intents-common.html#Maps)_ 157 | 158 | iOS 159 | 160 | * [Apple Maps](http://www.apple.com/uk/ios/maps/) 161 | * [Google Maps](https://itunes.apple.com/gb/app/google-maps/id585027354?mt=8) 162 | * [Waze](https://itunes.apple.com/gb/app/waze-gps-maps-social-traffic/id323229106?mt=8) 163 | * [Citymapper](https://itunes.apple.com/gb/app/citymapper-london-hong-kong/id469463298?mt=8) 164 | * [Garmin Navigon](https://itunes.apple.com/us/developer/garmin-wuerzburg-gmbh/id320198400) 165 | * [Transit App](https://itunes.apple.com/us/app/transit-app-real-time-tracker/id498151501?mt=8) 166 | * [Yandex Navigator](https://itunes.apple.com/gb/app/yandex.navigator/id474500851?mt=8) 167 | * [Uber](https://itunes.apple.com/gb/app/uber/id368677368?mt=8) 168 | * [Tomtom](https://itunes.apple.com/gb/developer/tomtom/id326055452) 169 | * [Sygic](https://itunes.apple.com/gb/app/sygic-gps-navigation-offline/id585193266?mt=8) 170 | * [HERE Maps](https://itunes.apple.com/gb/app/here-maps-offline-navigation/id955837609?mt=8) 171 | * [Moovit](https://itunes.apple.com/us/app/moovit-your-local-transit/id498477945?mt=8) 172 | * [Lyft](https://itunes.apple.com/us/app/lyft/id529379082?mt=8) 173 | * [MAPS.ME](https://itunes.apple.com/us/app/maps-me-offline-map-with-navigation-directions/id510623322?mt=8) 174 | * [Cabify](https://itunes.apple.com/us/app/cabify-enjoy-the-ride/id476087442?mt=8) 175 | * [99 Taxi](https://itunes.apple.com/gb/app/99-taxi-and-private-drivers/id553663691?mt=8) 176 | * [Baidu Maps](https://itunes.apple.com/us/app/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE-%E5%85%AC%E4%BA%A4%E5%9C%B0%E9%93%81%E5%87%BA%E8%A1%8C%E5%BF%85%E5%A4%87%E7%9A%84%E6%99%BA%E8%83%BD%E5%AF%BC%E8%88%AA/id452186370?mt=8) 177 | * [Gaode](https://itunes.apple.com/cn/app/%E9%AB%98%E5%BE%B7%E5%9C%B0%E5%9B%BE-%E7%B2%BE%E5%87%86%E5%9C%B0%E5%9B%BE-%E5%AF%BC%E8%88%AA%E5%BF%85%E5%A4%87/id461703208?mt=8) 178 | 179 | 180 | ## Adding support for more apps 181 | 182 | This module is a work in progress. I'd like it to support launching of as many popular navigation apps as possible. 183 | 184 | If there's another navigation app which you think should be explicitly supported and **it provides a mechanism to externally launch it**, 185 | open an issue containing a link or details of how the app should be invoked. 186 | 187 | **Don't** just open an issue saying "Add support for Blah" without first finding out if/how it can be externally launched. 188 | I don't have time to research launch mechanisms for every suggested app, so I will close such issues immediately. 189 | 190 | # Installation 191 | 192 | npm install --save react-native-launch-navigator 193 | 194 | For iOS only: 195 | 196 | cd ios && pod install 197 | 198 | ## Add iOS URL schemes 199 | On iOS, for each installed navigation app you want your app to be able to launch, you must manually whitelist its custom URL scheme in your app's `Info.plist`. 200 | Note: this is required since React Native v0.60 added autolinking and removed support for postlink hook scripts which made it possible to automate this step. 201 | 202 | Add the URL schemes for the navigation apps you want to support to the `LSApplicationQueriesSchemes` key in your `Info.plist`: 203 | 204 | | App | Scheme | 205 | |---|---| 206 | | City Mapper | `citymapper` | 207 | | Google Maps | `comgooglemaps` | 208 | | Garmin Navigon | `navigon` | 209 | | Transit App | `transit` | 210 | | Waze | `waze` | 211 | | Yandex Navigator | `yandexnavi` | 212 | | Uber | `uber` | 213 | | Tomtom | `tomtomhome` | 214 | | Sygic | `com.sygic.aura` | 215 | | HERE Maps | `here-route` | 216 | | Moovit | `moovit` | 217 | | Lyft | `lyft` | 218 | | MAPS.ME | `mapsme` | 219 | | Cabify | `cabify` | 220 | | Baidu Maps | `baidumap` | 221 | | 99 Taxi | `taxis99` | 222 | | Gadode | `iosamap` | 223 | 224 | The full list of URL schemes above can be found in the [example project's `Info.plist`](https://github.com/dpa99c/react-native-launch-navigator-example/blob/master/ios/RNLNExample/Info.plist#L78). 225 | 226 | # Usage 227 | 228 | Import the module into your app: 229 | 230 | import LaunchNavigator from 'react-native-launch-navigator'; 231 | 232 | ## Simple usage 233 | 234 | On Android, don't forget to set your [Google API key](#google-api-key-for-android): 235 | 236 | if(Platform.OS === "android") LaunchNavigator.setGoogleApiKey("your_api_key"); 237 | 238 | ### Navigate to a destination address from current location. 239 | 240 | Uses default OS navigation app (Google Maps on Android / Apple Maps on iOS). 241 | 242 | LaunchNavigator.navigate("London, UK") 243 | .then(() => console.log("Launched navigator")) 244 | .catch((err) => console.error("Error launching navigator: "+err)); 245 | 246 | ### Navigate to a destination with specified start location 247 | 248 | LaunchNavigator.navigate("London, UK", { 249 | start: "Manchester, UK" 250 | }) 251 | .then(() => console.log("Launched navigator")) 252 | .catch((err) => console.error("Error launching navigator: "+err)); 253 | 254 | ### Navigate using latitude/longitude coordinates 255 | 256 | Coordinates can be specified as a string or array 257 | 258 | LaunchNavigator.navigate([50.279306, -5.163158], { 259 | start: "50.342847, -4.749904" 260 | }) 261 | .then(() => console.log("Launched navigator")) 262 | .catch((err) => console.error("Error launching navigator: "+err)); 263 | 264 | ## Advanced usage 265 | 266 | ### Navigate using a specific app 267 | 268 | let app = null; 269 | 270 | LaunchNavigator.isAppAvailable(LaunchNavigator.APP.WAZE).then((isWazeAvailable) => { 271 | if(isWazeAvailable){ 272 | app = LaunchNavigator.APP.WAZE; 273 | }else{ 274 | console.warn("Waze not available - falling back to default navigation app"); 275 | } 276 | 277 | LaunchNavigator.navigate("London, UK", { 278 | app: app 279 | }); 280 | .then(() => console.log("Launched navigator")) 281 | .catch((err) => console.error("Error launching navigator: "+err)); 282 | }); 283 | 284 | 285 | ### List all of the apps supported by the current platform 286 | 287 | if(Platform.OS === "android"){ 288 | platform = LaunchNavigator.PLATFORM.ANDROID; 289 | }else if(Platform.OS == "ios"){ 290 | platform = LaunchNavigator.PLATFORM.IOS; 291 | } 292 | 293 | LaunchNavigator.getAppsForPlatform(platform).forEach((app) => { 294 | console.log(LaunchNavigator.getAppDisplayName(app) + " is supported"); 295 | }); 296 | 297 | ### List apps available on the current device 298 | 299 | let apps = LaunchNavigator.getAvailableApps(); 300 | for(let app in apps){ 301 | console.log(LaunchNavigator.getAppDisplayName(app) + (apps[app] ? " is" : " isn't") +" available"); 302 | } 303 | 304 | # Supported parameters 305 | 306 | Different apps support different input parameters on different platforms. 307 | Any input parameters not supported by a specified app will be ignored. 308 | 309 | The following table enumerates which apps support which parameters. 310 | 311 | | Platform | App | Dest | Dest name | Start | Start name | Transport mode | Free | 312 | |----------|--------------------------------|:----:|:---------:|:-----:|:----------:|:--------------:|:----:| 313 | | Android | Google Maps (Map mode) | X | | X | | | X | 314 | | Android | Google Maps (Turn-by-turn mode)| X | | | | X | X | 315 | | Android | Waze | X | | | | | X | 316 | | Android | CityMapper | X | X | X | X | | X | 317 | | Android | Uber | X | X | X | X | | X | 318 | | Android | Yandex | X | | X | | | X | 319 | | Android | Sygic | X | | | | X | X | 320 | | Android | HERE Maps | X | X | X | X | | X | 321 | | Android | Moovit | X | X | X | X | | X | 322 | | Android | Lyft | X | | X | | | X | 323 | | Android | MAPS.ME | X | | X | | X | X | 324 | | Android | _Geo: URI scheme_ | X | X | | | | N/A | 325 | | Android | Cabify | X | X | X | X | | X | 326 | | Android | Baidu Maps | X | X[\[1\]](#apple_baidu_maps_nicknames_uri) | X | X[\[1\]](#apple_baidu_maps_nicknames_uri) | X | X | 327 | | Android | 99 Taxi | X | X | X | X | | X | 328 | | Android | Gaode Maps | X | X | X | X | X | X | 329 | | iOS | Apple Maps - URI scheme | X | | X | | X | X | 330 | | iOS | Apple Maps - MapKit class | X | X | X | X | X | X | 331 | | iOS | Google Maps | X | | X | | X | X | 332 | | iOS | Waze | X | | | | | X | 333 | | iOS | Citymapper | X | X | X | X | | X | 334 | | iOS | Navigon | X | X | | | | | 335 | | iOS | Transit App | X | | X | | | X | 336 | | iOS | Yandex | X | | X | | | X | 337 | | iOS | Uber | X | X | X | | | X | 338 | | iOS | Tomtom | X | X | | | | | 339 | | iOS | Sygic | X | | | | X | X | 340 | | iOS | HERE Maps | X | X | X | X | | X | 341 | | iOS | Moovit | X | X | X | X | | X | 342 | | iOS | Lyft | X | | X | | | X | 343 | | iOS | MAPS.ME | X | | X | | X | X | 344 | | iOS | Cabify | X | X | X | X | | X | 345 | | iOS | Baidu Maps | X | X[\[1\]](#apple_baidu_maps_nicknames_uri) | X | X[\[1\]](#apple_baidu_maps_nicknames_uri) | X | X | 346 | | iOS | 99 Taxi | X | X | X | X | | X | 347 | | iOS | Gaode Maps | X | X | X | X | X | X | 348 | 349 | [1]: Only supported when Start or Dest is specified as lat/lon (e.g. "50,-4") 350 | 351 | Table columns: 352 | 353 | * Dest - destination location specified as lat/lon (e.g. "50,-4") or address (e.g. "London") 354 | * Dest name - nickname for destination location (e.g. "Bob's house") 355 | * Start - start location specified as lat/lon (e.g. "50,-4") or address (e.g. "London") 356 | * Start name - nickname for start location (e.g. "Bob's house") 357 | * Transport mode - mode of transport to use for route planning (e.g. "walking") 358 | * Free - is the app free or does it cost money? 359 | 360 | 361 | ## Transport modes 362 | 363 | Apps that support specifying transport mode. 364 | 365 | | Platform | App | Driving | Walking | Bicycling | Transit | 366 | |----------|--------------------------------|:-------:|:-------:|:---------:|:-------:| 367 | | Android | Google Maps (Turn-by-turn mode)| X | X | X | X | 368 | | Android | Sygic | X | X | | | 369 | | Android | MAPS.ME | X | X | X | X | 370 | | Android | Baidu Maps | X | X | X | X | 371 | | Android | Gaode Maps | X | X | X | X | 372 | | iOS | Apple Maps | X | X | | | 373 | | iOS | Google Maps | X | X | X | X | 374 | | iOS | Sygic | X | X | | | 375 | | iOS | MAPS.ME | X | X | X | X | 376 | | iOS | Baidu Maps | X | X | X | X | 377 | | iOS | Gaode Maps | X | X | X | X | 378 | 379 | 380 | # Module API 381 | 382 | All of the module constants and functions should be referenced from the namespace used to import the module, for example: 383 | 384 | import LaunchNavigator from 'react-native-launch-navigator'; 385 | let android = LaunchNavigator.PLATFORM.ANDROID; 386 | 387 | ## Constants 388 | 389 | ### PLATFORM 390 | 391 | Supported platforms: 392 | 393 | - `LaunchNavigator.PLATFORM.ANDROID` 394 | - `LaunchNavigator.PLATFORM.IOS` 395 | 396 | ### APP 397 | 398 | Supported apps: 399 | 400 | - `LaunchNavigator.APP.GEO` (Android) - invokes a native chooser, allowing users to select an app which supports the `geo:` URI scheme for navigation 401 | - `LaunchNavigator.APP.GOOGLE_MAPS` (Android & iOS) 402 | - `LaunchNavigator.APP.WAZE` (Android & iOS) 403 | - `LaunchNavigator.APP.CITYMAPPER` (Android & iOS) 404 | - `LaunchNavigator.APP.UBER` (Android & iOS) 405 | - `LaunchNavigator.APP.APPLE_MAPS` (iOS) 406 | - `LaunchNavigator.APP.NAVIGON` (iOS) 407 | - `LaunchNavigator.APP.TRANSIT_APP` (iOS) 408 | - `LaunchNavigator.APP.YANDEX` (Android & iOS) 409 | - `LaunchNavigator.APP.TOMTOM` (iOS) 410 | - `LaunchNavigator.APP.SYGIC` (Android & iOS) 411 | - `LaunchNavigator.APP.HERE_MAPS` (Android & iOS) 412 | - `LaunchNavigator.APP.MOOVIT` (Android & iOS) 413 | - `LaunchNavigator.APP.LYFT` (Android & iOS) 414 | - `LaunchNavigator.APP.MAPS_ME` (Android & iOS) 415 | - `LaunchNavigator.APP.CABIFY` (Android & iOS) 416 | - `LaunchNavigator.APP.BAIDU` (Android & iOS) 417 | - `LaunchNavigator.APP.TAXIS_99` (Android & iOS) 418 | - `LaunchNavigator.APP.GAODE` (Android & iOS) 419 | 420 | ### APP_NAMES 421 | 422 | Display names for supported apps, referenced by `LaunchNavigator.APP`. 423 | 424 | e.g. `LaunchNavigator.APP_NAMES[LaunchNavigator.APP.GOOGLE_MAPS] == "Google Maps"` 425 | x 426 | ### TRANSPORT_MODE 427 | 428 | Transport modes for navigation: 429 | 430 | - `LaunchNavigator.TRANSPORT_MODE.DRIVING` 431 | - `LaunchNavigator.TRANSPORT_MODE.WALKING` 432 | - `LaunchNavigator.TRANSPORT_MODE.BICYCLING` 433 | - `LaunchNavigator.TRANSPORT_MODE.TRANSIT` 434 | 435 | ### LAUNCH_MODE 436 | 437 | Launch modes supported by Google Maps on Android (see [Google Maps launch modes](#googlemapslaunchmodes)): 438 | 439 | - `LaunchNavigator.LAUNCH_MODE.MAPS` - Maps view 440 | - `LaunchNavigator.LAUNCH_MODE.TURN_BY_TURN` - Navigation view 441 | - `LaunchNavigator.LAUNCH_MODE.GEO` - Navigation view via `geo:` URI scheme 442 | 443 | Launch modes supported by Apple Maps on iOS (see [Apple Maps launch modes](#applemapslaunchmodes): 444 | 445 | - `LaunchNavigator.LAUNCH_MODE.URI_SCHEME`: use the URI scheme launch method. Default if not specified. 446 | - `LaunchNavigator.LAUNCH_MODE.MAPKIT`: use the MapKit class launch method. 447 | 448 | 449 | ## API methods 450 | 451 | ### navigate() 452 | Launches a navigation app with a specified destination. 453 | 454 | LaunchNavigator.navigate(destination, options); 455 | 456 | #### Parameters 457 | - destination (required): destination location to use for navigation. 458 | Either: 459 | - a {string} containing the address. e.g. "Buckingham Palace, London" 460 | - a {string} containing a latitude/longitude coordinate. e.g. "50.1. -4.0" 461 | - an {array} where the first element is the latitude and the second element is a longitude, as decimal numbers. e.g. [50.1, -4.0] 462 | - options - optional parameters: 463 | - {string} app - name of the navigation app to use for directions. 464 | - Specify using `LaunchNavigator.APP` constants. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 465 | - If not specified, defaults to the platform default maps app (Google Maps for Android/Apple Maps for iOS). 466 | - Note: this module does not currently implement an out-of-the-box picker UI so it's up to the app developer to implement a UI with which the user can specify which available navigation app they want to use. 467 | - {string} destinationName - nickname to display in app for destination. e.g. "Bob's House". 468 | - start (optional): start location to use for navigation. 469 | If not specified, the current device location will be used. 470 | Either: 471 | - a {string} containing the address. e.g. "Buckingham Palace, London" 472 | - a {string} containing a latitude/longitude coordinate. e.g. "50.1. -4.0" 473 | - an {array} where the first element is the latitude and the second element is a longitude, as decimal numbers. e.g. [50.1, -4.0] 474 | - {string} startName - nickname to display in app for start. e.g. "My Place". 475 | - {string} transportMode - transportation mode for navigation. 476 | - Defaults to "driving" if not specified. 477 | - Specify using `LaunchNavigator.TRANSPORT_MODE` constants. 478 | - {string} launchMode - mode in which to open default navigation app for platform: 479 | - Android: mode in which to open Google Maps app 480 | - `LaunchNavigator.LAUNCH_MODE.MAPS` or `LaunchNavigator.LAUNCH_MODE.TURN_BY_TURN` 481 | - Defaults to `LaunchNavigator.LAUNCH_MODE.MAPS` if not specified. 482 | - iOS: method to use to open Apple Maps app 483 | - `LaunchNavigator.LAUNCH_MODE.URI_SCHEME` or `LaunchNavigator.LAUNCH_MODE.MAPKIT` 484 | - Defaults to `LaunchNavigator.LAUNCH_MODE.URI_SCHEME` if not specified. 485 | - {object} extras - a key/value map of extra app-specific parameters. For example, to tell Google Maps on Android to display Satellite view in "maps" launch mode: `{"t": "k"}` 486 | - These will be appended to the URL used to invoke the app, e.g. `google_maps://?t=k&...` 487 | - See [Supported app URL scheme documentation wiki page](https://github.com/dpa99c/phonegap-launch-navigator/wiki/Supported-app-URL-scheme-documentation) for links to find app-specific parameters. 488 | - {boolean} enableGeocoding - if true, and input location type(s) doesn't match those required by the app, use geocoding to obtain the address/coords as required. Defaults to true. 489 | 490 | #### Returns 491 | - {Promise} 492 | - resolved when the navigation app is successfully launched. 493 | - rejected if an error is occurred. Rejected with args: 494 | - {string} - error message 495 | 496 | ### isAppAvailable() 497 | Determines if the given app is installed and available on the current device. 498 | 499 | let app = LaunchNavigator.APP.WAZE; 500 | LaunchNavigator.isAppAvailable(app) 501 | .then((isAvailable) => { 502 | console.log(LaunchNavigator.getAppDisplayName(app)+" is available: "+isAvailable); 503 | }) 504 | .catch((error) => { 505 | console.error(error); 506 | }); 507 | 508 | #### Parameters 509 | - {string} appName - name of the app to check availability for. Define as a constant using `LaunchNavigator.APP`. 510 | 511 | #### Returns 512 | - {Promise} 513 | - resolved with: 514 | - {boolean} - indicates the availability of the specified app. 515 | - rejected if an error is occurred. Rejected with args: 516 | - {string} - error message 517 | 518 | ### getAvailableApps() 519 | Returns a list indicating which apps are installed and available on the current device for the current platform. 520 | 521 | LaunchNavigator.getAvailableApps() 522 | .then((apps) => { 523 | for(let app in apps){ 524 | console.log(LaunchNavigator.getAppDisplayName(app)+" is "+(apps[app] ? "available" : "unavailable")); 525 | } 526 | }) 527 | .catch((error) => { 528 | console.error(error); 529 | }); 530 | 531 | #### Returns 532 | - {Promise} 533 | - resolved with: 534 | - {object} - a key/value object where the key is the app name as a constant in `LaunchNavigator.APP` and the value is a boolean indicating whether the app is available. 535 | - rejected if an error is occurred. Rejected with args: 536 | - {string} - error message 537 | 538 | ### getAppDisplayName() 539 | Returns the display name of the specified app. 540 | 541 | let name = LaunchNavigator.getAppDisplayName(LaunchNavigator.APP.WAZE); 542 | 543 | #### Parameters 544 | - {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 545 | 546 | #### Returns 547 | - {string} - app display name. e.g. "Google Maps". 548 | 549 | ### getAppsForPlatform() 550 | Returns list of supported apps on a given platform. 551 | 552 | let apps = LaunchNavigator.getAppsForPlatform(platform); 553 | 554 | #### Parameters 555 | - {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 556 | 557 | #### Returns 558 | - {array} - apps supported on specified platform as a list of `LaunchNavigator.APP` constants. 559 | 560 | 561 | ### supportsTransportMode() 562 | Indicates if an app on a given platform supports specification of transport mode. 563 | 564 | let isSupported = LaunchNavigator.supportsTransportMode(app, platform, launchMode); 565 | 566 | #### Parameters 567 | - {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 568 | - {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 569 | - {string} launchMode - (optional) Only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 570 | 571 | #### Returns 572 | - {boolean} - true if app/platform(/launch mode) combination supports specification of transport mode. 573 | 574 | ### getTransportModes() 575 | Returns the list of transport modes supported by an app on a given platform. 576 | 577 | let transportModes = LaunchNavigator.getTransportModes(app, platform, launchMode); 578 | 579 | #### Parameters 580 | - {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 581 | - {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 582 | - {string} launchMode - (optional) Only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 583 | 584 | #### Returns 585 | - {boolean} - {array} - list of transports modes as constants in `LaunchNavigator.TRANSPORT_MODE`. 586 | If app/platform(/launch mode) combination doesn't support specification of transport mode, the list will be empty; 587 | 588 | 589 | ### supportsDestName() 590 | Indicates if an app on a given platform supports specification of a custom nickname for destination location. 591 | 592 | let isSupported = LaunchNavigator.supportsDestName(app, platform, launchMode); 593 | 594 | #### Parameters 595 | - {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 596 | - {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 597 | - {string} launchMode - (optional) Applies to Google Maps on Android and Apple Maps on iOS. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 598 | 599 | #### Returns 600 | - {boolean} - true if app/platform(/launch mode) combination supports specification of a custom nickname for destination location. 601 | 602 | 603 | ### supportsStart() 604 | Indicates if an app on a given platform supports specification of start location. 605 | 606 | let isSupported = LaunchNavigator.supportsStart(app, platform, launchMode); 607 | 608 | #### Parameters 609 | - {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 610 | - {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 611 | - {string} launchMode - (optional) Only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 612 | 613 | #### Returns 614 | - {boolean} - true if app/platform(/launch mode) combination supports specification of start location. 615 | 616 | 617 | ### supportsStartName() 618 | Indicates if an app on a given platform supports specification of a custom nickname for start location. 619 | 620 | let isSupported = LaunchNavigator.supportsStartName(app, platform, launchMode); 621 | 622 | #### Parameters 623 | - {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 624 | - {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 625 | - {string} launchMode - (optional) Only applies to Apple Maps on iOS. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPKIT`. 626 | 627 | #### Returns 628 | - {boolean} - true if app/platform(/launch mode) combination supports specification of a custom nickname for start location. 629 | 630 | ### supportsLaunchMode() 631 | Indicates if an app on a given platform supports specification of launch mode. 632 | - Currently only Google Maps on Android and Apple Maps on iOS supports this. 633 | 634 | let isSupported = LaunchNavigator.supportsLaunchMode(app, platform); 635 | 636 | #### Parameters 637 | - {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 638 | - {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.ANDROID`. 639 | 640 | #### Returns 641 | - {boolean} - true if app/platform combination supports specification of launch mode. 642 | 643 | ### enableDebug() 644 | Enables debug log output from the module to the JS and native consoles. By default debug is disabled. 645 | 646 | LaunchNavigator.enableDebug(true); 647 | 648 | #### Parameters 649 | - {boolean} enabled - Whether to enable debug. 650 | 651 | ### setGoogleApiKey() 652 | Enables specification of the Google API key to use for accessing Google's Geocoding API. 653 | If you fail to set this on Android before attempting to use this module to launch a navigation app which requires a lat/lon coordinates as input, the module will raise an error if the input location is an address because it requires geocoding to a lat/lon coordinate. 654 | See [Google API key for Android](#google-api-key-for-android) for more information. 655 | 656 | Android only. Calling on iOS will have no effect. 657 | 658 | LaunchNavigator.setGoogleApiKey("your_api_key"); 659 | 660 | #### Parameters 661 | - {boolean} enabled - Whether to enable debug. 662 | 663 | # Example project 664 | 665 | The example project can be used to build and run a React Native app for Android & iOS: 666 | 667 | https://github.com/dpa99c/react-native-launch-navigator-example 668 | 669 | It demonstrates how this module can be used and validates its functionality. 670 | 671 | # Platform-specifics 672 | 673 | ## Android 674 | 675 | ### Google API key for Android 676 | - On Android, this module uses [Google's Geocoding API](https://developers.google.com/maps/documentation/geocoding/intro) to geocode input addresses to lat/lon coordinates in order to support navigation apps which only allow input locations to be specified as lat/lon coordinates. 677 | - Google now requires that an API key be specified in order to use the Geocoding API, so you'll need to obtain an API key and specify it via [`setGoogleApiKey()`](#setgoogleapikey). 678 | - For more information on how to obtain an API key, see the [Google documentation](https://developers.google.com/maps/documentation/geocoding/get-api-key). 679 | 680 | ### `geo:` URI scheme 681 | - Running on Android, in addition to discovering which explicitly supported apps are installed, the module will also detect which installed apps support using the `geo:` URI scheme for use in navigation. 682 | These are returned in the list of available apps. 683 | 684 | - By specifying the `app` option as `LaunchNavigator.APP.GEO`, the module will invoke a native Android chooser, to allow the user to select an app which supports the `geo:` URI scheme for navigation. 685 | 686 | 687 | ### Google Maps launch modes 688 | Google Maps on Android can be launched using 3 launch modes by specifying the `launchMode` option as a `LaunchNavigator.LAUNCH_MODE` constant to `navigate()`: 689 | 690 | - Maps mode (`LaunchNavigator.LAUNCH_MODE.MAPS`) - launches in Map view. Enables start location to be specified, but not transport mode or destination name. Default if not specified. 691 | - Turn-by-turn mode (`LaunchNavigator.LAUNCH_MODE.TURN_BY_TURN`) - launches in Navigation view. Enables transport mode to be specified, but not start location or destination name. 692 | - Geo mode (`LaunchNavigator.LAUNCH_MODE.GEO`) - invokes Navigation view via `geo`: URI scheme. Enables destination name to be specified, but not start location or transport mode. 693 | 694 | 695 | ## iOS 696 | 697 | ### "Removing" Apple Maps 698 | - Since iOS 10, it is possible to "remove" built-in Apple apps, including Maps, from the Home screen. 699 | - Not that removing is not the same as uninstalling - the app is still actually present on the device, just the icon is removed from the Home screen. 700 | - Therefore it's not possible detect if Apple Maps is unavailable - `LaunchNavigator.availableApps()` will always report it as present. 701 | - The best that can be done is to gracefully handle the error when attempting to open Apple Maps using `LaunchNavigator.navigate()` 702 | - For reference, see [this SO question](http://stackoverflow.com/questions/39603120/how-to-check-if-apple-maps-is-installed) and the [Apple documentation](https://support.apple.com/en-gb/HT204221). 703 | 704 | ### Apple Maps launch modes 705 | 706 | Apple Maps app on iOS can be launched using 2 launch methods by specifying the `launchMode` option as a `LaunchNavigator.LAUNCH_MODE` constant to `navigate()`: 707 | - `LaunchNavigator.LAUNCH_MODE.URI_SCHEME`: use the URI scheme launch method. Default if not specified. 708 | - `LaunchNavigator.LAUNCH_MODE.MAPKIT`: use the MapKit class launch method. 709 | 710 | #### URI scheme launch method 711 | - Launches the app using the [Apple Maps URI scheme](https://developer.apple.com/library/content/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html) 712 | - The default method used by the module. 713 | - Supports input location types of both coordinates and address string without requiring remote geocoding service (works offline) 714 | - Doesn't support specifying nicknames for start/destination locations. 715 | 716 | #### MapKit class launch method 717 | - Launches the app using the [MapKit class](https://developer.apple.com/documentation/mapkit/mkmapitem/1452207-openmapswithitems?language=objc) to launch Apple Maps 718 | - Only supports input location type of coordinates without requiring remote geocoding service (works offline) 719 | - An input location type of an address (formatted as a single string) requires use of remote geocoding service (requires internet connection) 720 | - MapKit class input requires an address which is formatted as an [address dictionary](https://developer.apple.com/documentation/contacts/cnpostaladdress), in which the address is split into known fields such as street, city and state. 721 | - Support specifying nicknames for start/destination locations. 722 | - Provides [additional launch options](https://developer.apple.com/documentation/mapkit/mkmapitem/launch_options_dictionary_keys?language=objc) which are not available via the URI scheme launch method. 723 | 724 | # App-specifics 725 | 726 | ## Lyft 727 | 728 | On both Android and iOS, the "ride type" will default to "Lyft" unless otherwise specified in the `extras` list as `id`. 729 | 730 | See the [Lyft documentation](https://developer.lyft.com/v1/docs/deeplinking) for URL scheme details and other supported ride types. 731 | 732 | ## 99 Taxi 733 | On both Android and iOS, the extra parameters `client_id` and `deep_link_product_id` are required by 99 Taxi 734 | 735 | - `client_id` should follow the pattern `MAP_***` where `***` is the client name given by the 99 Team. 736 | - If not specified defaults to `client_id=MAP_123` 737 | - `deep_link_product_id` identifies the ride category 738 | - Currently supported values are: 739 | - `316` - POP ride 740 | - `326` - TOP ride 741 | - `327` - Taxis ride 742 | - If not specified defaults to `deep_link_product_id=316` 743 | 744 | On Android, 99 Taxi is currently the only app where `options.start` is a **required** parameter when calling `navigate()` 745 | - If `navigate()` is called without a start location and the selected app is 99 Taxi, the error callback will be invoked and the 99 Taxi app will not be launched 746 | - In order for this module to automatically provide start location to 99 Taxi (if it's not already specified), the native Android implementation needs to be enhanced to: 747 | - check/request runtime permission to use location 748 | - add the necessary permission entries to the `AndroidManifest.xml` 749 | - check/request high accuracy location is enabled (no point in requesting a low-accuracy city-level position if you want a pickup at your exact current address) 750 | - request a high accuracy position to determine the user's current location 751 | - handle errors cases such as: 752 | - User denies location permission 753 | - User denies high accuracy mode permission 754 | - Location cannot be retrieved 755 | - Currently, I don't have time to do all of the above just for the case of 99 Taxi 756 | - However I'm willing to accept a PR request which implements the necessary native Android features. 757 | - Otherwise/until then, you'll need to manually specify the start location for 99 Taxi 758 | 759 | # Reporting issues 760 | 761 | Before reporting issues with this module, please first do the following: 762 | 763 | - Check the existing lists of [open issues](https://github.com/dpa99c/react-native-launch-navigator/issues) and [closed issues](https://github.com/dpa99c/react-native-launch-navigator/issues?q=is%3Aissue+is%3Aclosed) 764 | - Also check the [list of issues for this module's sister Cordova plugin](https://github.com/dpa99c/phonegap-launch-navigator) as it's been around longer and native issues apply equally to this React Native module. 765 | - Check your target country is supported for turn-by-turn by the native navigation app 766 | - [Apple Maps country list for iOS](https://www.apple.com/ios/feature-availability/#maps-turn-by-turn-navigation) 767 | - [Google Maps country list for Android](https://support.google.com/gmm/answer/3137767?hl=en-GB) 768 | - If possible, test using the [example project](https://github.com/dpa99c/react-native-launch-navigator-example) to eliminate the possibility of a bug in your code rather than the module. 769 | 770 | 771 | When reporting issues, please give the following information: 772 | 773 | - A clear description of the problem 774 | 775 | - OS version(s) and device (or emulator) model(s) on which the problem was observed 776 | 777 | - Code example of calling the module which results in the observed issue 778 | 779 | - Example parameters (locations or place names) which results in the observed issue 780 | 781 | **Issues which fail to give a clear description of the problem as described above will be closed immediately** 782 | 783 | License 784 | ================ 785 | 786 | The MIT License 787 | 788 | Copyright (c) 2018 Dave Alden (Working Edge Ltd.) 789 | 790 | Permission is hereby granted, free of charge, to any person obtaining a copy 791 | of this software and associated documentation files (the "Software"), to deal 792 | in the Software without restriction, including without limitation the rights 793 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 794 | copies of the Software, and to permit persons to whom the Software is 795 | furnished to do so, subject to the following conditions: 796 | 797 | The above copyright notice and this permission notice shall be included in 798 | all copies or substantial portions of the Software. 799 | 800 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 801 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 802 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 803 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 804 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 805 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 806 | THE SOFTWARE. 807 | -------------------------------------------------------------------------------- /RNLaunchNavigator.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = "RNLaunchNavigator" 7 | s.version = package['version'] 8 | s.summary = package['description'] 9 | s.license = package['license'] 10 | 11 | s.authors = package['author'] 12 | s.homepage = package['repository']['url'] 13 | s.platform = :ios, "9.0" 14 | s.ios.deployment_target = '9.0' 15 | s.tvos.deployment_target = '10.0' 16 | 17 | s.source = { :git => "https://github.com/dpa99c/react-native-launch-navigator.git", :tag => "v#{s.version}" } 18 | s.source_files = "ios/**/*.{h,m}" 19 | 20 | s.dependency 'React' 21 | end -------------------------------------------------------------------------------- /RNLogger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import { NativeModule, NativeEventEmitter } from 'react-native'; 3 | 4 | export default class RNLogger { 5 | nativeModule; 6 | 7 | /******************** 8 | * Internal functions 9 | ********************/ 10 | _addListeners() { 11 | const customModuleEmitter = new NativeEventEmitter(this.nativeModule); 12 | customModuleEmitter.addListener('console.error', this._error.bind(this)); 13 | customModuleEmitter.addListener('console.warn', this._warn.bind(this)); 14 | customModuleEmitter.addListener('console.info', this._info.bind(this)); 15 | customModuleEmitter.addListener('console.log', this._log.bind(this)); 16 | customModuleEmitter.addListener('console.debug', this._debug.bind(this)); 17 | } 18 | 19 | _createLogStatementFromEvent(ev){ 20 | return ev.logTag + ": " + ev.message; 21 | } 22 | 23 | _error(ev){ 24 | console.log(this._createLogStatementFromEvent(ev)); 25 | } 26 | 27 | _warn(ev){ 28 | console.warn(this._createLogStatementFromEvent(ev)); 29 | } 30 | 31 | _info(ev){ 32 | console.info(this._createLogStatementFromEvent(ev)); 33 | } 34 | 35 | _log(ev){ 36 | console.log(this._createLogStatementFromEvent(ev)); 37 | } 38 | 39 | _debug(ev){ 40 | console.debug(this._createLogStatementFromEvent(ev)); 41 | } 42 | 43 | /************ 44 | * Public API 45 | ************/ 46 | constructor(nativeModule) { 47 | this.nativeModule = nativeModule; 48 | this._addListeners(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /android.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import {NativeModules} from 'react-native'; 4 | let ln = require('./constants'); 5 | 6 | /********************* 7 | * Internal properties 8 | *********************/ 9 | let RNLaunchNavigator = NativeModules.RNLaunchNavigator; 10 | 11 | /****************** 12 | * Public Constants 13 | ******************/ 14 | 15 | /** 16 | * Launch modes supported by Google Maps on Android 17 | * @type {object} 18 | */ 19 | ln.LAUNCH_MODE = { 20 | MAPS: "maps", 21 | TURN_BY_TURN: "turn-by-turn", 22 | GEO: "geo" 23 | }; 24 | 25 | // Add the Android-specific option to pass in for geo: protocol, letting the native app chooser decide. 26 | ln.APP.GEO = "geo"; 27 | ln.SUPPORTS_DEST_NAME[ln.PLATFORM.ANDROID].push(ln.APP.GEO); 28 | ln.APPS_BY_PLATFORM[ln.PLATFORM.ANDROID].splice(1, 0, ln.APP.GEO); //insert at [1] below [User select] 29 | ln.APP_NAMES[ln.APP.GEO] = "Other navigation apps"; 30 | 31 | /******************** 32 | * Internal functions 33 | ********************/ 34 | var _constructor = function () { 35 | discoverGeoApps(); 36 | }; 37 | 38 | // Add apps that support the geo: protocol 39 | var discoverGeoApps = function (){ 40 | RNLaunchNavigator.getGeoApps().then((supportedApps) => { 41 | for(var appName in supportedApps){ 42 | var packageName = supportedApps[appName]; 43 | ln.APP[appName.toUpperCase().replace(" ","_")] = packageName; 44 | ln.APP_NAMES[packageName] = appName; 45 | ln.APPS_BY_PLATFORM[ln.PLATFORM.ANDROID].push(packageName); 46 | ln.SUPPORTS_DEST_NAME[ln.PLATFORM.ANDROID].push(packageName); 47 | } 48 | }); 49 | }; 50 | 51 | /****************** 52 | * Public API 53 | ******************/ 54 | 55 | 56 | /** 57 | * Opens navigator app to navigate to given destination, specified by either place name or lat/lon. 58 | * If a start location is not also specified, current location will be used for the start. 59 | * 60 | * @param {string/number[]} destination (required) - destination location to use for navigation. 61 | * Either: 62 | * - a {string} containing the address. e.g. "Buckingham Palace, London" 63 | * - an {array}, where the first element is the latitude and the second element is a longitude, as decimal numbers. e.g. [50.1, -4.0] 64 | * 65 | * @param {object} options (optional) - optional parameters: 66 | * 67 | * - {string} app - navigation app to use for directions, as a constant. e.g. LaunchNavigator.APP.WAZE 68 | * If not specified, defaults to Google Maps. 69 | * 70 | * - {string} destinationName - nickname to display in app for destination. e.g. "Bob's House". 71 | * 72 | * - {mixed} start - start location to use for navigation. If not specified, the current location of the device will be used. 73 | * Either: 74 | * - a {string} containing the address. e.g. "Buckingham Palace, London" 75 | * - a {string} containing a latitude/longitude coordinate. e.g. "50.1. -4.0" 76 | * - an {array}, where the first element is the latitude and the second element is a longitude, as decimal numbers. e.g. [50.1, -4.0] 77 | * 78 | * - {string} startName - nickname to display in app for start. e.g. "My Place". 79 | * 80 | * - {string} transportMode - transportation mode for navigation. 81 | * Can only be specified if navigationMode == "turn-by-turn". 82 | * Accepted values are "driving", "walking", "bicycling" or "transit". 83 | * Defaults to "driving" if not specified. 84 | * 85 | * - {string} launchMode - mode in which to open Google Maps app: 86 | * - `LaunchNavigator.LAUNCH_MODE.MAPS` or `LaunchNavigator.LAUNCH_MODE.TURN_BY_TURN` 87 | * - Defaults to `LaunchNavigator.LAUNCH_MODE.MAPS` if not specified. 88 | * 89 | * - {object} extras - a key/value map of extra app-specific parameters. For example, to tell Google Maps to display Satellite view in "maps" launch mode: `{"t": "k"}` 90 | * 91 | * - {string} appSelectionDialogHeader - text to display in the native picker which enables user to select which navigation app to launch. 92 | * Defaults to "Select app for navigation" if not specified. 93 | * 94 | * - {string} appSelectionCancelButton - text to display for the cancel button in the native picker which enables user to select which navigation app to launch. 95 | * Defaults to "Cancel" if not specified. 96 | * 97 | * - {array} appSelectionList - list of apps, defined as `LaunchNavigator.APP` constants, which should be displayed in the picker if the app is available. 98 | * This can be used to restrict which apps are displayed, even if they are installed. By default, all available apps will be displayed. 99 | * 100 | * - {boolean} enableGeocoding - if true, and input location type(s) doesn't match those required by the app, use geocoding to obtain the address/coords as required. Defaults to true. 101 | * 102 | * @return Promise 103 | * resolve - invoke when the navigation app is successfully launched. 104 | * reject - if an error is encountered while launching the app. 105 | * A single string argument containing the error message will be passed. 106 | */ 107 | ln.navigate = function(destination, options) { 108 | options = ln.util.conformNavigateOptions(arguments); 109 | 110 | var dType, sType = "none"; 111 | 112 | // Input validation 113 | var throwError = function(errMsg){ 114 | throw new Error(errMsg); 115 | }; 116 | 117 | if(!destination){ 118 | throwError("No destination was specified"); 119 | } 120 | 121 | if(options.extras && typeof options.extras !== "object"){ 122 | throwError("'options.extras' must be a key/value object"); 123 | } 124 | 125 | options.enableGeocoding = typeof options.enableGeocoding !== "undefined" ? options.enableGeocoding : true; 126 | 127 | destination = ln.util.extractCoordsFromLocationString(destination); 128 | if(typeof(destination) === "object"){ 129 | if(typeof destination.length === "undefined") throw "destination must be a string or an array"; 130 | dType = "pos"; 131 | }else{ 132 | dType = "name"; 133 | } 134 | 135 | if(options.start){ 136 | options.start = ln.util.extractCoordsFromLocationString(options.start); 137 | if(typeof(options.start) === "object"){ 138 | if(typeof options.start.length === "undefined") throw "start must be a string or an array"; 139 | sType = "pos"; 140 | }else{ 141 | sType = "name"; 142 | } 143 | } 144 | 145 | var transportMode = null; 146 | if(options.transportMode){ 147 | ln.util.validateTransportMode(options.transportMode); 148 | transportMode = options.transportMode.charAt(0); 149 | } 150 | 151 | // Default to Google Maps if not specified 152 | if(!options.app) options.app = ln.APP.GOOGLE_MAPS; 153 | ln.util.validateApp(options.app); 154 | 155 | if(!options.launchMode) options.launchMode = ln.LAUNCH_MODE.MAPS; 156 | ln.util.validateLaunchMode(options.launchMode); 157 | 158 | if(options.extras) options.extras = JSON.stringify(options.extras); 159 | 160 | return RNLaunchNavigator.navigate({ 161 | app: options.app, 162 | dType: dType, 163 | dest: destination, 164 | destNickname: options.destinationName, 165 | sType: sType, 166 | start: options.start, 167 | startNickname: options.startName, 168 | transportMode: transportMode, 169 | launchMode: options.launchMode, 170 | extras: options.extras, 171 | enableGeocoding: options.enableGeocoding 172 | }); 173 | }; 174 | 175 | 176 | /** 177 | * Indicates if an app on a given platform supports specification of transport mode. 178 | * Android-specific implementation supports additional specification of launch mode. 179 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 180 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 181 | * @param {string} launchMode (optional) - only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 182 | * @return {boolean} - true if app/platform combination supports specification of transport mode. 183 | */ 184 | ln.supportsTransportMode = function(app, platform, launchMode){ 185 | ln.util.validateApp(app); 186 | ln.util.validatePlatform(platform); 187 | 188 | var result; 189 | if(launchMode && platform === ln.PLATFORM.ANDROID && app === ln.APP.GOOGLE_MAPS){ 190 | ln.util.validateLaunchMode(launchMode); 191 | result = launchMode === ln.LAUNCH_MODE.TURN_BY_TURN; 192 | }else{ 193 | result = ln._supportsTransportMode(app, platform); 194 | } 195 | return result; 196 | }; 197 | 198 | /** 199 | * Returns the list of transport modes supported by an app on a given platform. 200 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 201 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 202 | * @param {string} launchMode (optional) - only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 203 | * @return {string[]} - list of transports modes as constants in `LaunchNavigator.TRANSPORT_MODE`. 204 | * If app/platform combination doesn't support specification of transport mode, the list will be empty; 205 | */ 206 | ln.getTransportModes = function(app, platform, launchMode){ 207 | if(ln.supportsTransportMode(app, platform, launchMode)){ 208 | return ln.TRANSPORT_MODES[platform][app]; 209 | } 210 | return []; 211 | }; 212 | 213 | /** 214 | * Indicates if an app on a given platform supports specification of start location. 215 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 216 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 217 | * @param {string} launchMode (optional) - only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 218 | * @return {boolean} - true if app/platform combination supports specification of start location. 219 | */ 220 | ln.supportsStart = function(app, platform, launchMode){ 221 | ln.util.validateApp(app); 222 | ln.util.validatePlatform(platform); 223 | 224 | let result; 225 | if(launchMode && platform === ln.PLATFORM.ANDROID && app === ln.APP.GOOGLE_MAPS){ 226 | ln.util.validateLaunchMode(launchMode); 227 | result = launchMode === ln.LAUNCH_MODE.MAPS; 228 | }else{ 229 | result = ln._supportsStart(app, platform); 230 | } 231 | return result; 232 | }; 233 | 234 | 235 | /** 236 | * Indicates if an app on a given platform supports specification of a custom nickname for destination location. 237 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 238 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 239 | * @param {string} launchMode (optional) - only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 240 | * @return {boolean} - true if app/platform combination supports specification of destination location. 241 | */ 242 | ln.supportsDestName = function(app, platform, launchMode){ 243 | ln.util.validateApp(app); 244 | ln.util.validatePlatform(platform); 245 | let result; 246 | if(launchMode && platform === ln.PLATFORM.ANDROID && app === ln.APP.GOOGLE_MAPS){ 247 | ln.util.validateLaunchMode(launchMode); 248 | result = launchMode === ln.LAUNCH_MODE.GEO; 249 | }else{ 250 | result = ln._supportsDestName(app, platform); 251 | } 252 | return result; 253 | }; 254 | 255 | // Map directly to public API 256 | ln.supportsStartName = function() { 257 | ln._supportsStartName.apply(this, arguments); 258 | }; 259 | 260 | /** 261 | * Sets the Google API key to use for the Google Geocoder API on Android. 262 | * @param {string} googleApiKey - the API key to use for the Geocoder API on Android. 263 | */ 264 | ln.setGoogleApiKey = RNLaunchNavigator.setGoogleApiKey; 265 | 266 | /************ 267 | * Bootstrap 268 | ************/ 269 | _constructor(); 270 | 271 | /************ 272 | * Export 273 | ************/ 274 | module.exports = ln; -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | def DEFAULT_COMPILE_SDK_VERSION = 27 4 | def DEFAULT_BUILD_TOOLS_VERSION = "27" 5 | def DEFAULT_MIN_SDK_VERSION = 4 6 | def DEFAULT_OK_HTTP_VERSION = "3.10.0" 7 | 8 | android { 9 | compileSdkVersion project.hasProperty('compileSdkVersion') ? project.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION 10 | buildToolsVersion project.hasProperty('buildToolsVersion') ? project.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION 11 | 12 | defaultConfig { 13 | minSdkVersion project.hasProperty('minSdkVersion') ? project.minSdkVersion : DEFAULT_MIN_SDK_VERSION 14 | } 15 | } 16 | 17 | dependencies { 18 | def okHttpVersion = project.hasProperty('okHttpVersion') ? project.okHttpVersion : DEFAULT_OK_HTTP_VERSION 19 | 20 | implementation 'com.facebook.react:react-native:+' 21 | implementation "com.squareup.okhttp3:okhttp:$okHttpVersion" 22 | } 23 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/src/main/java/uk/co/workingedge/ILogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Dave Alden (http://github.com/dpa99c) 3 | * Copyright (c) 2018 Working Edge Ltd. (http://www.workingedge.co.uk) 4 | * 5 | * Permission is hereby granted, free of charge, to any person 6 | * obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without 8 | * restriction, including without limitation the rights to use, 9 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following 12 | * conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | * OTHER DEALINGS IN THE SOFTWARE. 25 | * 26 | */ 27 | package uk.co.workingedge; 28 | 29 | public interface ILogger { 30 | public void setEnabled(boolean enabled); 31 | public boolean getEnabled(); 32 | public void error(String msg); 33 | public void warn(String msg); 34 | public void info(String msg); 35 | public void debug(String msg); 36 | public void verbose(String msg); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /android/src/main/java/uk/co/workingedge/RNLaunchNavigator/RNLaunchNavigatorModule.java: -------------------------------------------------------------------------------- 1 | package uk.co.workingedge.RNLaunchNavigator; 2 | 3 | import android.util.Log; 4 | 5 | import com.facebook.react.bridge.Arguments; 6 | import com.facebook.react.bridge.Promise; 7 | import com.facebook.react.bridge.ReactApplicationContext; 8 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 9 | import com.facebook.react.bridge.ReactMethod; 10 | import com.facebook.react.bridge.ReadableMap; 11 | import com.facebook.react.bridge.WritableMap; 12 | 13 | import org.json.JSONObject; 14 | 15 | import java.util.Map; 16 | import java.util.HashMap; 17 | 18 | import uk.co.workingedge.LaunchNavigator; 19 | 20 | public class RNLaunchNavigatorModule extends ReactContextBaseJavaModule { 21 | private static final String NATIVE = "[native]"; 22 | private static final String MODULE_NAME = "RNLaunchNavigator"; 23 | private static final String LOG_TAG = MODULE_NAME+NATIVE; 24 | private static final String ERROR_CODE_EXCEPTION = "EXCEPTION"; 25 | private static final String ERROR_CODE_ERROR = "ERROR"; 26 | 27 | private LaunchNavigator launchNavigator = null; 28 | private RNLogger logger = null; 29 | 30 | 31 | public RNLaunchNavigatorModule(ReactApplicationContext reactContext) { 32 | super(reactContext); 33 | try { 34 | logger = new RNLogger(reactContext, LOG_TAG); 35 | launchNavigator = new LaunchNavigator(getReactApplicationContext(), new RNLogger(reactContext, LaunchNavigator.LOG_TAG+NATIVE)); 36 | }catch (Exception e){ 37 | Log.e(MODULE_NAME, "Exception initializing :"+e.getMessage()); 38 | } 39 | } 40 | 41 | /************ 42 | * Overrides 43 | ************/ 44 | @Override 45 | public String getName() { 46 | return MODULE_NAME; 47 | } 48 | 49 | @Override 50 | public Map getConstants() { 51 | final Map constants = new HashMap<>(); 52 | constants.put("LOG_TAG", LOG_TAG); 53 | return constants; 54 | } 55 | 56 | /********************* 57 | * Module API methods 58 | *********************/ 59 | @ReactMethod 60 | public void setGoogleApiKey(final String googleApiKey){ 61 | this.launchNavigator.setGoogleApiKey(googleApiKey); 62 | } 63 | 64 | @ReactMethod 65 | public void enableDebug(final Boolean enabled){ 66 | this.logger.setEnabled(enabled); 67 | this.launchNavigator.getLogger().setEnabled(enabled); 68 | } 69 | 70 | @ReactMethod 71 | public void getGeoApps(Promise promise){ 72 | try{ 73 | logger.debug("getGeoApps"); 74 | JSONObject oApps = launchNavigator.getGeoApps(); 75 | ReadableMap mApps = RNUtils.convertJsonToMap(oApps); 76 | promise.resolve(mApps); 77 | }catch (Exception e){ 78 | handleExceptionWithPromise(promise, e); 79 | } 80 | } 81 | 82 | @ReactMethod 83 | public void getAvailableApps(Promise promise){ 84 | try{ 85 | logger.debug("getAvailableApps"); 86 | launchNavigator.discoverAvailableApps(); 87 | JSONObject oApps = launchNavigator.getAvailableApps(); 88 | ReadableMap mApps = RNUtils.convertJsonToMap(oApps); 89 | promise.resolve(mApps); 90 | }catch (Exception e){ 91 | handleExceptionWithPromise(promise, e); 92 | } 93 | } 94 | 95 | @ReactMethod 96 | public void isAppAvailable(String appName, Promise promise){ 97 | try{ 98 | logger.debug("isAppAvailable"); 99 | boolean available = launchNavigator.isAppAvailable(appName); 100 | promise.resolve(available); 101 | }catch (Exception e){ 102 | handleExceptionWithPromise(promise, e); 103 | } 104 | } 105 | 106 | @ReactMethod 107 | public void navigate(ReadableMap args, Promise promise){ 108 | try{ 109 | logger.debug("navigate"); 110 | String error = launchNavigator.navigate(RNUtils.convertMapToJson(args)); 111 | if(error == null){ 112 | promise.resolve(true); 113 | }else{ 114 | promise.reject(ERROR_CODE_ERROR, error); 115 | } 116 | } catch (Exception e){ 117 | handleExceptionWithPromise(promise, e); 118 | } 119 | } 120 | 121 | /****************** 122 | * Internal methods 123 | ******************/ 124 | 125 | private void handleExceptionWithPromise(Promise promise, Exception e){ 126 | promise.reject(ERROR_CODE_EXCEPTION, e); 127 | } 128 | } -------------------------------------------------------------------------------- /android/src/main/java/uk/co/workingedge/RNLaunchNavigator/RNLaunchNavigatorPackage.java: -------------------------------------------------------------------------------- 1 | package uk.co.workingedge.RNLaunchNavigator; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.NativeModule; 5 | import com.facebook.react.bridge.ReactApplicationContext; 6 | import com.facebook.react.uimanager.ViewManager; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | public class RNLaunchNavigatorPackage implements ReactPackage { 13 | 14 | @Override 15 | public List createViewManagers(ReactApplicationContext reactContext) { 16 | return Collections.emptyList(); 17 | } 18 | 19 | @Override 20 | public List createNativeModules( 21 | ReactApplicationContext reactContext) { 22 | List modules = new ArrayList<>(); 23 | 24 | modules.add(new RNLaunchNavigatorModule(reactContext)); 25 | 26 | return modules; 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /android/src/main/java/uk/co/workingedge/RNLaunchNavigator/RNLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Dave Alden (http://github.com/dpa99c) 3 | * Copyright (c) 2018 Working Edge Ltd. (http://www.workingedge.co.uk) 4 | * 5 | * Permission is hereby granted, free of charge, to any person 6 | * obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without 8 | * restriction, including without limitation the rights to use, 9 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following 12 | * conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | * OTHER DEALINGS IN THE SOFTWARE. 25 | * 26 | */ 27 | package uk.co.workingedge.RNLaunchNavigator; 28 | 29 | import uk.co.workingedge.ILogger; 30 | import android.util.Log; 31 | import com.facebook.react.bridge.Arguments; 32 | import com.facebook.react.bridge.ReactContext; 33 | import com.facebook.react.bridge.WritableMap; 34 | import com.facebook.react.modules.core.DeviceEventManagerModule; 35 | 36 | public class RNLogger implements ILogger { 37 | 38 | /********************** 39 | * Internal properties 40 | **********************/ 41 | private boolean enabled = false; 42 | private ReactContext reactContext; 43 | private String logTag; 44 | 45 | /******************* 46 | * Constructors 47 | *******************/ 48 | public RNLogger(ReactContext reactContext, String logTag) { 49 | initialize(reactContext, logTag); 50 | } 51 | 52 | public RNLogger(ReactContext reactContext, String logTag, boolean enabled) { 53 | initialize(reactContext, logTag); 54 | setEnabled(enabled); 55 | } 56 | 57 | /******************* 58 | * Public API 59 | *******************/ 60 | @Override 61 | public void setEnabled(boolean enabled){ 62 | this.enabled = enabled; 63 | } 64 | 65 | @Override 66 | public boolean getEnabled(){ 67 | return this.enabled; 68 | } 69 | 70 | @Override 71 | public void error(String msg) { 72 | Log.e(logTag, msg); 73 | logToReactConsole(msg, "error"); 74 | } 75 | 76 | @Override 77 | public void warn(String msg) { 78 | Log.w(logTag, msg); 79 | logToReactConsole(msg, "warn"); 80 | } 81 | 82 | @Override 83 | public void info(String msg) { 84 | Log.i(logTag, msg); 85 | logToReactConsole(msg, "info"); 86 | } 87 | 88 | @Override 89 | public void debug(String msg) { 90 | Log.d(logTag, msg); 91 | logToReactConsole(msg, "log"); 92 | } 93 | 94 | @Override 95 | public void verbose(String msg) { 96 | Log.v(logTag, msg); 97 | logToReactConsole(msg, "debug"); 98 | } 99 | 100 | /******************* 101 | * Internal methods 102 | *******************/ 103 | private void initialize(ReactContext reactContext, String logTag){ 104 | this.reactContext = reactContext; 105 | this.logTag = logTag; 106 | } 107 | 108 | private void logToReactConsole(String message, String logLevel){ 109 | if(reactContext.hasActiveCatalystInstance() && enabled){ 110 | WritableMap map = Arguments.createMap(); 111 | map.putString("logTag", logTag); 112 | map.putString("message", message); 113 | reactContext 114 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) 115 | .emit("console."+logLevel, map); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /android/src/main/java/uk/co/workingedge/RNLaunchNavigator/RNUtils.java: -------------------------------------------------------------------------------- 1 | package uk.co.workingedge.RNLaunchNavigator; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.facebook.react.bridge.Arguments; 6 | import com.facebook.react.bridge.ReadableArray; 7 | import com.facebook.react.bridge.ReadableMap; 8 | import com.facebook.react.bridge.ReadableMapKeySetIterator; 9 | import com.facebook.react.bridge.ReadableType; 10 | import com.facebook.react.bridge.WritableArray; 11 | import com.facebook.react.bridge.WritableMap; 12 | import com.facebook.react.bridge.WritableNativeArray; 13 | import com.facebook.react.bridge.WritableNativeMap; 14 | 15 | import org.json.JSONArray; 16 | import org.json.JSONException; 17 | import org.json.JSONObject; 18 | 19 | import java.util.Iterator; 20 | 21 | /** 22 | * @author Mihovil Kovačević 23 | * @since 03-27-2017 24 | */ 25 | public class RNUtils { 26 | /** 27 | * 28 | * @param jsonObject 29 | * @return map 30 | * @throws JSONException 31 | */ 32 | public static WritableMap convertJsonToMap(JSONObject jsonObject) throws JSONException { 33 | WritableMap map = new WritableNativeMap(); 34 | 35 | Iterator iterator = jsonObject.keys(); 36 | while (iterator.hasNext()) { 37 | String key = iterator.next(); 38 | Object value = jsonObject.get(key); 39 | if (value instanceof JSONObject) { 40 | map.putMap(key, convertJsonToMap((JSONObject) value)); 41 | } else if (value instanceof JSONArray) { 42 | map.putArray(key, convertJsonToArray((JSONArray) value)); 43 | } else if (value instanceof Boolean) { 44 | map.putBoolean(key, (Boolean) value); 45 | } else if (value instanceof Integer) { 46 | map.putInt(key, (Integer) value); 47 | } else if (value instanceof Double) { 48 | map.putDouble(key, (Double) value); 49 | } else if (value instanceof String) { 50 | map.putString(key, (String) value); 51 | } else { 52 | map.putString(key, value.toString()); 53 | } 54 | } 55 | return map; 56 | } 57 | 58 | /** 59 | * 60 | * @param jsonArray 61 | * @return 62 | * @throws JSONException 63 | */ 64 | public static WritableArray convertJsonToArray(JSONArray jsonArray) throws JSONException { 65 | WritableArray array = new WritableNativeArray(); 66 | 67 | for (int i = 0; i < jsonArray.length(); i++) { 68 | Object value = jsonArray.get(i); 69 | if (value instanceof JSONObject) { 70 | array.pushMap(convertJsonToMap((JSONObject) value)); 71 | } else if (value instanceof JSONArray) { 72 | array.pushArray(convertJsonToArray((JSONArray) value)); 73 | } else if (value instanceof Boolean) { 74 | array.pushBoolean((Boolean) value); 75 | } else if (value instanceof Integer) { 76 | array.pushInt((Integer) value); 77 | } else if (value instanceof Double) { 78 | array.pushDouble((Double) value); 79 | } else if (value instanceof String) { 80 | array.pushString((String) value); 81 | } else { 82 | array.pushString(value.toString()); 83 | } 84 | } 85 | return array; 86 | } 87 | 88 | /** 89 | * 90 | * @param readableMap 91 | * @return 92 | * @throws JSONException 93 | */ 94 | public static JSONObject convertMapToJson(ReadableMap readableMap) throws JSONException { 95 | JSONObject object = new JSONObject(); 96 | ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); 97 | while (iterator.hasNextKey()) { 98 | String key = iterator.nextKey(); 99 | switch (readableMap.getType(key)) { 100 | case Null: 101 | object.put(key, JSONObject.NULL); 102 | break; 103 | case Boolean: 104 | object.put(key, readableMap.getBoolean(key)); 105 | break; 106 | case Number: 107 | object.put(key, readableMap.getDouble(key)); 108 | break; 109 | case String: 110 | object.put(key, readableMap.getString(key)); 111 | break; 112 | case Map: 113 | object.put(key, convertMapToJson(readableMap.getMap(key))); 114 | break; 115 | case Array: 116 | object.put(key, convertArrayToJson(readableMap.getArray(key))); 117 | break; 118 | } 119 | } 120 | return object; 121 | } 122 | 123 | /** 124 | * 125 | * @param readableArray 126 | * @return 127 | * @throws JSONException 128 | */ 129 | public static JSONArray convertArrayToJson(ReadableArray readableArray) throws JSONException { 130 | JSONArray array = new JSONArray(); 131 | for (int i = 0; i < readableArray.size(); i++) { 132 | switch (readableArray.getType(i)) { 133 | case Null: 134 | break; 135 | case Boolean: 136 | array.put(readableArray.getBoolean(i)); 137 | break; 138 | case Number: 139 | array.put(readableArray.getDouble(i)); 140 | break; 141 | case String: 142 | array.put(readableArray.getString(i)); 143 | break; 144 | case Map: 145 | array.put(convertMapToJson(readableArray.getMap(i))); 146 | break; 147 | case Array: 148 | array.put(convertArrayToJson(readableArray.getArray(i))); 149 | break; 150 | } 151 | } 152 | return array; 153 | } 154 | 155 | /** 156 | * 157 | * @param readableArray 158 | * @return WritableArray 159 | */ 160 | public static WritableArray convertReadableArrayToWritableArray(@Nullable ReadableArray readableArray) { 161 | WritableArray array = Arguments.createArray(); 162 | if(null == readableArray) { 163 | return array; 164 | } 165 | for(int i = 0; i < readableArray.size(); i++) { 166 | ReadableType type = readableArray.getType(i); 167 | switch (type) { 168 | case Null: 169 | continue; 170 | case Boolean: 171 | array.pushBoolean(readableArray.getBoolean(i)); 172 | break; 173 | case Number: 174 | array.pushDouble(readableArray.getDouble(i)); 175 | break; 176 | case String: 177 | array.pushString(readableArray.getString(i)); 178 | break; 179 | case Map: 180 | array.pushMap(convertReadableMapToWritableMap(readableArray.getMap(i))); 181 | break; 182 | case Array: 183 | array.pushArray(convertReadableArrayToWritableArray(readableArray.getArray(i))); 184 | break; 185 | } 186 | } 187 | return array; 188 | } 189 | 190 | /** 191 | * 192 | * @param readableMap 193 | * @return WritableMap 194 | */ 195 | public static WritableMap convertReadableMapToWritableMap(@Nullable ReadableMap readableMap) { 196 | WritableMap map = Arguments.createMap(); 197 | if(null == readableMap) { 198 | return map; 199 | } 200 | ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); 201 | while (iterator.hasNextKey()) { 202 | String key = iterator.nextKey(); 203 | ReadableType type = readableMap.getType(key); 204 | switch (type) { 205 | case Null: 206 | continue; 207 | case Boolean: 208 | map.putBoolean(key, readableMap.getBoolean(key)); 209 | break; 210 | case String: 211 | map.putString(key, readableMap.getString(key)); 212 | break; 213 | case Number: 214 | map.putDouble(key, readableMap.getDouble(key)); 215 | break; 216 | case Map: 217 | map.putMap(key, convertReadableMapToWritableMap(readableMap.getMap(key))); 218 | break; 219 | case Array: 220 | map.putArray(key, convertReadableArrayToWritableArray(readableMap.getArray(key))); 221 | break; 222 | } 223 | } 224 | return map; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /********************* 4 | * Internal properties 5 | *********************/ 6 | let ln = {}; 7 | 8 | /****************** 9 | * Public Constants 10 | ******************/ 11 | 12 | /** 13 | * Supported platforms 14 | * @type {object} 15 | */ 16 | ln.PLATFORM = { 17 | ANDROID: "android", 18 | IOS: "ios" 19 | }; 20 | 21 | /** 22 | * string constants, used to identify apps in native code 23 | * @type {object} 24 | */ 25 | ln.APP = { 26 | APPLE_MAPS: "apple_maps", 27 | GOOGLE_MAPS: "google_maps", 28 | WAZE: "waze", 29 | CITYMAPPER: "citymapper", 30 | NAVIGON: "navigon", 31 | TRANSIT_APP: "transit_app", 32 | YANDEX: "yandex", 33 | UBER: "uber", 34 | TOMTOM: "tomtom", 35 | BING_MAPS: "bing_maps", 36 | SYGIC: "sygic", 37 | HERE_MAPS: "here_maps", 38 | MOOVIT: "moovit", 39 | LYFT: "lyft", 40 | MAPS_ME: "maps_me", 41 | CABIFY: "cabify", 42 | BAIDU: "baidu", 43 | TAXIS_99: "taxis_99", 44 | GAODE: "gaode" 45 | }; 46 | 47 | /** 48 | * Explicitly supported apps by platform 49 | * @type {object} 50 | */ 51 | ln.APPS_BY_PLATFORM = {}; 52 | ln.APPS_BY_PLATFORM[ln.PLATFORM.ANDROID] = [ 53 | ln.APP.GOOGLE_MAPS, 54 | ln.APP.CITYMAPPER, 55 | ln.APP.UBER, 56 | ln.APP.WAZE, 57 | ln.APP.YANDEX, 58 | ln.APP.SYGIC, 59 | ln.APP.HERE_MAPS, 60 | ln.APP.MOOVIT, 61 | ln.APP.LYFT, 62 | ln.APP.MAPS_ME, 63 | ln.APP.CABIFY, 64 | ln.APP.BAIDU, 65 | ln.APP.TAXIS_99, 66 | ln.APP.GAODE 67 | ]; 68 | ln.APPS_BY_PLATFORM[ln.PLATFORM.IOS] = [ 69 | ln.APP.APPLE_MAPS, 70 | ln.APP.GOOGLE_MAPS, 71 | ln.APP.WAZE, 72 | ln.APP.CITYMAPPER, 73 | ln.APP.NAVIGON, 74 | ln.APP.TRANSIT_APP, 75 | ln.APP.YANDEX, 76 | ln.APP.UBER, 77 | ln.APP.TOMTOM, 78 | ln.APP.SYGIC, 79 | ln.APP.HERE_MAPS, 80 | ln.APP.MOOVIT, 81 | ln.APP.LYFT, 82 | ln.APP.MAPS_ME, 83 | ln.APP.CABIFY, 84 | ln.APP.BAIDU, 85 | ln.APP.TAXIS_99, 86 | ln.APP.GAODE 87 | ]; 88 | 89 | /** 90 | * Stock maps app that is always present on each platform 91 | * @type {object} 92 | */ 93 | ln.STOCK_APP = {}; 94 | ln.STOCK_APP[ln.PLATFORM.ANDROID] = ln.APP.GOOGLE_MAPS; 95 | ln.STOCK_APP[ln.PLATFORM.IOS] = ln.APP.APPLE_MAPS; 96 | 97 | /** 98 | * Display names for supported apps 99 | * @type {object} 100 | */ 101 | ln.APP_NAMES = {}; 102 | ln.APP_NAMES[ln.APP.APPLE_MAPS] = "Apple Maps"; 103 | ln.APP_NAMES[ln.APP.GOOGLE_MAPS] = "Google Maps"; 104 | ln.APP_NAMES[ln.APP.WAZE] = "Waze"; 105 | ln.APP_NAMES[ln.APP.CITYMAPPER] = "Citymapper"; 106 | ln.APP_NAMES[ln.APP.NAVIGON] = "Navigon"; 107 | ln.APP_NAMES[ln.APP.TRANSIT_APP] = "Transit App"; 108 | ln.APP_NAMES[ln.APP.YANDEX] = "Yandex Navigator"; 109 | ln.APP_NAMES[ln.APP.UBER] = "Uber"; 110 | ln.APP_NAMES[ln.APP.TOMTOM] = "Tomtom"; 111 | ln.APP_NAMES[ln.APP.BING_MAPS] = "Bing Maps"; 112 | ln.APP_NAMES[ln.APP.SYGIC] = "Sygic"; 113 | ln.APP_NAMES[ln.APP.HERE_MAPS] = "HERE Maps"; 114 | ln.APP_NAMES[ln.APP.MOOVIT] = "Moovit"; 115 | ln.APP_NAMES[ln.APP.LYFT] = "Lyft"; 116 | ln.APP_NAMES[ln.APP.MAPS_ME] = "MAPS.ME"; 117 | ln.APP_NAMES[ln.APP.CABIFY] = "Cabify"; 118 | ln.APP_NAMES[ln.APP.BAIDU] = "Baidu Maps"; 119 | ln.APP_NAMES[ln.APP.TAXIS_99] = "99 Taxi"; 120 | ln.APP_NAMES[ln.APP.GAODE] = "Gaode Maps (Amap)"; 121 | 122 | /** 123 | * All possible transport modes 124 | * @type {object} 125 | */ 126 | ln.TRANSPORT_MODE = { 127 | DRIVING: "driving", 128 | WALKING: "walking", 129 | BICYCLING: "bicycling", 130 | TRANSIT: "transit" 131 | }; 132 | 133 | /** 134 | * Supported transport modes by apps and platform 135 | * @type {object} 136 | */ 137 | ln.TRANSPORT_MODES = {}; 138 | // Android 139 | ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID] = {}; 140 | ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.GOOGLE_MAPS] = [ // Only launchMode=turn-by-turn 141 | ln.TRANSPORT_MODE.DRIVING, 142 | ln.TRANSPORT_MODE.WALKING, 143 | ln.TRANSPORT_MODE.BICYCLING, 144 | ln.TRANSPORT_MODE.TRANSIT 145 | ]; 146 | ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.SYGIC] = [ 147 | ln.TRANSPORT_MODE.DRIVING, 148 | ln.TRANSPORT_MODE.WALKING 149 | ]; 150 | ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.MAPS_ME] = [ 151 | ln.TRANSPORT_MODE.DRIVING, 152 | ln.TRANSPORT_MODE.WALKING, 153 | ln.TRANSPORT_MODE.BICYCLING, 154 | ln.TRANSPORT_MODE.TRANSIT 155 | ]; 156 | ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.BAIDU] = [ 157 | ln.TRANSPORT_MODE.DRIVING, 158 | ln.TRANSPORT_MODE.WALKING, 159 | ln.TRANSPORT_MODE.BICYCLING, 160 | ln.TRANSPORT_MODE.TRANSIT 161 | ]; 162 | ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.GAODE] = [ 163 | ln.TRANSPORT_MODE.DRIVING, 164 | ln.TRANSPORT_MODE.WALKING, 165 | ln.TRANSPORT_MODE.BICYCLING, 166 | ln.TRANSPORT_MODE.TRANSIT 167 | ]; 168 | 169 | // iOS 170 | ln.TRANSPORT_MODES[ln.PLATFORM.IOS] = {}; 171 | ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.GOOGLE_MAPS] = [ 172 | ln.TRANSPORT_MODE.DRIVING, 173 | ln.TRANSPORT_MODE.WALKING, 174 | ln.TRANSPORT_MODE.BICYCLING, 175 | ln.TRANSPORT_MODE.TRANSIT 176 | ]; 177 | ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.APPLE_MAPS] = [ 178 | ln.TRANSPORT_MODE.DRIVING, 179 | ln.TRANSPORT_MODE.WALKING, 180 | ln.TRANSPORT_MODE.TRANSIT 181 | ]; 182 | ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.SYGIC] = [ 183 | ln.TRANSPORT_MODE.DRIVING, 184 | ln.TRANSPORT_MODE.WALKING 185 | ]; 186 | ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.MAPS_ME] = [ 187 | ln.TRANSPORT_MODE.DRIVING, 188 | ln.TRANSPORT_MODE.WALKING, 189 | ln.TRANSPORT_MODE.BICYCLING, 190 | ln.TRANSPORT_MODE.TRANSIT 191 | ]; 192 | ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.BAIDU] = [ 193 | ln.TRANSPORT_MODE.DRIVING, 194 | ln.TRANSPORT_MODE.WALKING, 195 | ln.TRANSPORT_MODE.BICYCLING, 196 | ln.TRANSPORT_MODE.TRANSIT 197 | ]; 198 | ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.GAODE] = [ 199 | ln.TRANSPORT_MODE.DRIVING, 200 | ln.TRANSPORT_MODE.WALKING, 201 | ln.TRANSPORT_MODE.BICYCLING, 202 | ln.TRANSPORT_MODE.TRANSIT 203 | ]; 204 | 205 | /** 206 | * Apps by platform that support specifying a start location 207 | * @type {object} 208 | */ 209 | ln.SUPPORTS_START = {}; 210 | ln.SUPPORTS_START[ln.PLATFORM.ANDROID] = [ 211 | ln.APP.GOOGLE_MAPS, // Only launchMode=maps 212 | ln.APP.CITYMAPPER, 213 | ln.APP.UBER, 214 | ln.APP.YANDEX, 215 | ln.APP.HERE_MAPS, 216 | ln.APP.MOOVIT, 217 | ln.APP.LYFT, 218 | ln.APP.MAPS_ME, 219 | ln.APP.CABIFY, 220 | ln.APP.BAIDU, 221 | ln.APP.TAXIS_99, 222 | ln.APP.GAODE 223 | ]; 224 | ln.SUPPORTS_START[ln.PLATFORM.IOS] = [ 225 | ln.APP.APPLE_MAPS, 226 | ln.APP.GOOGLE_MAPS, 227 | ln.APP.CITYMAPPER, 228 | ln.APP.TRANSIT_APP, 229 | ln.APP.YANDEX, 230 | ln.APP.UBER, 231 | ln.APP.HERE_MAPS, 232 | ln.APP.MOOVIT, 233 | ln.APP.LYFT, 234 | ln.APP.MAPS_ME, 235 | ln.APP.CABIFY, 236 | ln.APP.BAIDU, 237 | ln.APP.TAXIS_99, 238 | ln.APP.GAODE 239 | ]; 240 | /** 241 | * Apps by platform that support specifying a start nickname 242 | * @type {object} 243 | */ 244 | ln.SUPPORTS_START_NAME = {}; 245 | ln.SUPPORTS_START_NAME[ln.PLATFORM.ANDROID] = [ 246 | ln.APP.CITYMAPPER, 247 | ln.APP.UBER, 248 | ln.APP.HERE_MAPS, 249 | ln.APP.MOOVIT, 250 | ln.APP.CABIFY, 251 | ln.APP.BAIDU, 252 | ln.APP.TAXIS_99, 253 | ln.APP.GAODE 254 | ]; 255 | ln.SUPPORTS_START_NAME[ln.PLATFORM.IOS] = [ 256 | ln.APP.APPLE_MAPS, // Only launchMode=mapkit 257 | ln.APP.CITYMAPPER, 258 | ln.APP.UBER, 259 | ln.APP.HERE_MAPS, 260 | ln.APP.MOOVIT, 261 | ln.APP.CABIFY, 262 | ln.APP.BAIDU, 263 | ln.APP.TAXIS_99, 264 | ln.APP.GAODE 265 | ]; 266 | 267 | /** 268 | * Apps by platform that support specifying a destination nickname 269 | * @type {object} 270 | */ 271 | ln.SUPPORTS_DEST_NAME = {}; 272 | ln.SUPPORTS_DEST_NAME[ln.PLATFORM.ANDROID] = [ 273 | ln.APP.GOOGLE_MAPS, // only launchMode=geo 274 | ln.APP.CITYMAPPER, 275 | ln.APP.UBER, 276 | ln.APP.HERE_MAPS, 277 | ln.APP.MOOVIT, 278 | ln.APP.CABIFY, 279 | ln.APP.BAIDU, 280 | ln.APP.TAXIS_99, 281 | ln.APP.GAODE 282 | ]; 283 | ln.SUPPORTS_DEST_NAME[ln.PLATFORM.IOS] = [ 284 | ln.APP.APPLE_MAPS, // Only launchMode=mapkit 285 | ln.APP.CITYMAPPER, 286 | ln.APP.NAVIGON, 287 | ln.APP.UBER, 288 | ln.APP.TOMTOM, 289 | ln.APP.HERE_MAPS, 290 | ln.APP.MOOVIT, 291 | ln.APP.CABIFY, 292 | ln.APP.BAIDU, 293 | ln.APP.TAXIS_99, 294 | ln.APP.GAODE 295 | ]; 296 | 297 | /** 298 | * Apps by platform that support specifying a launch mode 299 | * @type {object} 300 | */ 301 | ln.SUPPORTS_LAUNCH_MODE = {}; 302 | ln.SUPPORTS_LAUNCH_MODE[ln.PLATFORM.ANDROID] = [ 303 | ln.APP.GOOGLE_MAPS 304 | ]; 305 | ln.SUPPORTS_LAUNCH_MODE[ln.PLATFORM.IOS] = [ 306 | ln.APP.APPLE_MAPS 307 | ]; 308 | 309 | ln.COORDS_REGEX = /^[-\d.]+,[\s]*[-\d.]+$/; 310 | 311 | /************ 312 | * Export 313 | ************/ 314 | module.exports = ln; -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for react-native-launch-navigator 2 | // Project: https://github.com/dpa99c/react-native-launch-navigator 3 | // Definitions by: Dave Alden 4 | // Usage: import { LaunchNavigator, LaunchNavigatorOptions } from 'react-native-launch-navigator'; 5 | 6 | 7 | declare module 'react-native-launch-navigator' { 8 | type APP_KEYS = "APPLE_MAPS" | "GOOGLE_MAPS" | "WAZE" | "CITYMAPPER" | "NAVIGON" | "TRANSIT_APP" | "YANDEX" | "UBER" | "TOMTOM" | "BING_MAPS" | "SYGIC" | "HERE_MAPS" | "MOOVIT" | "LYFT" | "MAPS_ME" | "CABIFY" | "BAIDU" | "TAXIS_99" | "GAODE"; 9 | 10 | export interface LaunchNavigatorOptions { 11 | 12 | /** 13 | * name of the navigation app to use for directions. 14 | * Specify using LaunchNavigator.APP constants. 15 | * e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 16 | */ 17 | app?: string; 18 | 19 | /** 20 | * nickname to display in app for destination. e.g. "Bob's House". 21 | */ 22 | destinationName?: string; 23 | 24 | /** 25 | * Start point of the navigation. 26 | * If not specified, the current device location will be used. 27 | * Either: 28 | * - a {string} containing the address. e.g. "Buckingham Palace, London" 29 | * - a {string} containing a latitude/longitude coordinate. e.g. "50.1. -4.0" 30 | * - an {array}, where the first element is the latitude and the second element is a longitude, as decimal numbers. e.g. [50.1, -4.0] 31 | */ 32 | start?: string | number[]; 33 | 34 | /** 35 | * nickname to display in app for start . e.g. "My House". 36 | */ 37 | startName?: string; 38 | 39 | /** 40 | * Transportation mode for navigation: "driving", "walking" or "transit". Defaults to "driving" if not specified. 41 | */ 42 | transportMode?: string; 43 | 44 | /** 45 | * Android: mode in which to open Google Maps app. 46 | * `LaunchNavigator.LAUNCH_MODE.MAPS` or `LaunchNavigator.LAUNCH_MODE.TURN_BY_TURN` 47 | * Defaults to `LaunchNavigator.LAUNCH_MODE.MAPS` if not specified. 48 | * 49 | * iOS: method to use to open Apple Maps app. 50 | * `LaunchNavigator.LAUNCH_MODE.URI_SCHEME` or `LaunchNavigator.LAUNCH_MODE.MAPKIT` 51 | * Defaults to `LaunchNavigator.LAUNCH_MODE.URI_SCHEME` if not specified. 52 | */ 53 | launchMode?: string; 54 | 55 | /** 56 | * a key/value map of extra app-specific parameters. For example, to tell Google Maps on Android to display Satellite view in "maps" launch mode: `{"t": "k"}` 57 | */ 58 | extras?: any; 59 | 60 | /** 61 | * If true, and input location type(s) doesn't match those required by the app, use geocoding to obtain the address/coords as required. Defaults to true. 62 | */ 63 | enableGeocoding?: boolean; 64 | } 65 | 66 | const LaunchNavigator: { 67 | 68 | /** 69 | * Supported platforms 70 | */ 71 | PLATFORM: any; 72 | 73 | /** 74 | * string constants, used to identify apps in native code 75 | */ 76 | APP: Record; 77 | 78 | /** 79 | * All possible transport modes 80 | */ 81 | TRANSPORT_MODE: any; 82 | 83 | /** 84 | * Launch modes supported by Google Maps on Android 85 | */ 86 | LAUNCH_MODE: any; 87 | 88 | 89 | /** 90 | * Launches navigator app 91 | * @param destination {string|number[]} Location name or coordinates (as string or array) 92 | * Either: 93 | * - a {string} containing the address. e.g. "Buckingham Palace, London" 94 | * - a {string} containing a latitude/longitude coordinate. e.g. "50.1. -4.0" 95 | * - an {array}, where the first element is the latitude and the second element is a longitude, as decimal numbers. e.g. [50.1, -4.0] 96 | * @param options {LaunchNavigatorOptions} 97 | * @return Promise 98 | * - resolved when the navigation app is successfully launched 99 | * - rejected if an error is encountered while launching the app. Will be passed a single string argument containing the error message. 100 | */ 101 | navigate: ( 102 | destination: string | number[], 103 | options?: LaunchNavigatorOptions 104 | ) => Promise; 105 | 106 | logEvent: (name: string, params?: any, valueToSum?: number) => void; 107 | 108 | /** 109 | * Determines if the given app is installed and available on the current device. 110 | * @param app {string} appName - name of the app to check availability for. Define as a constant using `LaunchNavigator.APP`. 111 | * @return {boolean} - indicates the availability of the specified app. 112 | */ 113 | isAppAvailable: ( 114 | app: string 115 | ) => boolean; 116 | 117 | /** 118 | * Returns a list indicating which apps are installed and available on the current device. 119 | * @return {object} - a key/value object where the key is the app name as a constant in `LaunchNavigator.APP` and the value is a boolean indicating whether the app is available. 120 | */ 121 | getAvailableApps: () => Promise>; 122 | 123 | /** 124 | * Returns the display name of the specified app. 125 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 126 | * @return {string} - app display name. e.g. "Google Maps". 127 | */ 128 | getAppDisplayName: (app: string) => string; 129 | 130 | /** 131 | * Returns list of supported apps on a given platform. 132 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 133 | * @return {array} - apps supported on specified platform as a list of `LaunchNavigator.APP` constants. 134 | */ 135 | getAppsForPlatform: (platform: string) => string[]; 136 | 137 | /** 138 | * Indicates if an app on a given platform supports specification of transport mode. 139 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 140 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 141 | * @param {string} launchMode - (optional) Only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 142 | * @return {boolean} - true if app/platform combination supports specification of transport mode. 143 | */ 144 | supportsTransportMode: ( 145 | app: string, 146 | platform: string, 147 | launchMode?: string 148 | ) => boolean; 149 | 150 | /** 151 | * Returns the list of transport modes supported by an app on a given platform. 152 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 153 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 154 | * @param {string} launchMode - (optional) Only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 155 | * @return {array} - list of transports modes as constants in `LaunchNavigator.TRANSPORT_MODE`. 156 | * If app/platform combination doesn't support specification of transport mode, the list will be empty; 157 | */ 158 | getTransportModes: ( 159 | app: string, 160 | platform: string, 161 | launchMode?: string 162 | ) => string[]; 163 | 164 | /** 165 | * Indicates if an app on a given platform supports specification of launch mode. 166 | * Note that currently only Google Maps on Android does. 167 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 168 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.ANDROID`. 169 | * @return {boolean} - true if app/platform combination supports specification of transport mode. 170 | */ 171 | supportsLaunchMode: ( 172 | app: string, 173 | platform: string 174 | ) => boolean; 175 | 176 | /** 177 | * Indicates if an app on a given platform supports specification of start location. 178 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 179 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 180 | * @param {string} launchMode - (optional) Only applies to Google Maps on Android. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 181 | * @return {boolean} - true if app/platform combination supports specification of start location. 182 | */ 183 | supportsStart: ( 184 | app: string, 185 | platform: string, 186 | launchMode?: string 187 | ) => boolean; 188 | 189 | /** 190 | * Indicates if an app on a given platform supports specification of a custom nickname for start location. 191 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 192 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 193 | * @param {string} launchMode - (optional) Only applies to Apple Maps on iOS. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPKIT`. 194 | * @return {boolean} - true if app/platform combination supports specification of start location. 195 | */ 196 | supportsStartName: ( 197 | app: string, 198 | platform: string, 199 | launchMode?: string 200 | ) => boolean; 201 | 202 | /** 203 | * Indicates if an app on a given platform supports specification of a custom nickname for destination location. 204 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 205 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 206 | * @param {string} launchMode - (optional) Applies to Google Maps on Android and Apple Maps on iOS. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPS`. 207 | * @return {boolean} - true if app/platform combination supports specification of destination location. 208 | */ 209 | supportsDestName: ( 210 | app: string, 211 | platform: string, 212 | launchMode?: string 213 | ) => boolean; 214 | 215 | /** 216 | * Sets the Google API key to use for the Google Geocoder API on Android. 217 | * @param {string} googleApiKey - the API key to use for the Geocoder API on Android. 218 | */ 219 | setGoogleApiKey: ( 220 | googleApiKey: string 221 | ) => void 222 | 223 | /** 224 | * Enables debug log output from the plugin to the JS and native consoles. By default debug is disabled. 225 | * @param enabled {boolean} 226 | */ 227 | enableDebug: ( 228 | enabled: boolean 229 | ) => void; 230 | } 231 | 232 | export default LaunchNavigator; 233 | } 234 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @providesModule react-native-launch-navigator 3 | * @flow 4 | */ 5 | 'use strict'; 6 | 7 | import {Platform, NativeModules} from 'react-native'; 8 | import RNLogger from './RNLogger'; 9 | 10 | let ln; 11 | if(Platform.OS === "ios"){ 12 | ln = require('./ios'); 13 | }else if(Platform.OS === "android"){ 14 | ln = require('./android'); 15 | }else{ 16 | throw "Unsupported platform: " + Platform.OS; 17 | } 18 | 19 | 20 | /********************* 21 | * Internal properties 22 | *********************/ 23 | let RNLaunchNavigator = NativeModules.RNLaunchNavigator; 24 | let Logger = new RNLogger(RNLaunchNavigator); 25 | 26 | /******************** 27 | * Internal functions 28 | ********************/ 29 | 30 | 31 | /****************** 32 | * Public API 33 | ******************/ 34 | 35 | /** 36 | * Sets debug mode status in the native launch navigator module 37 | * @param {boolean} enabled - if true, debug mode is enabled; if false, debug mode is disabled. 38 | */ 39 | ln.enableDebug = RNLaunchNavigator.enableDebug; 40 | 41 | /** 42 | * Returns a list indicating which apps are installed and available on the current device. 43 | * @return {Promise} 44 | * resolve - Will be passed a key/value object where the key is the app name and the value is a boolean indicating whether the app is available. 45 | * reject - Will be passed a single string argument containing the error message. 46 | */ 47 | ln.getAvailableApps = function(){ 48 | return RNLaunchNavigator.getAvailableApps(); 49 | }; 50 | 51 | /** 52 | * Determines if the given app is installed and available on the current device. 53 | * @param {string} appName - name of the app to check availability for. Define as a constant using ln.APP 54 | * @return {Promise} 55 | * resolve - Will be passed a single boolean argument indicating the availability of the app. 56 | * reject - Will be passed a single string argument containing the error message. 57 | */ 58 | ln.isAppAvailable = function(appName){ 59 | return RNLaunchNavigator.isAppAvailable(appName); 60 | }; 61 | 62 | /** 63 | * Returns the display name of the specified app. 64 | * @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`. 65 | * @return {string} - app display name. e.g. "Google Maps". 66 | */ 67 | ln.getAppDisplayName = function(app){ 68 | ln.util.validateApp(app); 69 | return ln.APP_NAMES[app]; 70 | }; 71 | 72 | /** 73 | * Returns list of supported apps on a given platform. 74 | * @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`. 75 | * @return {string[]} - apps supported on specified platform as a list of `launchnavigator.APP` constants. 76 | */ 77 | ln.getAppsForPlatform = function(platform){ 78 | ln.util.validatePlatform(platform); 79 | return ln.APPS_BY_PLATFORM[platform]; 80 | }; 81 | 82 | 83 | 84 | /** 85 | * Indicates if an app on a given platform supports specification of launch mode. 86 | * @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`. 87 | * @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.ANDROID`. 88 | * @return {boolean} - true if app/platform combination supports specification of transport mode. 89 | */ 90 | ln.supportsLaunchMode = function(app, platform) { 91 | ln.util.validateApp(app); 92 | ln.util.validatePlatform(platform); 93 | return !!ln.SUPPORTS_LAUNCH_MODE[platform] && ln.util.arrayContainsValue(ln.SUPPORTS_LAUNCH_MODE[platform], app); 94 | }; 95 | 96 | 97 | /** 98 | * Indicates if an app on a given platform supports specification of a custom nickname for start location. 99 | * @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`. 100 | * @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`. 101 | * @return {boolean} - true if app/platform combination supports specification of start location. 102 | */ 103 | ln._supportsStartName = function(app, platform){ 104 | ln.util.validateApp(app); 105 | ln.util.validatePlatform(platform); 106 | return !!ln.SUPPORTS_START_NAME[platform] && ln.util.arrayContainsValue(ln.SUPPORTS_START_NAME[platform], app); 107 | }; 108 | 109 | /** 110 | * Indicates if an app on a given platform supports specification of start location. 111 | * @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`. 112 | * @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`. 113 | * @return {boolean} - true if app/platform combination supports specification of start location. 114 | */ 115 | ln._supportsStart = function(app, platform){ 116 | ln.util.validateApp(app); 117 | ln.util.validatePlatform(platform); 118 | return !!ln.SUPPORTS_START[platform] && ln.util.arrayContainsValue(ln.SUPPORTS_START[platform], app); 119 | }; 120 | 121 | /** 122 | * Indicates if an app on a given platform supports specification of a custom nickname for destination location. 123 | * @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`. 124 | * @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`. 125 | * @return {boolean} - true if app/platform combination supports specification of destination location. 126 | */ 127 | ln._supportsDestName = function(app, platform){ 128 | ln.util.validateApp(app); 129 | ln.util.validatePlatform(platform); 130 | return !!ln.SUPPORTS_DEST_NAME[platform] && ln.util.arrayContainsValue(ln.SUPPORTS_DEST_NAME[platform], app); 131 | }; 132 | 133 | /** 134 | * Indicates if an app on a given platform supports specification of transport mode. 135 | * @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`. 136 | * @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`. 137 | * @return {boolean} - true if app/platform combination supports specification of transport mode. 138 | */ 139 | ln._supportsTransportMode = function(app, platform){ 140 | ln.util.validateApp(app); 141 | ln.util.validatePlatform(platform); 142 | return !!ln.TRANSPORT_MODES[platform] && ln.util.objectContainsKey(ln.TRANSPORT_MODES[platform], app); 143 | }; 144 | 145 | /******************* 146 | * Utility functions 147 | *******************/ 148 | ln.util = {}; 149 | ln.util.arrayContainsValue = function (a, obj) { 150 | var i = a.length; 151 | while (i--) { 152 | if (a[i] === obj) { 153 | return true; 154 | } 155 | } 156 | return false; 157 | }; 158 | 159 | ln.util.objectContainsKey = function (o, key) { 160 | for(var k in o){ 161 | if(k === key){ 162 | return true; 163 | } 164 | } 165 | return false; 166 | }; 167 | 168 | ln.util.objectContainsValue = function (o, value) { 169 | for(var k in o){ 170 | if(o[k] === value){ 171 | return true; 172 | } 173 | } 174 | return false; 175 | }; 176 | 177 | ln.util.countKeysInObject = function (o){ 178 | var count = 0; 179 | for(var k in o){ 180 | count++; 181 | } 182 | return count; 183 | }; 184 | 185 | ln.util.isValidApp = function(app){ 186 | if(app === "none") return true; // native chooser 187 | return ln.util.objectContainsValue(ln.APP, app); 188 | }; 189 | 190 | ln.util.isValidPlatform = function(platform){ 191 | return ln.util.objectContainsValue(ln.PLATFORM, platform); 192 | }; 193 | 194 | ln.util.isValidTransportMode = function(transportMode) { 195 | return ln.util.objectContainsValue(ln.TRANSPORT_MODE, transportMode); 196 | }; 197 | 198 | ln.util.validateApp = function(app){ 199 | if(!ln.util.isValidApp(app)){ 200 | throw new Error("'"+app+"' is not a recognised app"); 201 | } 202 | }; 203 | 204 | ln.util.validatePlatform = function(platform){ 205 | if(!ln.util.isValidPlatform(platform)){ 206 | throw new Error("'"+platform+"' is not a recognised platform"); 207 | } 208 | }; 209 | 210 | ln.util.validateTransportMode = function(transportMode){ 211 | if(!ln.util.isValidTransportMode(transportMode)){ 212 | throw new Error("'"+transportMode+"' is not a recognised transport mode"); 213 | } 214 | }; 215 | 216 | ln.util.extractCoordsFromLocationString = function(location){ 217 | if(location && typeof(location) === "string" && location.match(ln.COORDS_REGEX)){ 218 | location = location.replace(/\s*/g,''); 219 | var parts = location.split(","); 220 | location = [parts[0], parts[1]]; 221 | } 222 | return location; 223 | }; 224 | 225 | ln.util.isValidLaunchMode = function(launchMode){ 226 | for(var LAUNCH_MODE in ln.LAUNCH_MODE){ 227 | if(launchMode === ln.LAUNCH_MODE[LAUNCH_MODE]) return true; 228 | } 229 | return false; 230 | }; 231 | 232 | ln.util.validateLaunchMode = function(launchMode){ 233 | if(!ln.util.isValidLaunchMode(launchMode)){ 234 | throw new Error("'"+launchMode+"' is not a recognised launch mode"); 235 | } 236 | }; 237 | 238 | ln.util.conformNavigateOptions = function(args){ 239 | var options; 240 | if(args.length > 1 && typeof args[1] === "function"){ 241 | // assume (dest, success, error, opts) 242 | options = (args.length > 3 && typeof args[3] === "object") ? args[3] : {}; 243 | options.successCallback = args[1]; 244 | if(args.length > 2 && typeof args[2] === "function"){ 245 | options.errorCallback = args[2]; 246 | } 247 | }else{ 248 | // assume (dest, opts) 249 | options = (args.length > 1 && typeof args[1] === "object") ? args[1] : {}; 250 | } 251 | return options; 252 | }; 253 | 254 | module.exports = ln; -------------------------------------------------------------------------------- /ios.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import {NativeModules} from 'react-native'; 4 | let ln = require('./constants'); 5 | 6 | /********************* 7 | * Internal properties 8 | *********************/ 9 | let RNLaunchNavigator = NativeModules.RNLaunchNavigator; 10 | 11 | /****************** 12 | * Public Constants 13 | ******************/ 14 | 15 | // Launch modes for Apple Maps 16 | ln.LAUNCH_MODE = { 17 | URI_SCHEME: "uri_scheme", 18 | MAPKIT: "mapkit" 19 | }; 20 | 21 | /****************** 22 | * Public API 23 | ******************/ 24 | 25 | /** 26 | * Opens navigator app to navigate to given destination, specified by either place name or lat/lon. 27 | * If a start location is not also specified, current location will be used for the start. 28 | * 29 | * @param {string/number[]} destination (required) - destination location to use for navigation. 30 | * Either: 31 | * - a {string} containing the address. e.g. "Buckingham Palace, London" 32 | * - an {array}, where the first element is the latitude and the second element is a longitude, as decimal numbers. e.g. [50.1, -4.0] 33 | * 34 | * @param {object} options (optional) - optional parameters: 35 | * 36 | * - {string} app - navigation app to use for directions, as a constant. e.g. LaunchNavigator.APP.WAZE 37 | * If not specified, defaults to Apple Maps. 38 | * 39 | * - {string} destinationName - nickname to display in app for destination. e.g. "Bob's House". 40 | * 41 | * - {mixed} start - start location to use for navigation. If not specified, the current location of the device will be used. 42 | * Either: 43 | * - a {string} containing the address. e.g. "Buckingham Palace, London" 44 | * - an {array}, where the first element is the latitude and the second element is a longitude, as decimal numbers. e.g. [50.1, -4.0] 45 | * 46 | * - {string} startName - nickname to display in app for start. e.g. "My Place". 47 | * 48 | * - {string} transportMode - transportation mode for navigation. 49 | * Defaults to "driving" if not specified. 50 | * 51 | * - {string} launchMode - method to use to open Apple Maps app: 52 | * - `LaunchNavigator.LAUNCH_MODE.URI_SCHEME` or `LaunchNavigator.MAPKIT` 53 | * - Defaults to `LaunchNavigator.LAUNCH_MODE.URI_SCHEME` if not specified. 54 | * 55 | * - {object} extras - a key/value map of extra app-specific parameters. For example, to tell Google Maps to display Satellite view in "maps" launch mode: `{"t": "k"}` 56 | * 57 | * - {boolean} enableGeocoding - if true, and input location type(s) doesn't match those required by the app, use geocoding to obtain the address/coords as required. Defaults to TRUE. 58 | * 59 | * @return Promise 60 | * resolve - invoke when the navigation app is successfully launched. 61 | * reject - if an error is encountered while launching the app. 62 | * A single string argument containing the error message will be passed. 63 | */ 64 | ln.navigate = function(destination, options) { 65 | options = ln.util.conformNavigateOptions(arguments); 66 | 67 | // Set defaults 68 | options.transportMode = options.transportMode ? options.transportMode : ln.TRANSPORT_MODE.DRIVING; 69 | options.enableGeocoding = typeof options.enableGeocoding !== "undefined" ? options.enableGeocoding : true; 70 | options.launchMode = typeof options.launchMode !== "undefined" ? options.launchMode : ln.LAUNCH_MODE.URI_SCHEME; 71 | 72 | // Input validation 73 | var throwError = function(errMsg){ 74 | throw new Error(errMsg); 75 | }; 76 | 77 | if(!destination){ 78 | throwError("No destination was specified"); 79 | } 80 | 81 | if(options.extras && typeof options.extras !== "object"){ 82 | throwError("'options.extras' must be a key/value object"); 83 | } 84 | if(options.extras) options.extras = JSON.stringify(options.extras); 85 | 86 | // Default to Apple Maps if not specified 87 | if(!options.app) options.app = ln.APP.APPLE_MAPS; 88 | ln.util.validateApp(options.app); 89 | ln.util.validateTransportMode(options.transportMode); 90 | 91 | // Process options 92 | destination = ln.util.extractCoordsFromLocationString(destination); 93 | if(typeof(destination) === "object"){ 94 | if(typeof destination.length === "undefined") throw "destination must be a string or an array"; 95 | destination = destination.join(","); 96 | options.destType = "coords"; 97 | }else{ 98 | options.destType = "name"; 99 | } 100 | 101 | options.start = ln.util.extractCoordsFromLocationString(options.start); 102 | if(!options.start){ 103 | options.startType = "none"; 104 | }else if(typeof(options.start) === "object"){ 105 | if(typeof options.start.length === "undefined") throw "start must be a string or an array"; 106 | options.start = options.start.join(","); 107 | options.startType = "coords"; 108 | }else{ 109 | options.startType = "name"; 110 | } 111 | 112 | return RNLaunchNavigator.navigate({ 113 | appName: options.app, 114 | destType: options.destType, 115 | dest: destination, 116 | destName: options.destinationName, 117 | startType: options.startType, 118 | start: options.start, 119 | startName: options.startName, 120 | transportMode: options.transportMode, 121 | launchMode: options.launchMode, 122 | extras: options.extras, 123 | enableGeocoding: options.enableGeocoding 124 | }); 125 | 126 | }; 127 | 128 | /** 129 | * Returns the list of transport modes supported by an app on a given platform. 130 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.GOOGLE_MAPS`. 131 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 132 | * @return {string[]} - list of transports modes as constants in `LaunchNavigator.TRANSPORT_MODE`. 133 | * If app/platform combination doesn't support specification of transport mode, the list will be empty; 134 | */ 135 | ln.getTransportModes = function(app, platform){ 136 | if(ln.supportsTransportMode(app, platform)){ 137 | return ln.TRANSPORT_MODES[platform][app]; 138 | } 139 | return []; 140 | }; 141 | 142 | /** 143 | * Indicates if an app on a given platform supports specification of a custom nickname for destination location. 144 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.APPLE_MAPS`. 145 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. `LaunchNavigator.PLATFORM.IOS`. 146 | * @param {string} launchMode (optional) - only applies to Apple Maps on iOS. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPKIT`. 147 | * @return {boolean} - true if app/platform combination supports specification of destination location. 148 | */ 149 | ln.supportsDestName = function(app, platform, launchMode){ 150 | ln.util.validateApp(app); 151 | ln.util.validatePlatform(platform); 152 | let result; 153 | if(launchMode && platform === ln.PLATFORM.IOS && app === ln.APP.APPLE_MAPS){ 154 | ln.util.validateLaunchMode(launchMode); 155 | result = launchMode === ln.LAUNCH_MODE.MAPKIT; 156 | }else{ 157 | result = ln._supportsDestName(app, platform); 158 | } 159 | return result; 160 | }; 161 | 162 | 163 | /** 164 | * Indicates if an app on a given platform supports specification of a custom nickname for start location. 165 | * @param {string} app - specified as a constant in `LaunchNavigator.APP`. e.g. `LaunchNavigator.APP.APPLE_MAPS`. 166 | * @param {string} platform - specified as a constant in `LaunchNavigator.PLATFORM`. e.g. 167 | * @param {string} launchMode (optional) - only applies to Apple Maps on iOS. Specified as a constant in `LaunchNavigator.LAUNCH_MODE`. e.g. `LaunchNavigator.LAUNCH_MODE.MAPKIT`. 168 | * @return {boolean} - true if app/platform combination supports specification of start location. 169 | */ 170 | ln.supportsStartName = function(app, platform, launchMode){ 171 | ln.util.validateApp(app); 172 | ln.util.validatePlatform(platform); 173 | let result; 174 | if(launchMode && platform === ln.PLATFORM.IOS && app === ln.APP.APPLE_MAPS){ 175 | ln.util.validateLaunchMode(launchMode); 176 | result = launchMode === ln.LAUNCH_MODE.MAPKIT; 177 | }else{ 178 | result = ln._supportsStartName(app, platform); 179 | } 180 | return result; 181 | }; 182 | 183 | // Map directly to public API 184 | ln.supportsStart = function() { 185 | return ln._supportsStart.apply(this, arguments); 186 | }; 187 | ln.supportsTransportMode = function() { 188 | return ln._supportsTransportMode.apply(this, arguments); 189 | }; 190 | 191 | /************ 192 | * Export 193 | ************/ 194 | module.exports = ln; -------------------------------------------------------------------------------- /ios/RNLaunchNavigator.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5544C0A720B8B06300C34D72 /* RNLaunchNavigator.m in Sources */ = {isa = PBXBuildFile; fileRef = 5544C0A620B8B06300C34D72 /* RNLaunchNavigator.m */; }; 11 | 55C2978820DF9EE500475C12 /* LN_LaunchNavigator.m in Sources */ = {isa = PBXBuildFile; fileRef = 55C2977F20DF9EE400475C12 /* LN_LaunchNavigator.m */; }; 12 | 55C2978A20DF9EE500475C12 /* WE_ReactNativeLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 55C2978220DF9EE400475C12 /* WE_ReactNativeLogger.m */; }; 13 | 55C2978B20DF9EE500475C12 /* WE_Logger.m in Sources */ = {isa = PBXBuildFile; fileRef = 55C2978420DF9EE400475C12 /* WE_Logger.m */; }; 14 | 55C2978C20DF9EE500475C12 /* LN_Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 55C2978520DF9EE400475C12 /* LN_Reachability.m */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXCopyFilesBuildPhase section */ 18 | 58B511D91A9E6C8500147676 /* CopyFiles */ = { 19 | isa = PBXCopyFilesBuildPhase; 20 | buildActionMask = 2147483647; 21 | dstPath = "include/$(PRODUCT_NAME)"; 22 | dstSubfolderSpec = 16; 23 | files = ( 24 | ); 25 | runOnlyForDeploymentPostprocessing = 0; 26 | }; 27 | /* End PBXCopyFilesBuildPhase section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 134814201AA4EA6300B7C361 /* libRNLaunchNavigator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNLaunchNavigator.a; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 5544C0A520B8B06200C34D72 /* RNLaunchNavigator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNLaunchNavigator.h; path = RNLaunchNavigator/RNLaunchNavigator.h; sourceTree = ""; }; 32 | 5544C0A620B8B06300C34D72 /* RNLaunchNavigator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNLaunchNavigator.m; path = RNLaunchNavigator/RNLaunchNavigator.m; sourceTree = ""; }; 33 | 55C2977E20DF9EE400475C12 /* LN_Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LN_Reachability.h; path = RNLaunchNavigator/LN_Reachability.h; sourceTree = ""; }; 34 | 55C2977F20DF9EE400475C12 /* LN_LaunchNavigator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LN_LaunchNavigator.m; path = RNLaunchNavigator/LN_LaunchNavigator.m; sourceTree = ""; }; 35 | 55C2978020DF9EE400475C12 /* LN_LaunchNavigator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LN_LaunchNavigator.h; path = RNLaunchNavigator/LN_LaunchNavigator.h; sourceTree = ""; }; 36 | 55C2978220DF9EE400475C12 /* WE_ReactNativeLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WE_ReactNativeLogger.m; path = RNLaunchNavigator/WE_ReactNativeLogger.m; sourceTree = ""; }; 37 | 55C2978320DF9EE400475C12 /* WE_Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WE_Logger.h; path = RNLaunchNavigator/WE_Logger.h; sourceTree = ""; }; 38 | 55C2978420DF9EE400475C12 /* WE_Logger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WE_Logger.m; path = RNLaunchNavigator/WE_Logger.m; sourceTree = ""; }; 39 | 55C2978520DF9EE400475C12 /* LN_Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LN_Reachability.m; path = RNLaunchNavigator/LN_Reachability.m; sourceTree = ""; }; 40 | 55C2978720DF9EE500475C12 /* WE_ReactNativeLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WE_ReactNativeLogger.h; path = RNLaunchNavigator/WE_ReactNativeLogger.h; sourceTree = ""; }; 41 | /* End PBXFileReference section */ 42 | 43 | /* Begin PBXFrameworksBuildPhase section */ 44 | 58B511D81A9E6C8500147676 /* Frameworks */ = { 45 | isa = PBXFrameworksBuildPhase; 46 | buildActionMask = 2147483647; 47 | files = ( 48 | ); 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | /* End PBXFrameworksBuildPhase section */ 52 | 53 | /* Begin PBXGroup section */ 54 | 134814211AA4EA7D00B7C361 /* Products */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | 134814201AA4EA6300B7C361 /* libRNLaunchNavigator.a */, 58 | ); 59 | name = Products; 60 | sourceTree = ""; 61 | }; 62 | 58B511D21A9E6C8500147676 = { 63 | isa = PBXGroup; 64 | children = ( 65 | 55C2978020DF9EE400475C12 /* LN_LaunchNavigator.h */, 66 | 55C2977F20DF9EE400475C12 /* LN_LaunchNavigator.m */, 67 | 55C2977E20DF9EE400475C12 /* LN_Reachability.h */, 68 | 55C2978520DF9EE400475C12 /* LN_Reachability.m */, 69 | 134814211AA4EA7D00B7C361 /* Products */, 70 | 5544C0A520B8B06200C34D72 /* RNLaunchNavigator.h */, 71 | 5544C0A620B8B06300C34D72 /* RNLaunchNavigator.m */, 72 | 55C2978320DF9EE400475C12 /* WE_Logger.h */, 73 | 55C2978420DF9EE400475C12 /* WE_Logger.m */, 74 | 55C2978720DF9EE500475C12 /* WE_ReactNativeLogger.h */, 75 | 55C2978220DF9EE400475C12 /* WE_ReactNativeLogger.m */, 76 | ); 77 | indentWidth = 2; 78 | sourceTree = ""; 79 | tabWidth = 2; 80 | usesTabs = 0; 81 | }; 82 | /* End PBXGroup section */ 83 | 84 | /* Begin PBXNativeTarget section */ 85 | 58B511DA1A9E6C8500147676 /* RNLaunchNavigator */ = { 86 | isa = PBXNativeTarget; 87 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNLaunchNavigator" */; 88 | buildPhases = ( 89 | 58B511D71A9E6C8500147676 /* Sources */, 90 | 58B511D81A9E6C8500147676 /* Frameworks */, 91 | 58B511D91A9E6C8500147676 /* CopyFiles */, 92 | ); 93 | buildRules = ( 94 | ); 95 | dependencies = ( 96 | ); 97 | name = RNLaunchNavigator; 98 | productName = RCTDataManager; 99 | productReference = 134814201AA4EA6300B7C361 /* libRNLaunchNavigator.a */; 100 | productType = "com.apple.product-type.library.static"; 101 | }; 102 | /* End PBXNativeTarget section */ 103 | 104 | /* Begin PBXProject section */ 105 | 58B511D31A9E6C8500147676 /* Project object */ = { 106 | isa = PBXProject; 107 | attributes = { 108 | LastUpgradeCheck = 0610; 109 | ORGANIZATIONNAME = Facebook; 110 | TargetAttributes = { 111 | 58B511DA1A9E6C8500147676 = { 112 | CreatedOnToolsVersion = 6.1.1; 113 | }; 114 | }; 115 | }; 116 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNLaunchNavigator" */; 117 | compatibilityVersion = "Xcode 3.2"; 118 | developmentRegion = English; 119 | hasScannedForEncodings = 0; 120 | knownRegions = ( 121 | en, 122 | ); 123 | mainGroup = 58B511D21A9E6C8500147676; 124 | productRefGroup = 58B511D21A9E6C8500147676; 125 | projectDirPath = ""; 126 | projectRoot = ""; 127 | targets = ( 128 | 58B511DA1A9E6C8500147676 /* RNLaunchNavigator */, 129 | ); 130 | }; 131 | /* End PBXProject section */ 132 | 133 | /* Begin PBXSourcesBuildPhase section */ 134 | 58B511D71A9E6C8500147676 /* Sources */ = { 135 | isa = PBXSourcesBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | 55C2978B20DF9EE500475C12 /* WE_Logger.m in Sources */, 139 | 55C2978820DF9EE500475C12 /* LN_LaunchNavigator.m in Sources */, 140 | 5544C0A720B8B06300C34D72 /* RNLaunchNavigator.m in Sources */, 141 | 55C2978A20DF9EE500475C12 /* WE_ReactNativeLogger.m in Sources */, 142 | 55C2978C20DF9EE500475C12 /* LN_Reachability.m in Sources */, 143 | ); 144 | runOnlyForDeploymentPostprocessing = 0; 145 | }; 146 | /* End PBXSourcesBuildPhase section */ 147 | 148 | /* Begin XCBuildConfiguration section */ 149 | 58B511ED1A9E6C8500147676 /* Debug */ = { 150 | isa = XCBuildConfiguration; 151 | buildSettings = { 152 | ALWAYS_SEARCH_USER_PATHS = NO; 153 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 154 | CLANG_CXX_LIBRARY = "libc++"; 155 | CLANG_ENABLE_MODULES = YES; 156 | CLANG_ENABLE_OBJC_ARC = YES; 157 | CLANG_WARN_BOOL_CONVERSION = YES; 158 | CLANG_WARN_CONSTANT_CONVERSION = YES; 159 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 160 | CLANG_WARN_EMPTY_BODY = YES; 161 | CLANG_WARN_ENUM_CONVERSION = YES; 162 | CLANG_WARN_INT_CONVERSION = YES; 163 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 164 | CLANG_WARN_UNREACHABLE_CODE = YES; 165 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 166 | COPY_PHASE_STRIP = NO; 167 | ENABLE_STRICT_OBJC_MSGSEND = YES; 168 | GCC_C_LANGUAGE_STANDARD = gnu99; 169 | GCC_DYNAMIC_NO_PIC = NO; 170 | GCC_OPTIMIZATION_LEVEL = 0; 171 | GCC_PREPROCESSOR_DEFINITIONS = ( 172 | "DEBUG=1", 173 | "$(inherited)", 174 | ); 175 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 176 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 177 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 178 | GCC_WARN_UNDECLARED_SELECTOR = YES; 179 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 180 | GCC_WARN_UNUSED_FUNCTION = YES; 181 | GCC_WARN_UNUSED_VARIABLE = YES; 182 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 183 | MTL_ENABLE_DEBUG_INFO = YES; 184 | ONLY_ACTIVE_ARCH = YES; 185 | SDKROOT = iphoneos; 186 | }; 187 | name = Debug; 188 | }; 189 | 58B511EE1A9E6C8500147676 /* Release */ = { 190 | isa = XCBuildConfiguration; 191 | buildSettings = { 192 | ALWAYS_SEARCH_USER_PATHS = NO; 193 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 194 | CLANG_CXX_LIBRARY = "libc++"; 195 | CLANG_ENABLE_MODULES = YES; 196 | CLANG_ENABLE_OBJC_ARC = YES; 197 | CLANG_WARN_BOOL_CONVERSION = YES; 198 | CLANG_WARN_CONSTANT_CONVERSION = YES; 199 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 200 | CLANG_WARN_EMPTY_BODY = YES; 201 | CLANG_WARN_ENUM_CONVERSION = YES; 202 | CLANG_WARN_INT_CONVERSION = YES; 203 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 204 | CLANG_WARN_UNREACHABLE_CODE = YES; 205 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 206 | COPY_PHASE_STRIP = YES; 207 | ENABLE_NS_ASSERTIONS = NO; 208 | ENABLE_STRICT_OBJC_MSGSEND = YES; 209 | GCC_C_LANGUAGE_STANDARD = gnu99; 210 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 211 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 212 | GCC_WARN_UNDECLARED_SELECTOR = YES; 213 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 214 | GCC_WARN_UNUSED_FUNCTION = YES; 215 | GCC_WARN_UNUSED_VARIABLE = YES; 216 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 217 | MTL_ENABLE_DEBUG_INFO = NO; 218 | SDKROOT = iphoneos; 219 | VALIDATE_PRODUCT = YES; 220 | }; 221 | name = Release; 222 | }; 223 | 58B511F01A9E6C8500147676 /* Debug */ = { 224 | isa = XCBuildConfiguration; 225 | buildSettings = { 226 | HEADER_SEARCH_PATHS = ( 227 | "$(inherited)", 228 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 229 | "$(SRCROOT)/../../React/**", 230 | "$(SRCROOT)/../../node_modules/react-native/React/**", 231 | ); 232 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 233 | OTHER_LDFLAGS = "-ObjC"; 234 | PRODUCT_NAME = RNLaunchNavigator; 235 | SKIP_INSTALL = YES; 236 | }; 237 | name = Debug; 238 | }; 239 | 58B511F11A9E6C8500147676 /* Release */ = { 240 | isa = XCBuildConfiguration; 241 | buildSettings = { 242 | HEADER_SEARCH_PATHS = ( 243 | "$(inherited)", 244 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 245 | "$(SRCROOT)/../../React/**", 246 | ); 247 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 248 | OTHER_LDFLAGS = "-ObjC"; 249 | PRODUCT_NAME = RNLaunchNavigator; 250 | SKIP_INSTALL = YES; 251 | }; 252 | name = Release; 253 | }; 254 | /* End XCBuildConfiguration section */ 255 | 256 | /* Begin XCConfigurationList section */ 257 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNLaunchNavigator" */ = { 258 | isa = XCConfigurationList; 259 | buildConfigurations = ( 260 | 58B511ED1A9E6C8500147676 /* Debug */, 261 | 58B511EE1A9E6C8500147676 /* Release */, 262 | ); 263 | defaultConfigurationIsVisible = 0; 264 | defaultConfigurationName = Release; 265 | }; 266 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNLaunchNavigator" */ = { 267 | isa = XCConfigurationList; 268 | buildConfigurations = ( 269 | 58B511F01A9E6C8500147676 /* Debug */, 270 | 58B511F11A9E6C8500147676 /* Release */, 271 | ); 272 | defaultConfigurationIsVisible = 0; 273 | defaultConfigurationName = Release; 274 | }; 275 | /* End XCConfigurationList section */ 276 | }; 277 | rootObject = 58B511D31A9E6C8500147676 /* Project object */; 278 | } 279 | -------------------------------------------------------------------------------- /ios/RNLaunchNavigator/LN_LaunchNavigator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LN_LaunchNavigator Library 3 | * 4 | * Copyright (c) 2018 Dave Alden (http://github.com/dpa99c) 5 | * Copyright (c) 2018 Working Edge Ltd. (http://www.workingedge.co.uk) 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | * 28 | */ 29 | 30 | #import 31 | #import 32 | #import "WE_Logger.h" 33 | 34 | // This enumeration identifies the mapping apps 35 | // that this launcher knows how to support. 36 | typedef NS_ENUM(NSUInteger, LNApp) { 37 | LNAppAppleMaps = 0, // Preinstalled Apple Maps 38 | LNAppCitymapper, // Citymapper 39 | LNAppGoogleMaps, // Standalone Google Maps App 40 | LNAppNavigon, // Navigon 41 | LNAppTheTransitApp, // The Transit App 42 | LNAppWaze, // Waze 43 | LNAppYandex, // Yandex Navigator 44 | LNAppUber, // Uber 45 | LNAppTomTom, // TomTom 46 | LNAppSygic, // Sygic 47 | LNAppHereMaps, // HERE Maps 48 | LNAppMoovit, // Moovit 49 | LNAppLyft, // Lyft 50 | LNAppMapsMe, // MAPS.ME 51 | LNAppCabify, // Cabify 52 | LNAppBaidu, // Baidu 53 | LNAppTaxis99, // 99 Taxi 54 | LNAppGaode // Gaode (Amap) 55 | }; 56 | 57 | static NSString*const LOG_TAG = @"LN_LaunchNavigator[native]"; 58 | static NSString*const LNLocTypeNone = @"none"; 59 | static NSString*const LNLocTypeBoth = @"both"; 60 | static NSString*const LNLocTypeAddress = @"name"; 61 | static NSString*const LNLocTypeCoords = @"coords"; 62 | 63 | /** 64 | Indicates an empty coordinate 65 | */ 66 | static CLLocationCoordinate2D LNEmptyCoord; 67 | 68 | /** 69 | Indicates an empty latitude or longitude component 70 | */ 71 | static const CLLocationDegrees LNEmptyLocation = 0.000000; 72 | 73 | 74 | @interface LN_LaunchNavigator : NSObject {} 75 | 76 | typedef void (^NavigateSuccessBlock)(void); 77 | typedef void (^NavigateFailBlock)(NSString* errorMsg); 78 | typedef void(^LocationSuccessBlock)(CLLocation*); 79 | typedef void(^LocationErrorBlock)(NSError*); 80 | 81 | @property (nonatomic, strong) NavigateSuccessBlock navigateSuccess; 82 | @property (nonatomic, strong) NavigateFailBlock navigateFail; 83 | @property (nonatomic, strong) LocationSuccessBlock locationSuccess; 84 | @property (nonatomic, strong) LocationErrorBlock locationError; 85 | @property (retain, nonatomic) CLLocationManager* locationManager; 86 | 87 | /******************* 88 | * Public API 89 | *******************/ 90 | - (id)init:(WE_Logger*) logger; 91 | - (void)setLogger:(WE_Logger*) logger; 92 | - (WE_Logger*)getLogger; 93 | - (void) navigate:(NSDictionary*)params 94 | success:(NavigateSuccessBlock)success 95 | fail:(NavigateFailBlock)fail; 96 | - (BOOL) isAppAvailable:(NSString*)appName; 97 | - (NSDictionary*) availableApps; 98 | 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /ios/RNLaunchNavigator/LN_Reachability.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | Basic demonstration of how to use the SystemConfiguration Reachablity APIs. 7 | */ 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | 14 | typedef enum : NSInteger { 15 | NotReachable = 0, 16 | ReachableViaWiFi, 17 | ReachableViaWWAN 18 | } NetworkStatus; 19 | 20 | #pragma mark IPv6 Support 21 | //Reachability fully support IPv6. For full details, see ReadMe.md. 22 | 23 | 24 | extern NSString *kReachabilityChangedNotification; 25 | 26 | 27 | @interface LN_Reachability : NSObject 28 | 29 | /*! 30 | * Use to check the reachability of a given host name. 31 | */ 32 | + (instancetype)reachabilityWithHostName:(NSString *)hostName; 33 | 34 | /*! 35 | * Use to check the reachability of a given IP address. 36 | */ 37 | + (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress; 38 | 39 | /*! 40 | * Checks whether the default route is available. Should be used by applications that do not connect to a particular host. 41 | */ 42 | + (instancetype)reachabilityForInternetConnection; 43 | 44 | 45 | #pragma mark reachabilityForLocalWiFi 46 | //reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information. 47 | //+ (instancetype)reachabilityForLocalWiFi; 48 | 49 | /*! 50 | * Start listening for reachability notifications on the current run loop. 51 | */ 52 | - (BOOL)startNotifier; 53 | - (void)stopNotifier; 54 | 55 | - (NetworkStatus)currentReachabilityStatus; 56 | 57 | /*! 58 | * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand. 59 | */ 60 | - (BOOL)connectionRequired; 61 | 62 | @end 63 | 64 | 65 | -------------------------------------------------------------------------------- /ios/RNLaunchNavigator/LN_Reachability.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | Basic demonstration of how to use the SystemConfiguration Reachablity APIs. 7 | */ 8 | 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import 14 | 15 | #import 16 | 17 | #import "LN_Reachability.h" 18 | 19 | #pragma mark IPv6 Support 20 | //Reachability fully support IPv6. For full details, see ReadMe.md. 21 | 22 | 23 | NSString *kLNReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification"; 24 | 25 | 26 | #pragma mark - Supporting functions 27 | 28 | #define kShouldPrintReachabilityFlags 1 29 | 30 | static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) 31 | { 32 | #if kShouldPrintReachabilityFlags 33 | 34 | NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", 35 | (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', 36 | (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', 37 | 38 | (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', 39 | (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', 40 | (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', 41 | (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', 42 | (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', 43 | (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', 44 | (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', 45 | comment 46 | ); 47 | #endif 48 | } 49 | 50 | 51 | static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) 52 | { 53 | #pragma unused (target, flags) 54 | NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); 55 | NSCAssert([(__bridge NSObject*) info isKindOfClass: [LN_Reachability class]], @"info was wrong class in ReachabilityCallback"); 56 | 57 | LN_Reachability* noteObject = (__bridge LN_Reachability *)info; 58 | // Post a notification to notify the client that the network reachability changed. 59 | [[NSNotificationCenter defaultCenter] postNotificationName: kLNReachabilityChangedNotification object: noteObject]; 60 | } 61 | 62 | 63 | #pragma mark - LN_Reachability implementation 64 | 65 | @implementation LN_Reachability 66 | { 67 | SCNetworkReachabilityRef _reachabilityRef; 68 | } 69 | 70 | + (instancetype)reachabilityWithHostName:(NSString *)hostName 71 | { 72 | LN_Reachability* returnValue = NULL; 73 | SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); 74 | if (reachability != NULL) 75 | { 76 | returnValue= [[self alloc] init]; 77 | if (returnValue != NULL) 78 | { 79 | returnValue->_reachabilityRef = reachability; 80 | } 81 | else { 82 | CFRelease(reachability); 83 | } 84 | } 85 | return returnValue; 86 | } 87 | 88 | 89 | + (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress 90 | { 91 | SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress); 92 | 93 | LN_Reachability* returnValue = NULL; 94 | 95 | if (reachability != NULL) 96 | { 97 | returnValue = [[self alloc] init]; 98 | if (returnValue != NULL) 99 | { 100 | returnValue->_reachabilityRef = reachability; 101 | } 102 | else { 103 | CFRelease(reachability); 104 | } 105 | } 106 | return returnValue; 107 | } 108 | 109 | 110 | + (instancetype)reachabilityForInternetConnection 111 | { 112 | struct sockaddr_in zeroAddress; 113 | bzero(&zeroAddress, sizeof(zeroAddress)); 114 | zeroAddress.sin_len = sizeof(zeroAddress); 115 | zeroAddress.sin_family = AF_INET; 116 | 117 | return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress]; 118 | } 119 | 120 | #pragma mark reachabilityForLocalWiFi 121 | //reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information. 122 | //+ (instancetype)reachabilityForLocalWiFi 123 | 124 | 125 | 126 | #pragma mark - Start and stop notifier 127 | 128 | - (BOOL)startNotifier 129 | { 130 | BOOL returnValue = NO; 131 | SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; 132 | 133 | if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)) 134 | { 135 | if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) 136 | { 137 | returnValue = YES; 138 | } 139 | } 140 | 141 | return returnValue; 142 | } 143 | 144 | 145 | - (void)stopNotifier 146 | { 147 | if (_reachabilityRef != NULL) 148 | { 149 | SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 150 | } 151 | } 152 | 153 | 154 | - (void)dealloc 155 | { 156 | [self stopNotifier]; 157 | if (_reachabilityRef != NULL) 158 | { 159 | CFRelease(_reachabilityRef); 160 | } 161 | } 162 | 163 | 164 | #pragma mark - Network Flag Handling 165 | 166 | - (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags 167 | { 168 | PrintReachabilityFlags(flags, "networkStatusForFlags"); 169 | if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) 170 | { 171 | // The target host is not reachable. 172 | return NotReachable; 173 | } 174 | 175 | NetworkStatus returnValue = NotReachable; 176 | 177 | if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) 178 | { 179 | /* 180 | If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi... 181 | */ 182 | returnValue = ReachableViaWiFi; 183 | } 184 | 185 | if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || 186 | (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) 187 | { 188 | /* 189 | ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs... 190 | */ 191 | 192 | if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) 193 | { 194 | /* 195 | ... and no [user] intervention is needed... 196 | */ 197 | returnValue = ReachableViaWiFi; 198 | } 199 | } 200 | 201 | if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) 202 | { 203 | /* 204 | ... but WWAN connections are OK if the calling application is using the CFNetwork APIs. 205 | */ 206 | returnValue = ReachableViaWWAN; 207 | } 208 | 209 | return returnValue; 210 | } 211 | 212 | 213 | - (BOOL)connectionRequired 214 | { 215 | NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); 216 | SCNetworkReachabilityFlags flags; 217 | 218 | if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) 219 | { 220 | return (flags & kSCNetworkReachabilityFlagsConnectionRequired); 221 | } 222 | 223 | return NO; 224 | } 225 | 226 | 227 | - (NetworkStatus)currentReachabilityStatus 228 | { 229 | NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef"); 230 | NetworkStatus returnValue = NotReachable; 231 | SCNetworkReachabilityFlags flags; 232 | 233 | if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) 234 | { 235 | returnValue = [self networkStatusForFlags:flags]; 236 | } 237 | 238 | return returnValue; 239 | } 240 | 241 | 242 | @end 243 | -------------------------------------------------------------------------------- /ios/RNLaunchNavigator/RNLaunchNavigator.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "LN_LaunchNavigator.h" 4 | 5 | @interface RNLaunchNavigator : RCTEventEmitter 6 | @property (nonatomic, retain) LN_LaunchNavigator* launchNavigator; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /ios/RNLaunchNavigator/RNLaunchNavigator.m: -------------------------------------------------------------------------------- 1 | #import "RNLaunchNavigator.h" 2 | #import "WE_ReactNativeLogger.h" 3 | 4 | @interface RNLaunchNavigator() 5 | @end 6 | 7 | @implementation RNLaunchNavigator 8 | @synthesize launchNavigator; 9 | 10 | // Internal constants 11 | static NSString*const ERROR_CODE_EXCEPTION = @"EXCEPTION"; 12 | static NSString*const ERROR_CODE_ERROR = @"ERROR"; 13 | static long ERROR_CODE_EXCEPTION_CODE = 0; 14 | 15 | // Internal variables; 16 | static WE_ReactNativeLogger* logger; 17 | static BOOL isListening = false; 18 | static BOOL isLoggerEnabled = false; 19 | 20 | RCT_EXPORT_MODULE(RNLaunchNavigator) 21 | 22 | /********************************/ 23 | #pragma mark - overrides 24 | /********************************/ 25 | - (instancetype)init{ 26 | if(self = [super init]){ 27 | logger = [[WE_ReactNativeLogger alloc] init:self logTag:@"RNLaunchNavigator[native]"]; 28 | self.launchNavigator = [[LN_LaunchNavigator alloc] init:[[WE_ReactNativeLogger alloc] init:self logTag:@"LaunchNavigator[native]"]]; 29 | } 30 | return self; 31 | } 32 | 33 | + (BOOL)requiresMainQueueSetup{ 34 | return YES; 35 | } 36 | 37 | - (NSArray*) supportedEvents{ 38 | NSMutableArray* events = [NSMutableArray arrayWithArray:[logger getEventNames]]; 39 | return [events copy]; 40 | } 41 | 42 | - (void)startObserving{ 43 | isListening = YES; 44 | [self applyLoggerEnabled]; 45 | } 46 | 47 | - (void)stopObserving{ 48 | isListening = NO; 49 | [self applyLoggerEnabled]; 50 | } 51 | 52 | /**********************************/ 53 | #pragma mark - module API functions 54 | /**********************************/ 55 | RCT_EXPORT_METHOD(setGoogleApiKey:(NSString*)googleApiKey){ 56 | [logger info:@"setGoogleApiKey not implemented/required on iOS"]; 57 | } 58 | 59 | RCT_EXPORT_METHOD(enableDebug:(BOOL)enabled){ 60 | [self _setLoggerEnabled:enabled]; 61 | } 62 | 63 | RCT_EXPORT_METHOD(isAppAvailable:(NSString*) app 64 | resolve:(RCTPromiseResolveBlock) resolve 65 | reject:(RCTPromiseRejectBlock) reject) 66 | { 67 | @try { 68 | BOOL result = [self.launchNavigator isAppAvailable:app]; 69 | resolve([NSNumber numberWithBool:result]); 70 | } 71 | @catch (NSException* exception) { 72 | [logger error: exception.reason]; 73 | reject(ERROR_CODE_EXCEPTION, exception.reason, [self exceptionToError:exception]); 74 | } 75 | } 76 | 77 | RCT_EXPORT_METHOD(getAvailableApps:(RCTPromiseResolveBlock) resolve 78 | reject:(RCTPromiseRejectBlock) reject) 79 | { 80 | @try { 81 | NSDictionary* results = [launchNavigator availableApps]; 82 | resolve(results); 83 | } 84 | @catch (NSException* exception) { 85 | [logger error: exception.reason]; 86 | reject(ERROR_CODE_EXCEPTION, exception.reason, [self exceptionToError:exception]); 87 | } 88 | } 89 | 90 | RCT_EXPORT_METHOD(navigate:(NSDictionary*) params 91 | resolve:(RCTPromiseResolveBlock) resolve 92 | reject:(RCTPromiseRejectBlock) reject) 93 | { 94 | @try { 95 | NSString* logMsg = @"Called navigate() with args: "; 96 | for(id object in params){ 97 | NSString* key = object; 98 | NSString* value = [params objectForKey:key]; 99 | logMsg = [NSString stringWithFormat:@"%@ %@=%@;", logMsg, key, value]; 100 | } 101 | [logger debug:logMsg]; 102 | 103 | [launchNavigator navigate:params 104 | success:^(void) { 105 | resolve(nil); 106 | } 107 | fail:^(NSString* errorMsg) { 108 | reject(ERROR_CODE_ERROR, errorMsg, nil); 109 | } 110 | ]; 111 | 112 | 113 | } 114 | @catch (NSException* exception) { 115 | [logger error: exception.reason]; 116 | reject(ERROR_CODE_EXCEPTION, exception.reason, [self exceptionToError:exception]); 117 | } 118 | } 119 | 120 | 121 | /********************************/ 122 | #pragma mark - internal functions 123 | /********************************/ 124 | -(void)_setLoggerEnabled:(BOOL)enabled{ 125 | isLoggerEnabled = enabled; 126 | [self applyLoggerEnabled]; 127 | } 128 | 129 | -(void)applyLoggerEnabled{ 130 | BOOL enabled = isListening && isLoggerEnabled; 131 | [logger setEnabled:enabled]; 132 | [[self.launchNavigator getLogger] setEnabled:enabled]; 133 | } 134 | 135 | - (NSError*) exceptionToError: (NSException*)exception 136 | { 137 | NSMutableDictionary * info = [NSMutableDictionary dictionary]; 138 | [info setValue:ERROR_CODE_EXCEPTION forKey:@"ExceptionCode"]; 139 | [info setValue:exception.name forKey:@"ExceptionName"]; 140 | [info setValue:exception.reason forKey:@"ExceptionReason"]; 141 | [info setValue:exception.callStackReturnAddresses forKey:@"ExceptionCallStackReturnAddresses"]; 142 | [info setValue:exception.callStackSymbols forKey:@"ExceptionCallStackSymbols"]; 143 | [info setValue:exception.userInfo forKey:@"ExceptionUserInfo"]; 144 | return [[NSError alloc] initWithDomain:[[NSBundle mainBundle] bundleIdentifier] code:ERROR_CODE_EXCEPTION_CODE userInfo:info]; 145 | } 146 | 147 | @end 148 | -------------------------------------------------------------------------------- /ios/RNLaunchNavigator/WE_Logger.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface WE_Logger : NSObject 4 | 5 | @property (nonatomic) BOOL enabled; 6 | 7 | -(id)init; 8 | -(void)setEnabled:(BOOL)enabled; 9 | -(BOOL)getEnabled; 10 | -(void)error:(NSString*)msg; 11 | -(void)warn:(NSString*)msg; 12 | -(void)info:(NSString*)msg; 13 | -(void)debug:(NSString*)msg; 14 | -(void)verbose:(NSString*)msg; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/RNLaunchNavigator/WE_Logger.m: -------------------------------------------------------------------------------- 1 | #import "WE_Logger.h" 2 | 3 | @implementation WE_Logger 4 | @synthesize enabled; 5 | 6 | static BOOL enabled = FALSE; 7 | 8 | /******************* 9 | * Public API 10 | *******************/ 11 | -(id)init{ 12 | if(self = [super init]){ 13 | 14 | } 15 | return self; 16 | } 17 | 18 | -(void)setEnabled:(BOOL)_enabled{ 19 | enabled = _enabled; 20 | } 21 | 22 | -(BOOL)getEnabled{ 23 | return enabled; 24 | } 25 | 26 | -(void)error:(NSString*)msg{ 27 | [self throwException:@"error() must be overriden by subclass"]; 28 | } 29 | 30 | -(void)warn:(NSString*)msg{ 31 | [self throwException:@"warn() must be overriden by subclass"]; 32 | } 33 | 34 | -(void)info:(NSString*)msg{ 35 | [self throwException:@"info() must be overriden by subclass"]; 36 | } 37 | 38 | -(void)debug:(NSString*)msg{ 39 | [self throwException:@"debug() must be overriden by subclass"]; 40 | } 41 | 42 | -(void)verbose:(NSString*)msg{ 43 | [self throwException:@"verbose() must be overriden by subclass"]; 44 | } 45 | 46 | /********************* 47 | * Internal functions 48 | **********************/ 49 | 50 | -(void)throwException:(NSString*)reason{ 51 | @throw([NSException exceptionWithName:reason reason:reason userInfo:nil]); 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /ios/RNLaunchNavigator/WE_ReactNativeLogger.h: -------------------------------------------------------------------------------- 1 | #import "WE_Logger.h" 2 | #import 3 | 4 | @interface WE_ReactNativeLogger : WE_Logger 5 | 6 | @property (nonatomic, weak) RCTEventEmitter * eventEmitter; 7 | @property (nonatomic, retain) NSString* logTag; 8 | 9 | -(id)init:(RCTEventEmitter *)eventEmitter logTag:(NSString*)logTag; 10 | -(NSArray*)getEventNames; 11 | -(void)error:(NSString*) msg; 12 | -(void)warn:(NSString*) msg; 13 | -(void)info:(NSString*) msg; 14 | -(void)debug:(NSString*) msg; 15 | -(void)verbose:(NSString*) msg; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /ios/RNLaunchNavigator/WE_ReactNativeLogger.m: -------------------------------------------------------------------------------- 1 | #import "WE_ReactNativeLogger.h" 2 | #import 3 | 4 | @implementation WE_ReactNativeLogger; 5 | @synthesize eventEmitter; 6 | @synthesize logTag; 7 | 8 | /********************** 9 | * Internal properties 10 | **********************/ 11 | static NSArray* eventNames; 12 | 13 | /******************* 14 | * Public API 15 | *******************/ 16 | -(id)init:(RCTEventEmitter *)eventEmitter logTag:(NSString*)logTag{ 17 | if(self = [super init]){ 18 | self.eventEmitter = eventEmitter; 19 | self.logTag = logTag; 20 | eventNames = @[ 21 | @"console.error", 22 | @"console.warn", 23 | @"console.info", 24 | @"console.log", 25 | @"console.debug" 26 | ]; 27 | } 28 | return self; 29 | } 30 | 31 | -(void)error:(NSString*) msg{ 32 | [self log:msg jsLogLevel:@"error" nsLogLevel:@"error"]; 33 | } 34 | 35 | -(void)warn:(NSString*) msg{ 36 | [self log:msg jsLogLevel:@"warn" nsLogLevel:@"warn"]; 37 | } 38 | 39 | -(void)info:(NSString*) msg{ 40 | [self log:msg jsLogLevel:@"info" nsLogLevel:@"info"]; 41 | } 42 | 43 | -(void)debug:(NSString*) msg{ 44 | [self log:msg jsLogLevel:@"log" nsLogLevel:@"debug"]; 45 | } 46 | 47 | -(void)verbose:(NSString*) msg{ 48 | [self log:msg jsLogLevel:@"debug" nsLogLevel:@"verbose"]; 49 | } 50 | 51 | -(NSArray*)getEventNames{ 52 | return eventNames; 53 | } 54 | 55 | /********************* 56 | * Internal functions 57 | **********************/ 58 | - (void)log: (NSString*)msg jsLogLevel:(NSString*)jsLogLevel nsLogLevel:(NSString*)nsLogLevel 59 | { 60 | if(self.enabled){ 61 | NSLog(@"%@[%@]: %@", self.logTag, nsLogLevel, msg); 62 | [self.eventEmitter sendEventWithName:[NSString stringWithFormat:@"console.%@",jsLogLevel] body:@{@"logTag": [RCTConvert NSString:self.logTag], @"message": [RCTConvert NSString:msg]}]; 63 | } 64 | } 65 | @end 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-launch-navigator", 3 | "version": "1.0.9", 4 | "description": "A React Native module for launching today's most popular navigation/ride apps to navigate to a destination.", 5 | "main": "index.js", 6 | "types": "./index.d.ts", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/dpa99c/react-native-launch-navigator.git" 10 | }, 11 | "homepage": "https://github.com/dpa99c/react-native-launch-navigator", 12 | "issue": "https://github.com/dpa99c/react-native-launch-navigator/issues", 13 | "author": "Dave Alden", 14 | "license": "MIT", 15 | "keywords": [ 16 | "react-component", 17 | "react-native", 18 | "ios", 19 | "android", 20 | "navigation", 21 | "navigator", 22 | "launch" 23 | ], 24 | "peerDependencies": { 25 | "react-native": ">=0.60.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /react-native.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | --------------------------------------------------------------------------------