# @nativescript/geolocation

## Contents
* [Intro](#intro)
* [Installation](#installation)
* [Android permissions requirements](#android-permissions-requirements)
* [iOS permissions requirements](#ios-permissions-requirements)
* [Use @nativescript/geolocation](#use-nativescriptgeolocation)
  * [Get current location](#get-current-location)
* [API](#api)
  * [Plugin functions](#plugin-functions)
  * [Location class](#location-class)
  * [Options interface](#options-interface)
* [Known Issues](#known-issues)
  * [Version conflicts with Google Play Services](#version-conflicts-with-google-play-services)
  * [openSettingsIfLocationHasBeenDenied on Android API level 30](#opensettingsiflocationhasbeendenied-on-android-api-level-30)

## Intro

A geolocation plugin to use for getting current location, monitor movement, etc.

## Installation

To install the plugin, run the following command in the  root  of your project.

```cli
npm install @nativescript/geolocation
```

## Android permissions requirements

To use geolocation on Android, you need to add the following permissions to your app's `AndroidManifest.xml` inside the `App_Resources/Android/src/main` directory:

```xml
  <!-- Always include this permission -->
  <!-- This permission is for "approximate" location data -->
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

  <!-- Include only if your app benefits from precise location access. -->
  <!-- This permission is for "precise" location data -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

  <!-- Required only when requesting background location access on
       Android 10 (API level 29) and higher. -->
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
```

More information can be found in the [Android docs here](https://developer.android.com/training/location/permissions).

## iOS permissions requirements

If `iosAllowsBackgroundLocationUpdates` property of the [options](#options-interface) object is set to `true`, the following code is required in the `App_Resources/iOS/Info.plist` file:

```xml
<key>UIBackgroundModes</key>
<array>
  <string>location</string>
</array>
```

## Use @nativescript/geolocation

### Get current location

Before you call any method that gets the user's location, request for the user's permission by calling the `enableLocationRequest` method. Once the user has granted the permission, you can call the `getCurrentLocation()` method, passing it a [options](#options) object to get the user's current location.

```ts
import * as geolocation from '@nativescript/geolocation';
import { CoreTypes } from '@nativescript/core' // used to describe at what accuracy the location should get

geolocation.enableLocationRequest().then(() => {
    
    geolocation.getCurrentLocation({ desiredAccuracy: CoreTypes.Accuracy.high, maximumAge: 5000, timeout: 20000 }).then((currentLocation) => {

      console.log("My current latitude: ", currentLocation.latitude)
    })
  })
```

## API
### Plugin functions

The plugin provides the following functions for getting current location and more:

| Method  | Returns    | Description |
|---------|------------|-------------|
| `getCurrentLocation(options: Options)`                                                                   | Promise\<[Location](#location)\> | Gets current location applying the specified options (if any). Since version 5.0 of the plugin, it will use [requestLocation](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620548-requestlocation?language=objc) API for devices using `iOS 9.0+`. In situation of poor or no GPS signal, but available Wi-Fi it will take 10 sec to return the location.<br> The `options` parameter is optional. |
| `watchLocation(successCallback: successCallbackType, errorCallback: errorCallbackType, options?: Options)` | `number`              | Monitors location change.   |
| `watchPermissionStatus(permissionCallback: permissionCallbackType, errorCallback: errorCallbackType)`      | `number`              | (`iOS-only`)Monitors a change in location permission.|
| `clearWatch(watchId: number)` | `void` | Stops monitoring a change in location. The `watchId` parameter is returned from the `watchLocation()` method.  |
| `enableLocationRequest(always?: boolean, openSettingsIfLocationHasBeenDenied?: boolean`                   | `Promise<void> `    | Asks for permissions to use location services. On iOS if `always` is `true`, add the following keys to the `Info.plist`: [NSLocationAlwaysAndWhenInUseUsageDescription](https://developer.apple.com/documentation/bundleresources/information_property_list/nslocationalwaysandwheninuseusagedescription) (iOS 11.0+) OR [NSLocationAlwaysUsageDescription](https://developer.apple.com/documentation/bundleresources/information_property_list/nslocationalwaysusagedescription?language=objc) (iOS 8.0-10.0) and [NSLocationWhenInUseUsageDescription](https://developer.apple.com/documentation/bundleresources/information_property_list/nslocationwheninuseusagedescription). Read more about [request always usage](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620551-requestalwaysauthorization). On Android `SDK >= 29`, the `always` parameter set to `true` requires the  `ACCESS_BACKGROUND_LOCATION` permission to be added to the `AndroidManifest.xml`. That results in the user getting a system dialog with the option `'allow all the time'` option. Read about Android location permissions [here](https://developer.android.com/training/location/permissions) and [here](https://developer.android.com/training/location/permissions#request-background-location). If `openSettingsIfLocationHasBeenDenied` is `true` and the permission has previously been denied then the Settings app will open so the user can change the location services permission. See the [exception](#android-api-level-30---opensettingsiflocationhasbeendenied) to this.|
|`isEnabled(options?: Options)` | `Promise<boolean>`  | Resolves `true` or `false` based on the location services availability. |
| `distance(loc1: Location, loc2: Location)`  | `number ` | Calculates the distance between two locations. Returns the distance in meters. |
| `getIOSLocationManagerStatus()`| [CLAuthorizationStatus](https://developer.apple.com/documentation/corelocation/clauthorizationstatus?language=objc)|  Returns the status of the Location Authorization permission.|

### Location class
 
 This is a data class that encapsulates the following common properties for a geolocation.


| Property           | Type | Description                                             |
| ------------------ |------|------------------------------------------------------- |
| `latitude`         | `number`| The latitude of the geolocation, in degrees.            |
| `longitude`        | `number`|  The longitude of the geolocation, in degrees.           |
| `altitude`         | `number`|  The altitude (if available), in meters above sea level. |
| `horizontalAccuracy` | `number`|  The horizontal accuracy, in meters.                     |
| `verticalAccuracy`   | `number`|  The vertical accuracy, in meters.                       |
| `speed`              | `number`|  The speed, in meters/second over ground.                |
| `timestamp`          | `Date`|  The time at which this location was determined.         |


### Options interface

The following are the properties of the options object that you pass to the geolocation [functions](#plugin-functions) of the plugin.

| Property | Type | Description
|:---------|:-----|:-----------
| `desiredAccuracy` | `CoreTypes.Accuracy` | _Optional_: Specifies if high accuracy or any is required. Defaults to `CoreTypes.Accuracy.high` which returns the finest location available but use more power than the `CoreTypes.Accuracy.any` option. `Accuracy.any` is considered to be about 100 meter accuracy.                                                               
| `updateDistance`                       | `number`     | _Optional_: Specifies how often to update the location. Update distance filter in meters. Read more in [Apple document](https://developer.apple.com/documentation/corelocation/cllocationmanager/1423500-distancefilter?language=objc) and/or [Google documents](<https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#setSmallestDisplacement(float)>) |
| `updateTime`                            | `number`      | Interval between location updates, in milliseconds (ignored on iOS). Read more in [Google document](<https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest#setInterval(long)>).  Defaults to `1 minute`|
| `minimumUpdateTime`                     | `number` | _Optional_: Minimum time interval between location updates, in milliseconds (ignored on iOS). Read more in [Google document](<https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest#setFastestInterval(long)>).                                                                                                                                               |
| `maximumAge`                            | `number` | _Optional_: The maximum age of the location data, in `ms`. |
| `timeout`                               |  `number` | _Optional_: It indicates how long, in `ms`, to wait for a location. Defaults to `5 minutes`. |
| `iosAllowsBackgroundLocationUpdates`    | `boolean`         |_Optional_: Indicates whether to allow the application to receive location updates in the background (ignored on Android). Defaults to `false`. If enabled, the `UIBackgroundModes` key in `Info.plist` is required. A. Read more in [Apple document](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620568-allowsbackgroundlocationupdates?language=objc)                                                     |
| `iosPausesLocationUpdatesAutomatically` | `boolean`          | Indicates whether to allow the deactivation of the automatic pause of location updates (ignored on Android). Read more in [Apple document](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620553-pauseslocationupdatesautomatical?language=objc)                                                                                                                                          |

## Breaking changes

- 9.0+:
  - `watchLocation` is now `async` in order to check for permissions before attempting to watch
## Known issues

### openSettingsIfLocationHasBeenDenied on Android API level 30

If the user declines the permission twice during the installation lifetime of the app on Android API level 30 , the user won't be taken to the settings even if the `openSettingsIfLocationHasBeenDenied` option is true for `enableLocationRequest()`.

## License

Apache License Version 2.0