Skip to content

Commit

Permalink
Updated location topic with nativescript-geolocation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Nedyalko Nikolov authored and ErjanGavalji committed Jan 7, 2016
1 parent 56d0ca9 commit 0cf2d8c
Showing 1 changed file with 164 additions and 74 deletions.
238 changes: 164 additions & 74 deletions hardware/location.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,106 +8,196 @@ previous_url: /location

# Location

The NativeScript location module uses an accuracy criteria approach to deliver geolocation. This means that getting (or monitoring) a location is powered by the most accurate location provider that is available (for example if GPS signal is available and the GPS provider is enabled, then it will be used; if GPS is not connected, the device falls back to other available providers such as Wi-Fi networks or cell towers).
With the 1.5.0 release nativescript location module has been deprecated. There is a plugin called `nativescript-geolocation` (available on npmjs.com) which can be used instead. This plugin provide API similar to WC3 geolocation API [WC3-API](http://dev.w3.org/geo/api/spec-source.html). The most important change is that location monitoring returns and `id` which can be used to stop location monitoring. Plugin again uses an accuracy criteria approach to deliver geolocation. This means that getting (or monitoring) a location is powered by the most accurate location provider that is available (for example if GPS signal is available and the GPS provider is enabled, then it will be used; if GPS is not connected, the device falls back to other available providers such as Wi-Fi networks or cell towers).

This approach does not limit location monitoring only to a specific location provider; it can still work with all of them.

It is a good idea to start with the [How-to]({{site.baseurl}}/ApiReference/location/HOW-TO.md) article. Here are some further explanations of how API is designed to work.
It is a good idea to start with this [example](https://github.com/nsndeck/locationtest) which demonstrates how to use the `nativescript-geolocation` plugin.

### Getting an information about location service

NativeScript has an universal way to check if location service is turned on. This can be done by static `isEnabled` method of the LocationManager class.
NativeScript has an universal way to check if location service is turned on. This can be done by `isEnabled` method which returns a boolean value (true is the location service is enabled).

> Note: This method will get an information about if the location service is enabled (in android) (any accuracy level), or if the location service is enabled for the application (iOS) (either for foreground or background use).
> Note: Keep in mind that location services does not work with emulator (only on a real device).
### Request a permission to use location service

Unfortunately here NativeScript cannot give a common approach, since Android and iOS platforms differ significantly on that.
The good thing is that you can always use native API from NativeScript.
By default plugin adds necessary permissions within `AndroidManifest.xml` file for Android and `Info.plist` file for iOS. For iOS plugin adds two dummy string values which will be used as message when platform asks for permission to use location services (this messages could be edited at any time later). With the plugin installed getting a request for using location services is as simple as a method call:

``` JavaScript
var buttonModule = require("ui/button");
var appModule = require("application");
var platformModule = require("platform");

var onRequestButtonTap = function(args: observable.EventData) {
var button = <buttonModule.Button>(args.object);
if (button.android) {
console.log("Application run on Android");
(<android.app.Activity>appModule.android.currentContext).startActivityForResult(new android.content.Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS), 0);
}
else if (button.ios) {
console.log("Application run on iOS");
if (platformModule.device.osVersion.indexOf("8") === 0) {
console.log("iOS version is greater or equal to 8.0");
var iosLocationManager = CLLocationManager.alloc().init();
iosLocationManager.requestWhenInUseAuthorization();
}

```XML
<Page>
<StackLayout>
<Button text="enable Location" tap="enableLocationTap"/>
</StackLayout>
</Page>
```
```JavaScript
var geolocation = require("nativescript-geolocation");
function enableLocationTap(args) {
if (!geolocation.isEnabled()) {
geolocation.enableLocationRequest();
}
}
exports.enableLocationTap = enableLocationTap;
```
``` TypeScript
import buttonModule = require("ui/button");
import appModule = require("application");
import platformModule = require("platform");

var onRequestButtonTap = function(args: observable.EventData) {
var button = <buttonModule.Button>(args.object);
if (button.android) {
console.log("Application run on Android");
(<android.app.Activity>appModule.android.currentContext).startActivityForResult(new android.content.Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS), 0);
}
else if (button.ios) {
console.log("Application run on iOS");
if (platformModule.device.osVersion.indexOf("8") === 0) {
console.log("iOS version is greater or equal to 8.0");
var iosLocationManager = CLLocationManager.alloc().init();
iosLocationManager.requestWhenInUseAuthorization();
}
```TypeScript
import geolocation = require("nativescript-geolocation");
export function enableLocationTap(args) {
if (!geolocation.isEnabled()) {
geolocation.enableLocationRequest();
}
}
```

> Note (iOS): For iOS there is a change introduced in 8.0 version that changes the way location service is requested. There are two modes for using location service from an application (`WhenInUse` - denotes using location service only when application is running, and `Always` mode which allows using location service in a background application). According to business scenario location service request could be done via `requestWhenInUseAuthorization` or `requestAlwaysAuthorization` methods. Both methods require a specific setting in your application to be set in `application.plist` file. Application `plist` file should contain `NSLocationWhenInUseUsageDescrition` or `NSLocationAlwaysUsageDescription` string values respectively. For iOS versions below 8.0 there is a similar string value named `NSLocationUsageDescription` which is not mandatory.
> Note (Android): In order to request a location service in android a special permission should be set - either `android.permission.ACCESS_COARSE_LOCATION` or `android.permission.ACCESS_FINE_LOCATION`. Fine location permission enables usage of the GPS sensor, so this is the recommended option.
### Getting a location
For getting a location information NativeScript provides two different approaches.

* First approach is available using the `location` module, where there is a `getLocation` method which can be used to get a single location. This method accepts [`location options`]({{site.baseurl}}/ApiReference/location/Options.md) parameter. The `timeout` parameter denotes the time in milliseconds when location monitoring will be stopped (default value is 20 seconds). When `timeout` is set to 0 (zero), then last known location (if is newer than maximum age) will be returned.
* First approach is available using the `nativescript-geolocation` plugin, where there is a `getCurrentLocation` method which can be used to get a single location. This method accepts `location options` parameter. Here is another difference with the previous `location` module and the difference is that this method returns a Promise<Location> where Location and location options are defined as follows:

## Class: Location
A data class that encapsulates common properties for a geolocation.

##### Instance Properties
- **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.
- **direction** - _Number_.
The direction (course), in degrees.
- **timestamp** - _Object_.
The time at which this location was determined.
- **android** - _Object_.
The android-specific [location](http://developer.android.com/reference/android/location/Location.html) object.
- **ios** - _CLLocation_.
The ios-specific [CLLocation](https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocation_Class/) object.

## Interface: Options
Provides options for location monitoring.

##### Properties
- **desiredAccuracy** - _(optional)_ - _Number_.
Specifies desired accuracy in meters. Defaults to DesiredAccuracy.HIGH
- **updateDistance** - _(optional)_ - _Number_.
Update distance filter in meters. Specifies how often to update. Default on iOS is no filter, on Android it is 0 meters
- **minimumUpdateTime** - _(optional)_ - _Number_.
Minimum time interval between location updates, in milliseconds (ignored on iOS)
- **maximumAge** - _(optional)_ - _Number_.
how old locations to receive in ms.
- **timeout** - _(optional)_ - _Number_.
how long to wait for a location in ms.

```XML
<Page>
<StackLayout>
<Button text="Get Current Location" tap="buttonGetLocationTap"/>
</StackLayout>
</Page>
```
```JavaScript
var geolocation = require("nativescript-geolocation");
function buttonGetLocationTap(args) {
var location = geolocation.getCurrentLocation({desiredAccuracy: 3, updateDistance: 10, maximumAge: 20000, timeout: 20000}).
then(function(loc) {
if (loc) {
console.log("Current location is: " + loc);
}
}, function(e){
console.log("Error: " + e.message);
});
}
exports.buttonGetLocationTap = buttonGetLocationTap;
```
```TypeScript
import geolocation = require("nativescript-geolocation");
export function buttonGetLocationTap(args) {
var location = geolocation.getCurrentLocation({desiredAccuracy: 3, updateDistance: 10, maximumAge: 20000, timeout: 20000}).
then(function(loc) {
if (loc) {
console.log("Current location is: " + loc);
}
}, function(e){
console.log("Error: " + e.message);
});
}
```

* Second approach is using the location manager `startLocationMonitoring` method. The difference here is that location monitoring will not be stopped automatically (useful for a GPS log like application). `stopLocationMonitoring` method is used to stop location monitoring.
* Second approach is using the `watchLocation` method. The difference here is that location watching will not be stopped automatically (useful for a GPS log like application) until `clearWatch` method is called.

```XML
<Page>
<StackLayout>
<Button row="2" text="start monitoring" tap="buttonStartTap"/>
<Button row="3" text="stop monitoring" tap="buttonStopTap"/>
</StackLayout>
</Page>
```
``` JavaScript
var locationModule = require("location");
var locationManager = new locationModule.LocationManager();
var locationOptions = {
desiredAccuracy: 3,
updateDistance: 0,
minimumUpdateTime: 5000,
maximumAge: 20000
};
locationManager.startLocationMonitoring(function(location){
console.log("Location received: " + location);
}, function (error) {
console.log("Location error received: " + error);
}, locationOptions);
var geolocation = require("nativescript-geolocation");
function buttonStartTap(agrs) {
watchId = geolocation.watchLocation(
function (loc) {
if (loc) {
console.log("Received location: " + loc);
}
},
function(e){
console.log("Error: " + e.message);
},
{desiredAccuracy: 3, updateDistance: 10, updateTime: 1000 * 20}); // should update every 20 sec according to google documentation this is not so sure.
}
exports.buttonStartTap = buttonStartTap;

function buttonStopTap(agrs) {
if (watchId) {
geolocation.clearWatch(watchId);
}
}
exports.buttonStopTap = buttonStopTap;
```
``` TypeScript
import locationModule = require("location");
var locationManager = new locationModule.LocationManager();
var locationOptions = {
desiredAccuracy: 3,
updateDistance: 0,
minimumUpdateTime: 5000,
maximumAge: 20000
};
locationManager.startLocationMonitoring(function(location){
console.log("Location received: " + location);
}, function (error) {
console.log("Location error received: " + error);
}, locationOptions);
import geolocation = require("nativescript-geolocation");
export function buttonStartTap(agrs) {
watchId = geolocation.watchLocation(
function (loc) {
if (loc) {
console.log("Received location: " + loc);
}
},
function(e){
console.log("Error: " + e.message);
},
{desiredAccuracy: 3, updateDistance: 10, updateTime: 1000 * 20}); // should update every 20 sec according to google documentation this is not so sure.
}

export function buttonStopTap(agrs) {
if (watchId) {
geolocation.clearWatch(watchId);
}
}
```

More information about the NativeScript location module can be found in the [API Reference]({{site.baseurl}}/ApiReference/location/location.md).
Furthermore there is another interesting method which is called distance which returns distance between two locations in meters:

```JavaScript
var geolocation = require("nativescript-geolocation");
function getDistance(loc1, loc2) {
console.log("Distance between loc1 and loc2 is: " + geolocation.distance(loc1, loc2));
}
```
```TypeScript
import geolocation = require("nativescript-geolocation");
function getDistance(loc1, loc2) {
console.log("Distance between loc1 and loc2 is: " + geolocation.distance(loc1, loc2));
}
```

0 comments on commit 0cf2d8c

Please sign in to comment.