diff --git a/README.md b/README.md index 7ffc411..0052bec 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,16 @@ Apple requires privacy descriptions to be specified in `Info.plist` for location - `NSLocationAlwaysAndWhenInUseUsageDescription` (`Privacy - Location Always and When In Use Usage Description`) - `NSLocationWhenInUseUsageDescription` (`Privacy - Location When In Use Usage Description`) -> [!NOTE] -> This Capacitor plugin does not support background geolocation directly. However, it relies on -> [`ion-ios-geolocation`](https://github.com/ionic-team/ion-ios-geolocation), which can report -> location in the background. As a result, Apple requires you to include a -> `NSLocationAlwaysAndWhenInUseUsageDescription` entry in your `Info.plist`. Since this permission -> prompt won’t appear to users, you can safely use the same description string as for -> `NSLocationWhenInUseUsageDescription`. +:::info[Background Location Usage Strings] + +This Capacitor plugin does not support background geolocation directly. However, it relies on +[`ion-ios-geolocation`](https://github.com/ionic-team/ion-ios-geolocation), which can report +location in the background. As a result, Apple requires you to include a +`NSLocationAlwaysAndWhenInUseUsageDescription` entry in your `Info.plist`. Since this permission +prompt won’t appear to users, you can safely use the same description string as for +`NSLocationWhenInUseUsageDescription`. + +:::info Read about [Configuring `Info.plist`](https://capacitorjs.com/docs/ios/configuration#configuring-infoplist) in the [iOS Guide](https://capacitorjs.com/docs/ios) for more information on setting iOS permissions in Xcode @@ -39,6 +42,12 @@ This plugin requires the following permissions be added to your `AndroidManifest The first two permissions ask for location data, both fine and coarse, and the last line is optional but necessary if your app _requires_ GPS to function. You may leave it out, though keep in mind that this may mean your app is installed on devices lacking GPS hardware. +:::note + +If you only require approximate location (variable accuracy but usually around 2 kilometers), you may just declare `ACCESS_COARSE_LOCATION` and ` Unit ) { - val alias = getAlias(call) + val alias = getAlias(call) ?: run { + call.sendError(GeolocationErrors.LOCATION_MANIFEST_PERMISSIONS_MISSING) + return + } if (getPermissionState(alias) != PermissionState.GRANTED) { requestPermissionForAlias(alias, call, callbackName) } else { @@ -178,19 +180,20 @@ class GeolocationPlugin : Plugin() { } /** - * Gets the appropriate permission alias + * Gets the appropriate permission alias, based on the Android version, + * the permissions declared in the manifest + * and the enableHighAccuracy option provided by the caller. * @param call the plugin call - * @return String with correct alias + * @return String with correct alias or null if no permissions can be requested */ - private fun getAlias(call: PluginCall): String { - var alias = LOCATION_ALIAS - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - val enableHighAccuracy = call.getBoolean("enableHighAccuracy") ?: false - if (!enableHighAccuracy) { - alias = COARSE_LOCATION_ALIAS - } - } - return alias + private fun getAlias(call: PluginCall): String? { + val hasFine = isPermissionDeclared(LOCATION_ALIAS) + val hasCoarse = isPermissionDeclared(COARSE_LOCATION_ALIAS) + if (!hasFine && !hasCoarse) return null + val enableHighAccuracy = call.getBoolean("enableHighAccuracy") ?: false + val shouldRequestFine = + hasFine && (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || enableHighAccuracy) + return if (shouldRequestFine) LOCATION_ALIAS else COARSE_LOCATION_ALIAS } /** @@ -316,7 +319,7 @@ class GeolocationPlugin : Plugin() { } /** - * Extension function to return a unsuccessful plugin result + * Extension function to return an unsuccessful plugin result * @param error error class representing the error to return, containing a code and message */ private fun PluginCall.sendError(error: GeolocationErrors.ErrorInfo) { diff --git a/example-app/src/js/capacitor-welcome.js b/example-app/src/js/capacitor-welcome.js index 1e1acc7..f06aa21 100644 --- a/example-app/src/js/capacitor-welcome.js +++ b/example-app/src/js/capacitor-welcome.js @@ -1,3 +1,4 @@ +import { Capacitor } from '@capacitor/core'; import { SplashScreen } from '@capacitor/splash-screen'; import { Geolocation } from '@capacitor/geolocation'; @@ -63,6 +64,7 @@ window.customElements.define(

Below are the several features for the capacitor geolocation plugin. You may be prompted to grant location permission to the application.

+


@@ -98,13 +100,30 @@ window.customElements.define( connectedCallback() { const self = this; + const isAndroid = Capacitor.getPlatform() === 'android'; + + if (isAndroid) { + self.shadowRoot.querySelector('#request-coarse-permission').style.display = 'inline-block'; + } + + function permissionStatusToString(permissionStatus) { + if (isAndroid) { + return `Permissions are:\nlocation (fine+coarse) = ${permissionStatus.location}\ncoarseLocation = ${permissionStatus.coarseLocation}`; + } + return `Permissions are:\nlocation = ${permissionStatus.location}`; + } + self.shadowRoot.querySelector('#check-permission').addEventListener('click', async function (e) { const permissionStatus = await Geolocation.checkPermissions(); - alert(`Permissions are:\nlocation = ${permissionStatus.location}`); + alert(permissionStatusToString(permissionStatus)); }); self.shadowRoot.querySelector('#request-permission').addEventListener('click', async function (e) { const permissionStatus = await Geolocation.requestPermissions(); - alert(`Permissions are:\nlocation = ${permissionStatus.location}`); + alert(permissionStatusToString(permissionStatus)); + }); + self.shadowRoot.querySelector('#request-coarse-permission').addEventListener('click', async function (e) { + const permissionStatus = await Geolocation.requestPermissions({ permissions: ['coarseLocation'] }); + alert(permissionStatusToString(permissionStatus)); }); self.shadowRoot.querySelector('#current-location').addEventListener('click', async function (e) {