@wisdomgarden/capacitor-native-geolocation
v0.0.6
Published
Capacitor plugin for native geolocation on Android and Web using Android LocationManager
Downloads
324
Readme
@wisdomgarden/capacitor-native-geolocation
A Capacitor plugin that provides native geolocation capabilities for Android and Web. It wraps Android's LocationManager API directly, giving you fine-grained control over GPS and network-based positioning.
Platform support: Android ✅ · Web ⚠️ (not yet implemented) · iOS ⚠️ (not yet implemented)
Install
npm install @wisdomgarden/capacitor-native-geolocation
npx cap syncThis plugin targets Capacitor 2.x. It is not compatible with Capacitor 3+.
The plugin's AGP version defaults to
8.6.0and can be overridden viaagpVersionin the host app'sgradle.propertiesor rootbuild.gradleextblock.
Android Configuration
The plugin's AndroidManifest.xml is merged into your app automatically. It declares:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false" />Permissions
| Permission | Purpose |
|---|---|
| ACCESS_COARSE_LOCATION | Network-based location (Wi-Fi / cell tower), accuracy ~300 m–3 km |
| ACCESS_FINE_LOCATION | GPS-based location, accuracy ~metres. Triggers a runtime permission dialog on Android 6+ |
Both permissions are required for the plugin to function. Missing either one causes a SecurityException at runtime. They are declared in the plugin manifest so you do not need to add them manually.
Hardware features
Both permissions cause the Play Store to implicitly infer the following as required="true":
| Permission | Implied features |
|---|---|
| ACCESS_FINE_LOCATION | android.hardware.location + android.hardware.location.gps |
| ACCESS_COARSE_LOCATION | android.hardware.location + android.hardware.location.network |
This silently excludes tablets, Wi-Fi-only devices, and Android TV. The manifest merger treats required by taking the strictest value — if any source says true, the result is true. The only way to suppress an implicit true is to declare required="false" in the same manifest that declares the permission (i.e. inside the plugin itself). An override in the app's own manifest is not enough.
The plugin therefore declares all three features with required="false" to cover every implied requirement. The plugin code already falls back automatically: GPS → network → any available provider.
If your app genuinely requires GPS (e.g. turn-by-turn navigation), add this to your app's AndroidManifest.xml:
<uses-feature android:name="android.hardware.location.gps" android:required="true" />API
getCurrentPosition(...)watchPosition(...)clearWatch(...)clearAllWatches()checkPermissions()requestPermissions(...)- Interfaces
- Type Aliases
getCurrentPosition(...)
getCurrentPosition(options?: PositionOptions): Promise<Position>Gets the current device location. Returns a cached position if it is within maximumAge; otherwise waits for a fresh fix up to timeout ms. Requires location permissions — if not already granted, the plugin will prompt the user automatically.
| Param | Type |
| ----------- | ------------------------------------------------------- |
| options | PositionOptions |
Returns: Promise<Position>
watchPosition(...)
watchPosition(options: PositionOptions, callback: WatchPositionCallback): Promise<CallbackID>Registers a continuous location listener. The callback is invoked on every location update from the device. Returns a CallbackID that can be passed to clearWatch to stop monitoring.
Battery note: continuous location updates consume significant energy. Call
clearWatchas soon as monitoring is no longer needed.
| Param | Type |
| ------------ | --------------------------------------------------------------- |
| options | PositionOptions |
| callback | WatchPositionCallback |
Returns: Promise<CallbackID>
clearWatch(...)
clearWatch(options: ClearWatchOptions): Promise<void>Stops a previously registered location watch. When the last active watch is removed, location updates are stopped entirely on the device.
| Param | Type |
| ----------- | ----------------------------------------------------------- |
| options | ClearWatchOptions |
clearAllWatches()
clearAllWatches(): Promise<void>Stops all active location watches at once and releases all associated resources. Equivalent to calling clearWatch for every ID returned by previous watchPosition calls.
checkPermissions()
checkPermissions(): Promise<PermissionStatus>Returns the current location permission state without triggering a permission prompt. Throws if system location services are disabled.
Returns: Promise<PermissionStatus>
requestPermissions(...)
requestPermissions(permissions?: GeolocationPluginPermissions): Promise<PermissionStatus>Prompts the user for location permissions if not already granted. Throws if system location services are disabled.
| Param | Type |
| --------------- | ----------------------------------------------------------------------------- |
| permissions | GeolocationPluginPermissions |
Returns: Promise<PermissionStatus>
Interfaces
Position
| Prop | Type | Description |
| --------------- | --------------------------- | ------------------------------------------------- |
| timestamp | number | Unix timestamp (ms) when the coordinates were recorded |
| coords | Coords | The location data |
Coords
| Prop | Type | Description |
| --------------------- | ------------------------- | ---------------------------------------------------------------- |
| latitude | number | Latitude in decimal degrees |
| longitude | number | Longitude in decimal degrees |
| accuracy | number | Horizontal accuracy in metres |
| altitude | number \| null | Altitude in metres above sea level, if available |
| altitudeAccuracy | number \| null \| undefined | Vertical accuracy in metres. Available on Android 8.0+ (API 26+) |
| speed | number \| null | Speed in m/s, if available |
| heading | number \| null | Bearing in degrees (0–360), if available |
PositionOptions
| Prop | Type | Default | Description |
| ---------------------- | --------- | -------- | ------------------------------------------------------------------------------------------------ |
| enableHighAccuracy | boolean | false | Use GPS (ACCURACY_FINE) when true, network/cell (ACCURACY_COARSE) when false |
| timeout | number | 10000 | Maximum wait time in ms for a location fix. 0 means no timeout. For watchPosition, fires a TIMEOUT error callback if no update arrives within this interval. |
| maximumAge | number | 0 | Maximum age in ms of a cached position that is acceptable to return |
PermissionStatus
| Prop | Type | Description |
| ------------------- | ---------------- | ---------------------------------------------------------------------------- |
| location | PermissionType | State for ACCESS_FINE_LOCATION (and ACCESS_COARSE_LOCATION) on Android |
| coarseLocation | PermissionType | State for ACCESS_COARSE_LOCATION only. Useful on Android 12+ where users can choose approximate vs precise location. |
ClearWatchOptions
| Prop | Type | Description |
| ------ | ------------ | ------------------------------------------------ |
| id | CallbackID | The ID returned by watchPosition |
GeolocationPluginPermissions
| Prop | Type |
| --------------- | ------------------------------- |
| permissions | GeolocationPermissionType[] |
Type Aliases
CallbackID
type CallbackID = string;GeolocationPermissionType
type GeolocationPermissionType = 'location' | 'coarseLocation';WatchPositionCallback
type WatchPositionCallback = (position: Position | null, err?: any) => void;Usage Example
import { Plugins } from '@capacitor/core';
import '@wisdomgarden/capacitor-native-geolocation';
const { WGGeolocation } = Plugins;
// One-shot position
async function getLocation() {
const { coords } = await WGGeolocation.getCurrentPosition({
enableHighAccuracy: true,
});
console.log(`lat: ${coords.latitude}, lng: ${coords.longitude}`);
}
// Continuous watch
async function startTracking() {
const watchId = await WGGeolocation.watchPosition(
{ enableHighAccuracy: true },
(position, err) => {
if (err) {
console.error(err);
return;
}
console.log(position?.coords);
},
);
// Later: stop tracking
await WGGeolocation.clearWatch({ id: watchId });
}
// Stop all watches at once
async function stopAllTracking() {
await WGGeolocation.clearAllWatches();
}
// Permissions
async function ensurePermission() {
const status = await WGGeolocation.checkPermissions();
if (status.location !== 'granted') {
await WGGeolocation.requestPermissions({ permissions: ['location'] });
}
}Error Codes
Use the GeolocationErrorCode enum to check errors without magic strings.
| Code | GeolocationErrorCode | Cause |
| ---- | --------------------------- | -------------------------------------------------- |
| 1 | PERMISSION_DENIED | User denied location permission |
| 2 | POSITION_UNAVAILABLE | Location services disabled or no provider available |
| 3 | TIMEOUT | No fix obtained within the timeout window |
Platform Notes
Android
- Uses
LocationManagerdirectly (no Google Play Services dependency). - Provider is selected automatically based on
enableHighAccuracy: GPS for fine accuracy, network/cell for coarse accuracy. getCurrentPositionreturns a cached position if withinmaximumAge; otherwise registers a one-shot listener and waits up totimeoutms for a fresh fix.- Location updates (
watchPosition) use 0 ms / 0 m thresholds — every available update is delivered to the callback. altitudeAccuracyrequires Android 8.0+ (API level 26).
Web
- Not yet implemented. All methods reject with an error.
iOS
- Not yet implemented. The plugin registers on iOS but no geolocation methods are functional.
License
MIT
