Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ geolocation.getCurrentLocation({ desiredAccuracy: Accuracy.high, maximumAge: 500
| timeout | 5 minutes | How long to wait for a location in ms. |
| iosAllowsBackgroundLocationUpdates | false | If enabled, UIBackgroundModes key in info.plist is required (check the hint below). Allow the application to receive location updates in background (ignored on Android). Read more in [Apple document](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620568-allowsbackgroundlocationupdates?language=objc) |
| iosPausesLocationUpdatesAutomatically | true | Allow 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)|
| iosOpenSettingsIfLocationHasBeenDenied | false | Argument on the `enableLocationRequest`. If true, the settings app will open on iOS so the user can change the location services permission. |

> If iosAllowsBackgroundLocationUpdates is set to true, the following code is required in the info.plist file:
>```
Expand Down
2 changes: 1 addition & 1 deletion demo/app/main-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export function stopBackgroundTap() {
export function enableLocationTap() {
geolocation.isEnabled().then(function (isEnabled) {
if (!isEnabled) {
geolocation.enableLocationRequest().then(function () {
geolocation.enableLocationRequest(false, true).then(function () {
}, function (e) {
console.log("Error: " + (e.message || e));
});
Expand Down
2 changes: 1 addition & 1 deletion demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@
"ci.tslint": "npm i && tslint --config '../tslint.json' 'app/**/*.ts' --exclude '**/node_modules/**'",
"build.plugin": "cd ../src && npm run build"
}
}
}
2 changes: 1 addition & 1 deletion src/geolocation.android.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { on as applicationOn, android as androidAppInstance, AndroidApplication, uncaughtErrorEvent, UnhandledErrorEventData } from "application";
import { Accuracy } from "tns-core-modules/ui/enums";
import { setTimeout, clearTimeout } from "timer";
import { setTimeout, clearTimeout } from "tns-core-modules/timer";
import { LocationBase, defaultGetLocationTimeout, fastestTimeUpdate, minTimeUpdate } from "./geolocation.common";
import { Options, successCallbackType, errorCallbackType } from "./location-monitor";
import * as permissions from "nativescript-permissions";
Expand Down
2 changes: 1 addition & 1 deletion src/geolocation.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ export class LocationBase implements LocationDef {
export const defaultGetLocationTimeout = 5 * 60 * 1000; // 5 minutes
export const minRangeUpdate = 0.1; // 0 meters
export const minTimeUpdate = 1 * 60 * 1000; // 1 minute
export const fastestTimeUpdate = 5 * 1000; // 5 secs
export const fastestTimeUpdate = 5 * 1000; // 5 secs
64 changes: 41 additions & 23 deletions src/geolocation.ios.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Accuracy } from "tns-core-modules/ui/enums";
import { setTimeout, clearTimeout } from "timer";
import { on as applicationOn, uncaughtErrorEvent, UnhandledErrorEventData } from "application";
import { setTimeout, clearTimeout } from "tns-core-modules/timer";
import { on as applicationOn, uncaughtErrorEvent, UnhandledErrorEventData } from "tns-core-modules/application";
import * as utils from "tns-core-modules/utils/utils";

import {
LocationBase,
Expand Down Expand Up @@ -239,48 +240,65 @@ export function clearWatch(_watchId: number): void {
LocationMonitor.stopLocationMonitoring(_watchId);
}

export function enableLocationRequest(always?: boolean): Promise<void> {
export function enableLocationRequest(always?: boolean, iosOpenSettingsIfLocationHasBeenDenied?: boolean): Promise<void> {
return new Promise<void>(function (resolve, reject) {
if (_isEnabled()) {
const locationIsEnabled = _isEnabled();

if (locationIsEnabled) {
resolve();
return;
}

let listener = LocationListenerImpl.initWithPromiseCallbacks(resolve, reject, always);
try {
let manager = getIOSLocationManager(listener, null);
if (always) {
manager.requestAlwaysAuthorization();
} else {
const status = getIOSLocationManagerStatus();
if (status === CLAuthorizationStatus.kCLAuthorizationStatusDenied &&
iosOpenSettingsIfLocationHasBeenDenied) {
// now open the Settings so the user can toggle the Location permission
utils.ios.getter(UIApplication, UIApplication.sharedApplication).openURL(NSURL.URLWithString(UIApplicationOpenSettingsURLString));
} else {
manager.requestWhenInUseAuthorization();
let listener = LocationListenerImpl.initWithPromiseCallbacks(resolve, reject, always);
try {
let manager = getIOSLocationManager(listener, null);
if (always) {
manager.requestAlwaysAuthorization();
} else {
manager.requestWhenInUseAuthorization();
}
} catch (e) {
LocationMonitor.stopLocationMonitoring(listener.id);
reject(e);
}
}
} catch (e) {
LocationMonitor.stopLocationMonitoring(listener.id);
reject(e);
}
});
}

function _isEnabled(options?: Options): boolean {
function _isEnabled(): boolean {
if (CLLocationManager.locationServicesEnabled()) {
const status = getIOSLocationManagerStatus();

// CLAuthorizationStatus.kCLAuthorizationStatusAuthorizedWhenInUse and
// CLAuthorizationStatus.kCLAuthorizationStatusAuthorizedAlways are options that are available in iOS 8.0+
// while CLAuthorizationStatus.kCLAuthorizationStatusAuthorized is here to support iOS 8.0-.
const AUTORIZED_WHEN_IN_USE = CLAuthorizationStatus.kCLAuthorizationStatusAuthorizedWhenInUse;

return (CLLocationManager.authorizationStatus() === AUTORIZED_WHEN_IN_USE
|| CLLocationManager.authorizationStatus() === CLAuthorizationStatus.kCLAuthorizationStatusAuthorizedAlways
|| CLLocationManager.authorizationStatus() === CLAuthorizationStatus.kCLAuthorizationStatusAuthorized);
// const AUTORIZED_WHEN_IN_USE = CLAuthorizationStatus.kCLAuthorizationStatusAuthorizedWhenInUse;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

return (status === CLAuthorizationStatus.kCLAuthorizationStatusAuthorizedWhenInUse
|| status === CLAuthorizationStatus.kCLAuthorizationStatusAuthorizedAlways
// @ts-ignore: Types have no overlap error
|| status === CLAuthorizationStatus.kCLAuthorizationStatusAuthorized);
}
return false;
}

export function isEnabled(): Promise<boolean> {
export function isEnabled(options: Options): Promise<boolean> {
return new Promise(function (resolve, reject) {
resolve(_isEnabled());
const isEnabledResult = _isEnabled();

resolve(isEnabledResult);
});
}

export function getIOSLocationManagerStatus(): CLAuthorizationStatus {
return CLLocationManager.authorizationStatus();
}

export function distance(loc1: Location, loc2: Location): number {
if (!loc1.ios) {
loc1.ios = clLocationFromLocation(loc1);
Expand Down
118 changes: 68 additions & 50 deletions src/location-monitor.d.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,60 @@
import { Location } from "./location";

/**
* Provides options for location monitoring.
*/
* Provides options for location monitoring.
*/
export interface Options {
/**
* Specifies desired accuracy in meters. Defaults to DesiredAccuracy.HIGH
*/
desiredAccuracy?: number;

/**
* Update distance filter in meters. Specifies how often to update. Default is no filter
*/
updateDistance?: number;

/**
* Interval between location updates, in milliseconds (ignored on iOS)
*/
updateTime?: number;

/**
* Minimum time interval between location updates, in milliseconds (ignored on iOS)
*/
minimumUpdateTime?: number;

/**
* How old locations to receive in ms.
*/
maximumAge?: number;

/**
* How long to wait for a location in ms.
*/
timeout?: number;

/**
* A Boolean value which has to be set to true on iOS versions > 9.0 to allow the application to receive location updates in
* background in combination with the UIBackgroundModes key 'location' in the Info.plist. An exception is thrown if the
* property is enabled without the UIBackgroundModes key set to true. The value is ignored on Android.
* @see {@link https://developer.apple.com/reference/corelocation/cllocationmanager/1620568-allowsbackgroundlocationupdates|allowsBackgroundLocationUpdates}
*/
iosAllowsBackgroundLocationUpdates?: boolean;

/**
* A Boolean value which has to be set to false on iOS to deactivate the automatic pause of location updates. The location manager might pause
* location updates for a period of time to improve battery life. This behavior may stop a long-running background task. Set this flag to false
* to prevent this behavior. The value is ignored on Android.
* @see {@link https://developer.apple.com/reference/corelocation/cllocationmanager/1620553-pauseslocationupdatesautomatical|pausesLocationUpdatesAutomatically}
*/
iosPausesLocationUpdatesAutomatically?: boolean;
/**
* Specifies desired accuracy in meters. Defaults to DesiredAccuracy.HIGH
*/
desiredAccuracy?: number;

/**
* Update distance filter in meters. Specifies how often to update. Default is no filter
*/
updateDistance?: number;

/**
* Interval between location updates, in milliseconds (ignored on iOS)
*/
updateTime?: number;

/**
* Minimum time interval between location updates, in milliseconds (ignored on iOS)
*/
minimumUpdateTime?: number;

/**
* How old locations to receive in ms.
*/
maximumAge?: number;

/**
* How long to wait for a location in ms.
*/
timeout?: number;

/**
* A Boolean value which has to be set to true on iOS versions > 9.0 to allow the application to receive location updates in
* background in combination with the UIBackgroundModes key 'location' in the Info.plist. An exception is thrown if the
* property is enabled without the UIBackgroundModes key set to true. The value is ignored on Android.
* @see {@link https://developer.apple.com/reference/corelocation/cllocationmanager/1620568-allowsbackgroundlocationupdates|allowsBackgroundLocationUpdates}
*/
iosAllowsBackgroundLocationUpdates?: boolean;

/**
* A Boolean value which has to be set to false on iOS to deactivate the automatic pause of location updates. The location manager might pause
* location updates for a period of time to improve battery life. This behavior may stop a long-running background task. Set this flag to false
* to prevent this behavior. The value is ignored on Android.
* @see {@link https://developer.apple.com/reference/corelocation/cllocationmanager/1620553-pauseslocationupdatesautomatical|pausesLocationUpdatesAutomatically}
*/
iosPausesLocationUpdatesAutomatically?: boolean;

/**
* A boolean value which if set to true, the application will open the Settings
* app only after the user has previously denied the location permission.
*/
iosOpenSettingsIfLocationHasBeenDenied?: boolean;
}

declare type successCallbackType = (location: Location) => void;
Expand All @@ -64,7 +70,11 @@ export function getCurrentLocation(options: Options): Promise<Location>;
* Monitor for location change.
* @returns {number} The watch id
*/
export function watchLocation(successCallback: successCallbackType, errorCallback: errorCallbackType, options: Options): number;
export function watchLocation(
successCallback: successCallbackType,
errorCallback: errorCallbackType,
options: Options
): number;

/**
* Stop monitoring for location change. Parameter expected is the watchId returned from `watchLocation`.
Expand All @@ -76,11 +86,12 @@ export function clearWatch(watchId: number): void;
* Ask for permissions to use location services. The option 'always' is applicable to iOS only. Read more: https://developer.apple.com/documentation/corelocation/cllocationmanager/1620551-requestalwaysauthorization.
* @param always iOS only. https://developer.apple.com/documentation/corelocation/cllocationmanager/1620551-requestalwaysauthorization
*/
export function enableLocationRequest(always?: boolean): Promise<void>;
export function enableLocationRequest(always?: boolean, iosOpenSettingsIfLocationHasBeenDenied?: boolean): Promise<void>;

/**
* Check if location services are enabled
* @param options android only. Check the availability based on the specified options.
* @param options Check the availability based on the specified options.
* ** iOS Only ** utilizes the iosOpenSettingsIfLocationHasBeenDenied value **
* @returns {boolean} True if location services are enabled
*/
export function isEnabled(options?: Options): Promise<boolean>;
Expand All @@ -92,3 +103,10 @@ export function isEnabled(options?: Options): Promise<boolean>;
* @returns {number} The calculated distance in meters.
*/
export function distance(loc1: Location, loc2: Location): number;

/**
* ** iOS Only **
* Returns the value for the CLLocationManager on iOS.
* @returns {CLAuthorizationStatus} The status of the Location Authorization permission.
*/
export function getIOSLocationManagerStatus(): CLAuthorizationStatus;
2 changes: 1 addition & 1 deletion src/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nativescript-geolocation",
"version": "4.3.1",
"version": "4.4.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert version

"description": "Provides API for getting and monitoring location for NativeScript app.",
"main": "geolocation",
"typings": "index.d.ts",
Expand Down