react-native-map-link
Version:
Open the map app of the user's choice with a specific location.
353 lines (299 loc) • 12.4 kB
Markdown

[](https://www.npmjs.com/package/react-native-map-link)
[](https://www.npmjs.com/package/react-native-map-link)
[](https://github.com/flexible-agency/react-native-map-link/blob/master/LICENSE)
---
An easy way to open a location in a map app of the user's choice, based on the apps they have installed
on their device. The app supports Apple Maps, Google Maps, Citymapper, Uber, and a dozen other apps.
<details>
<summary><strong>Full list of supported apps</strong></summary>
- Apple Maps – `apple-maps`
- Google Maps – `google-maps`
- Citymapper – `citymapper`
- Uber – `uber`
- Lyft – `lyft`
- The Transit App – `transit`
- TruckMap – `truckmap`
- Waze – `waze`
- Yandex.Navi – `yandex`
- Moovit – `moovit`
- Yandex Taxi – `yandex-taxi`
- Yandex Maps – `yandex-maps`
- Kakao Map – `kakaomap`
- TMAP - `tmap`
- Mapy.cz – `mapycz`
- Maps.me – `maps-me`
- OsmAnd - `osmand`
- Gett - `gett`
- Naver Map - `navermap`
- 2GIS - `dgis`
- Liftago - `liftago`
- Petal Maps - `petalmaps` (Android only)
- Sygic - `sygic`
</details>
<br /><p align="center">
<img src="./docs/example.png" alt="Example screenshot" width="320" />
</p>
## Installation
### 1. Install the package
```shell
npm i -S react-native-map-link # or yarn add react-native-map-link
```
### 2. Post-install steps
Based on the platforms your app supports, you also need to:
<details id="iOSPostInstall">
<summary><strong>iOS – Update Info.plist</strong></summary>
To allow your app to detect if any of the directions apps are installed, an extra step is required on iOS. Your app needs to provide the `LSApplicationQueriesSchemes` key inside `ios/{my-project}/Info.plist` to specify the URL schemes with which the app can interact.
Just add this in your `Info.plist` depending on which apps you'd like to support. Omitting these might mean that the library can't detect some of the maps apps installed by the user.
```xml
<key>LSApplicationQueriesSchemes</key>
<array>
<string>comgooglemaps</string>
<string>citymapper</string>
<string>uber</string>
<string>lyft</string>
<string>transit</string>
<string>truckmap</string>
<string>waze</string>
<string>yandexnavi</string>
<string>moovit</string>
<string>yandextaxi</string>
<string>yandexmaps</string>
<string>kakaomap</string>
<string>tmap</string>
<string>szn-mapy</string>
<string>mapsme</string>
<string>osmandmaps</string>
<string>gett</string>
<string>nmap</string>
<string>dgis</string>
<string>lftgpas</string>
<string>sygic</string>
</array>
```
Using Expo? [Read the instructions](docs/expo.md) to make it work on iOS.
</details>
<details id="androidPostInstall">
<summary><strong>Android – Update AndroidManifest.xml</strong></summary>
When switching to Android 11/Android SDK 30 (i.e. using Expo SDK 41), this library doesn't work out of the box anymore. The reason is the new [Package Visibilty](https://developer.android.com/training/package-visibility) security feature. We'll have to update our `AndroidManifest.xml` to explicitly allow querying for other apps.
You can do so by coping the `<queries>` statement below, and pasting it in the top level of your AndroidManifest (i.e. within the `<manifest> ... </manifest>`).
```xml
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http"/>
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https"/>
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="geo" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="google.navigation" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="applemaps" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="citymapper" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="uber" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="lyft" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="transit" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="truckmap" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="waze" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="yandexnavi" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="moovit" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="yandexmaps://maps.yandex." />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="yandextaxi" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="kakaomap" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tmap" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="mapycz" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="mapsme" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="osmand.geo" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="gett" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="nmap" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="dgis" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="lftgpas" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="petalmaps" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="com.sygic.aura" />
</intent>
</queries>
```
If you're running into a 'unexpected element `<queries>` found in `<manifest>`' error, make sure you have an updated version of Gradle in your `android/build.gradle` file:
```java
classpath("com.android.tools.build:gradle:3.5.4")
```
More info [here](https://stackoverflow.com/a/67383641/1129689).
</details>
<details>
<summary><strong>Expo – Update app.json</strong></summary>
[Read the instructions here](docs/expo.md)
</details>
## Simple example
```js
import {showLocation} from 'react-native-map-link';
showLocation({
latitude: 38.8976763,
longitude: -77.0387185,
title: 'Your destination',
});
```
## Full usage
Using the `showLocation` function will shown an action sheet on iOS and an alert on Android, without any custom styling:
```js
import {showLocation} from 'react-native-map-link';
showLocation({
latitude: 38.8976763,
longitude: -77.0387185,
sourceLatitude: -8.0870631, // optionally specify starting location for directions
sourceLongitude: -34.8941619, // required if sourceLatitude is specified
title: 'The White House', // optional
googleForceLatLon: false, // optionally force GoogleMaps to use the latlon for the query instead of the title
googlePlaceId: 'ChIJGVtI4by3t4kRr51d_Qm_x58', // optionally specify the google-place-id
alwaysIncludeGoogle: true, // optional, true will always add Google Maps to iOS and open in Safari, even if app is not installed (default: false)
dialogTitle: 'This is the dialog Title', // optional (default: 'Open in Maps')
dialogMessage: 'This is the amazing dialog Message', // optional (default: 'What app would you like to use?')
cancelText: 'This is the cancel button text', // optional (default: 'Cancel')
appsWhiteList: ['google-maps'], // optionally you can set which apps to show (default: will show all supported apps installed on device)
appsBlackList: ['uber'], // optionally you can set which apps NOT to show (default: will show all supported apps installed on device)
naverCallerName: 'com.example.myapp', // to link into Naver Map You should provide your appname which is the bundle ID in iOS and applicationId in android.
appTitles: {'google-maps': 'My custom Google Maps title'}, // optionally you can override default app titles
app: 'uber', // optionally specify specific app to use
directionsMode: 'walk', // optional, accepted values are 'car', 'walk', 'public-transport' or 'bike'
});
```
Alternatively you can specify the `address` field and leave the latitude and longitude properties as empty strings
```js
import {showLocation} from 'react-native-map-link';
showLocation({
address: '1600 Pennsylvania Avenue NW, Washington, DC 20500', // Required if replacing latitude and longitude
app: 'comgooglemaps', // optionally specify specific app to use
});
```
Notes:
- The `sourceLatitude` / `sourceLongitude` options only work if you specify both. Currently supports all apps except Waze.
- `directionsMode` works on google-maps, apple-maps and sygic (on apple-maps, `bike` mode will not work, while on sygic, only `walk` and `car` will work). Without setting it, the app will decide based on its own settings.
- If you set `directionsMode` but do not set `sourceLatitude` and `sourceLongitude`, google-maps and apple-maps will still enter directions mode, and use the current location as starting point.
- If you want to query an address instead of passing the `latitude` and `longitude` fields, you can do this by leaving those fields off and provide a full address to be queried with the `address` field. Just be aware that not all applications support this.
### Or
Using the `getApps` function will return an array (`GetAppResult[]`) with the apps available on the smartphone:
```ts
type GetAppResult = {
id: string;
name: string;
icon: NodeRequire;
open: () => Promise<void>;
};
```
```tsx
import {getApps, GetAppResult} from 'react-native-map-link';
const Demo = () => {
const [availableApps, setAvailableApps] = useState<GetAppResult[]>([]);
useEffect(() => {
(async () => {
const result = await getApps({
latitude: 38.8976763,
longitude: -77.0387185,
address: '1600 Pennsylvania Avenue NW, Washington, DC 20500', // optional
title: 'The White House', // optional
googleForceLatLon: false, // optionally force GoogleMaps to use the latlon for the query instead of the title
alwaysIncludeGoogle: true, // optional, true will always add Google Maps to iOS and open in Safari, even if app is not installed (default: false)
appsWhiteList: ['google-maps'], // optionally you can set which apps to show (default: will show all supported apps installed on device)
appsBlackList: ['uber'], // optionally you can set which apps NOT to show (default: will show all supported apps installed on device)
});
setAvailableApps(result);
})();
}, []);
return (
<React.Fragment>
{availableApps.map(({icon, name, id, open}) => (
<Pressable key={id} onPress={open}>
<Image source={icon} />
<Text>{name}</Text>
</Pressable>
))}
</React.Fragment>
);
};
```
## More information
- [Using this library with Expo](docs/expo.md)
- [Alternative usage: styled popup](docs/popup.md)
- [Adding support for new maps apps](docs/add-app.md)
<br /><br />
---
<div align="center">
<b>
<a href="https://schof.co/consulting/?utm_source=flexible-agency/react-native-map-link">Get professional support for this package →</a>
</b>
<br>
<sub>
Custom consulting sessions available for implementation support or feature development.
</sub>
</div>