Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Tbozhikov/add allow location ios #185

Merged
merged 9 commits into from
Jan 18, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
63 changes: 40 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,64 @@ 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);
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;