Native plugin wrappers for Cordova and Ionic with TypeScript, ES6+, Promise and Observable support
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Geolocation services, background location tracking, geofencing capabilities, and maps integration for location-aware applications.
Access device location services for current position and continuous location tracking with configurable accuracy options.
/**
* Geographic coordinates interface
*/
interface Coordinates {
/** Latitude in decimal degrees */
latitude: number;
/** Longitude in decimal degrees */
longitude: number;
/** Altitude in meters above the reference ellipsoid */
altitude: number;
/** Accuracy of latitude and longitude coordinates in meters */
accuracy: number;
/** Accuracy of altitude coordinate in meters */
altitudeAccuracy: number;
/** Direction of travel in degrees (0-359.99) */
heading: number;
/** Current ground speed in meters per second */
speed: number;
}
/**
* Geographic position with timestamp
*/
interface Geoposition {
/** Geographic coordinates */
coords: Coordinates;
/** Timestamp when location was retrieved */
timestamp: number;
}
/**
* Position error information
*/
interface PositionError {
/** Error code (1: PERMISSION_DENIED, 2: POSITION_UNAVAILABLE, 3: TIMEOUT) */
code: number;
/** Error message */
message: string;
}
/**
* Geolocation options
*/
interface GeolocationOptions {
/** Enable high accuracy mode (uses GPS) */
enableHighAccuracy?: boolean;
/** Timeout for location request in milliseconds */
timeout?: number;
/** Maximum age of cached position in milliseconds */
maximumAge?: number;
}
/**
* Geolocation class for location services
*/
class Geolocation {
/**
* Get current device position
* @param options Location options
* @returns Promise resolving to current Geoposition
*/
static getCurrentPosition(options?: GeolocationOptions): Promise<Geoposition>;
/**
* Watch device position changes
* @param options Location options
* @returns Observable emitting Geoposition updates
*/
static watchPosition(options?: GeolocationOptions): Observable<Geoposition>;
}Usage Examples:
import { Geolocation, GeolocationOptions } from 'ionic-native';
// Get current location
async function getCurrentLocation() {
const options: GeolocationOptions = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 60000
};
try {
const position = await Geolocation.getCurrentPosition(options);
console.log('Current position:');
console.log('Latitude:', position.coords.latitude);
console.log('Longitude:', position.coords.longitude);
console.log('Accuracy:', position.coords.accuracy, 'meters');
return {
lat: position.coords.latitude,
lng: position.coords.longitude,
accuracy: position.coords.accuracy
};
} catch (error) {
console.error('Error getting location:', error);
throw error;
}
}
// Watch position changes for navigation
function startLocationTracking() {
const options: GeolocationOptions = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
return Geolocation.watchPosition(options).subscribe(
(position) => {
console.log('Position update:', {
lat: position.coords.latitude,
lng: position.coords.longitude,
accuracy: position.coords.accuracy,
speed: position.coords.speed,
heading: position.coords.heading,
timestamp: new Date(position.timestamp)
});
// Update map marker
updateMapPosition(position.coords);
// Log movement if speed > 0
if (position.coords.speed > 0) {
logMovement(position);
}
},
(error) => {
console.error('Location error:', error);
handleLocationError(error);
}
);
}
// Distance calculation between two points
function calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number) {
const R = 6371e3; // Earth's radius in meters
const φ1 = lat1 * Math.PI/180;
const φ2 = lat2 * Math.PI/180;
const Δφ = (lat2-lat1) * Math.PI/180;
const Δλ = (lon2-lon1) * Math.PI/180;
const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c; // Distance in meters
}
// Location-based features
async function findNearbyPlaces(radius: number = 1000) {
try {
const position = await getCurrentLocation();
// Find nearby places within radius
const nearbyPlaces = await searchNearbyPlaces(
position.lat,
position.lng,
radius
);
return nearbyPlaces;
} catch (error) {
console.error('Error finding nearby places:', error);
return [];
}
}Continuous location tracking that works when the app is in the background for tracking and navigation use cases.
/**
* Background geolocation configuration
*/
interface BackgroundGeolocationConfig {
/** Desired accuracy in meters (iOS: kCLLocationAccuracyXXX) */
desiredAccuracy?: number;
/** Stationary radius in meters */
stationaryRadius?: number;
/** Distance filter in meters */
distanceFilter?: number;
/** Enable debug mode */
debug?: boolean;
/** Location timeout in milliseconds */
interval?: number;
/** Fastest location interval in milliseconds */
fastestInterval?: number;
/** Activity type for iOS (AutomotiveNavigation, Navigation, Fitness, Other) */
activityType?: string;
/** Defer location updates until later */
deferLocationUpdates?: boolean;
/** Stop on terminate */
stopOnTerminate?: boolean;
/** Start on boot */
startOnBoot?: boolean;
/** Start in foreground */
startForeground?: boolean;
/** Notification title (Android) */
notificationTitle?: string;
/** Notification text (Android) */
notificationText?: string;
/** Notification icon (Android) */
notificationIcon?: string;
/** Location provider (GPS_PROVIDER, NETWORK_PROVIDER, PASSIVE_PROVIDER) */
locationProvider?: number;
}
/**
* Background location data
*/
interface BackgroundLocation {
/** Latitude */
latitude: number;
/** Longitude */
longitude: number;
/** Accuracy in meters */
accuracy: number;
/** Altitude in meters */
altitude: number;
/** Speed in m/s */
speed: number;
/** Bearing in degrees */
bearing: number;
/** Location timestamp */
time: number;
/** Location provider used */
provider: string;
}
/**
* BackgroundGeolocation class for continuous location tracking
*/
class BackgroundGeolocation {
/**
* Configure background location tracking
* @param options Configuration options
* @returns Observable emitting location updates
*/
static configure(options: BackgroundGeolocationConfig): Observable<BackgroundLocation>;
/**
* Start background location tracking
*/
static start(): void;
/**
* Stop background location tracking
*/
static stop(): void;
/**
* Check if location services are enabled
* @returns Promise resolving to boolean
*/
static isLocationEnabled(): Promise<boolean>;
/**
* Show app-specific settings
*/
static showAppSettings(): void;
/**
* Show location settings
*/
static showLocationSettings(): void;
/**
* Check plugin status
* @returns Promise resolving to status object
*/
static checkStatus(): Promise<any>;
/**
* Get stationary location
* @returns Promise resolving to location
*/
static getStationaryLocation(): Promise<BackgroundLocation>;
/**
* Get plugin log entries
* @param limit Maximum number of entries
* @returns Promise resolving to log entries
*/
static getLogEntries(limit: number): Promise<any>;
}Usage Examples:
import { BackgroundGeolocation, BackgroundGeolocationConfig } from 'ionic-native';
// Configure and start background tracking
function startBackgroundTracking() {
const config: BackgroundGeolocationConfig = {
desiredAccuracy: 10,
stationaryRadius: 20,
distanceFilter: 30,
debug: false,
interval: 60000,
fastestInterval: 5000,
activitiesInterval: 300000,
activityType: 'AutomotiveNavigation',
stopOnTerminate: false,
startOnBoot: true,
startForeground: false,
notificationTitle: 'Location Tracking',
notificationText: 'Your location is being tracked',
locationProvider: 1 // GPS_PROVIDER
};
BackgroundGeolocation.configure(config).subscribe(
(location) => {
console.log('Background location update:', {
latitude: location.latitude,
longitude: location.longitude,
accuracy: location.accuracy,
speed: location.speed,
timestamp: new Date(location.time)
});
// Save location to local storage or send to server
saveLocationUpdate(location);
},
(error) => {
console.error('Background location error:', error);
}
);
// Start tracking
BackgroundGeolocation.start();
}
// Trip tracking functionality
class TripTracker {
private trackingSubscription: any;
private tripData: BackgroundLocation[] = [];
async startTrip() {
try {
const isEnabled = await BackgroundGeolocation.isLocationEnabled();
if (!isEnabled) {
BackgroundGeolocation.showLocationSettings();
return;
}
const config: BackgroundGeolocationConfig = {
desiredAccuracy: 10,
distanceFilter: 10,
interval: 5000,
debug: true,
notificationTitle: 'Trip in Progress',
notificationText: 'Recording your journey'
};
this.trackingSubscription = BackgroundGeolocation.configure(config).subscribe(
(location) => {
this.tripData.push(location);
this.updateTripStats(location);
}
);
BackgroundGeolocation.start();
console.log('Trip started');
} catch (error) {
console.error('Failed to start trip:', error);
}
}
stopTrip() {
if (this.trackingSubscription) {
this.trackingSubscription.unsubscribe();
}
BackgroundGeolocation.stop();
const tripSummary = this.calculateTripSummary();
console.log('Trip completed:', tripSummary);
return tripSummary;
}
private updateTripStats(location: BackgroundLocation) {
// Calculate distance, speed, etc.
if (this.tripData.length > 1) {
const prevLocation = this.tripData[this.tripData.length - 2];
const distance = this.calculateDistance(
prevLocation.latitude, prevLocation.longitude,
location.latitude, location.longitude
);
console.log(`Distance since last point: ${distance.toFixed(2)}m`);
}
}
private calculateTripSummary() {
if (this.tripData.length < 2) {
return { distance: 0, duration: 0, avgSpeed: 0 };
}
let totalDistance = 0;
for (let i = 1; i < this.tripData.length; i++) {
const prev = this.tripData[i - 1];
const curr = this.tripData[i];
totalDistance += this.calculateDistance(
prev.latitude, prev.longitude,
curr.latitude, curr.longitude
);
}
const startTime = this.tripData[0].time;
const endTime = this.tripData[this.tripData.length - 1].time;
const duration = (endTime - startTime) / 1000; // seconds
const avgSpeed = totalDistance / duration; // m/s
return {
distance: totalDistance,
duration,
avgSpeed,
points: this.tripData.length
};
}
private calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number) {
// Haversine formula implementation
const R = 6371e3;
const φ1 = lat1 * Math.PI/180;
const φ2 = lat2 * Math.PI/180;
const Δφ = (lat2-lat1) * Math.PI/180;
const Δλ = (lon2-lon1) * Math.PI/180;
const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
}
}Set up geographic boundaries and receive notifications when entering or leaving defined areas.
/**
* Geofence configuration options
*/
interface GeofenceOptions {
/** Unique geofence identifier */
id: string;
/** Latitude of geofence center */
latitude: number;
/** Longitude of geofence center */
longitude: number;
/** Radius in meters */
radius: number;
/** Transition types to monitor (1: ENTER, 2: EXIT, 3: BOTH) */
transitionType: number;
/** Notification configuration */
notification?: {
/** Notification ID */
id?: number;
/** Notification title */
title?: string;
/** Notification text */
text?: string;
/** Small icon */
smallIcon?: string;
/** Large icon */
icon?: string;
/** Open app on click */
openAppOnClick?: boolean;
/** Vibration pattern */
vibrate?: number[];
/** Data payload */
data?: any;
};
}
/**
* Geofence transition event
*/
interface GeofenceTransition {
/** Geofence ID */
fenceKey: string;
/** Transition type (ENTER or EXIT) */
transitionType: string;
/** Device location when transition occurred */
location: {
latitude: number;
longitude: number;
accuracy: number;
speed: number;
altitude: number;
};
}
/**
* Geofence class for location-based triggers
*/
class Geofence {
/**
* Initialize geofencing service
* @returns Promise indicating initialization completion
*/
static initialize(): Promise<any>;
/**
* Add or update geofences
* @param geofences Array of geofence configurations
* @returns Promise indicating operation completion
*/
static addOrUpdate(geofences: GeofenceOptions[]): Promise<any>;
/**
* Remove geofences by ID
* @param geofenceIds Array of geofence IDs to remove
* @returns Promise indicating removal completion
*/
static remove(geofenceIds: string[]): Promise<any>;
/**
* Remove all geofences
* @returns Promise indicating removal completion
*/
static removeAll(): Promise<any>;
/**
* Get list of watched geofences
* @returns Promise resolving to array of geofence IDs
*/
static getWatched(): Promise<string[]>;
/**
* Observable for geofence transition events
* @returns Observable emitting GeofenceTransition events
*/
static onTransitionReceived(): Observable<GeofenceTransition>;
/**
* Observable for notification click events
* @returns Observable emitting notification click events
*/
static onNotificationClicked(): Observable<any>;
}Usage Examples:
import { Geofence, GeofenceOptions } from 'ionic-native';
// Initialize geofencing service
async function initializeGeofencing() {
try {
await Geofence.initialize();
console.log('Geofencing initialized');
// Set up event listeners
setupGeofenceListeners();
} catch (error) {
console.error('Geofencing initialization failed:', error);
}
}
// Set up geofence event listeners
function setupGeofenceListeners() {
// Listen for geofence transitions
Geofence.onTransitionReceived().subscribe((transition) => {
console.log('Geofence transition:', {
fence: transition.fenceKey,
type: transition.transitionType,
location: transition.location
});
handleGeofenceTransition(transition);
});
// Listen for notification clicks
Geofence.onNotificationClicked().subscribe((notificationData) => {
console.log('Geofence notification clicked:', notificationData);
handleNotificationClick(notificationData);
});
}
// Create geofences for important locations
async function createLocationGeofences() {
const geofences: GeofenceOptions[] = [
{
id: 'home',
latitude: 37.7749,
longitude: -122.4194,
radius: 100,
transitionType: 3, // Both enter and exit
notification: {
id: 1,
title: 'Home',
text: 'Welcome home!',
openAppOnClick: true,
vibrate: [1000, 1000, 1000],
data: { type: 'home', action: 'arrived' }
}
},
{
id: 'work',
latitude: 37.7849,
longitude: -122.4094,
radius: 200,
transitionType: 1, // Enter only
notification: {
id: 2,
title: 'Work',
text: 'You have arrived at work',
openAppOnClick: false,
data: { type: 'work', action: 'checkin' }
}
},
{
id: 'gym',
latitude: 37.7649,
longitude: -122.4294,
radius: 50,
transitionType: 3, // Both
notification: {
id: 3,
title: 'Gym',
text: 'Time for your workout!',
openAppOnClick: true,
data: { type: 'gym', action: 'workout' }
}
}
];
try {
await Geofence.addOrUpdate(geofences);
console.log('Geofences created successfully');
const watched = await Geofence.getWatched();
console.log('Currently watched geofences:', watched);
} catch (error) {
console.error('Failed to create geofences:', error);
}
}
// Handle geofence transitions
function handleGeofenceTransition(transition: GeofenceTransition) {
const { fenceKey, transitionType, location } = transition;
switch (fenceKey) {
case 'home':
if (transitionType === 'ENTER') {
// Arrived home
console.log('Welcome home!');
setHomeMode(true);
} else if (transitionType === 'EXIT') {
// Left home
console.log('Left home');
setHomeMode(false);
}
break;
case 'work':
if (transitionType === 'ENTER') {
// Arrived at work
console.log('Checking in at work');
checkInAtWork(location);
}
break;
case 'gym':
if (transitionType === 'ENTER') {
// Entered gym
console.log('Starting workout session');
startWorkoutSession();
} else if (transitionType === 'EXIT') {
// Left gym
console.log('Ending workout session');
endWorkoutSession();
}
break;
}
}
// Dynamic geofence management
class GeofenceManager {
private activeGeofences: Set<string> = new Set();
async addTemporaryGeofence(id: string, lat: number, lng: number, radius: number, durationMinutes: number) {
const geofence: GeofenceOptions = {
id,
latitude: lat,
longitude: lng,
radius,
transitionType: 3,
notification: {
title: 'Temporary Alert',
text: `You are near ${id}`,
openAppOnClick: true
}
};
await Geofence.addOrUpdate([geofence]);
this.activeGeofences.add(id);
// Auto-remove after duration
setTimeout(async () => {
await this.removeGeofence(id);
}, durationMinutes * 60 * 1000);
}
async removeGeofence(id: string) {
if (this.activeGeofences.has(id)) {
await Geofence.remove([id]);
this.activeGeofences.delete(id);
console.log(`Geofence ${id} removed`);
}
}
async clearAllGeofences() {
await Geofence.removeAll();
this.activeGeofences.clear();
console.log('All geofences cleared');
}
getActiveGeofences(): string[] {
return Array.from(this.activeGeofences);
}
}Integrate Google Maps with native map functionality and custom controls.
/**
* Google Map configuration options
*/
interface GoogleMapOptions {
/** Map center coordinates */
center?: { lat: number; lng: number; };
/** Initial zoom level */
zoom?: number;
/** Map type (MAP_TYPE_NORMAL, MAP_TYPE_ROADMAP, MAP_TYPE_SATELLITE, MAP_TYPE_HYBRID, MAP_TYPE_TERRAIN) */
mapType?: string;
/** Enable user location */
myLocationEnabled?: boolean;
/** Show my location button */
myLocationButtonEnabled?: boolean;
/** Enable indoor maps */
indoorEnabled?: boolean;
/** Show compass */
compassEnabled?: boolean;
/** Show zoom controls */
zoomControlsEnabled?: boolean;
/** Allow map rotation */
rotateGesturesEnabled?: boolean;
/** Allow map scrolling */
scrollGesturesEnabled?: boolean;
/** Allow map tilting */
tiltGesturesEnabled?: boolean;
/** Allow zoom gestures */
zoomGesturesEnabled?: boolean;
/** Map padding */
padding?: { top: number; right: number; bottom: number; left: number; };
}
/**
* Google Map instance interface
*/
interface GoogleMapObject {
/**
* Add marker to map
* @param options Marker options
* @returns Promise resolving to marker instance
*/
addMarker(options: MarkerOptions): Promise<any>;
/**
* Move camera to position
* @param target Camera target options
* @returns Promise indicating animation completion
*/
animateCamera(target: CameraPosition): Promise<any>;
/**
* Move camera to position instantly
* @param target Camera target options
*/
moveCamera(target: CameraPosition): void;
/**
* Get current camera position
* @returns Promise resolving to current camera position
*/
getCameraPosition(): Promise<CameraPosition>;
/**
* Set map bounds
* @param bounds Array of coordinates defining bounds
* @returns Promise indicating completion
*/
setMyLocationEnabled(enabled: boolean): Promise<any>;
/**
* Remove the map
*/
remove(): void;
/**
* Clear all overlays from map
*/
clear(): void;
/**
* Add event listener
* @param event Event name
* @returns Observable emitting map events
*/
on(event: string): Observable<any>;
}
/**
* Camera position for map view
*/
interface CameraPosition {
/** Target coordinates */
target?: { lat: number; lng: number; };
/** Zoom level */
zoom?: number;
/** Tilt angle */
tilt?: number;
/** Bearing angle */
bearing?: number;
/** Animation duration */
duration?: number;
}
/**
* Marker configuration options
*/
interface MarkerOptions {
/** Marker position */
position: { lat: number; lng: number; };
/** Marker title */
title?: string;
/** Marker snippet (subtitle) */
snippet?: string;
/** Marker icon */
icon?: string | any;
/** Marker anchor point */
anchor?: { x: number; y: number; };
/** Whether marker is draggable */
draggable?: boolean;
/** Whether marker is visible */
visible?: boolean;
/** Marker z-index */
zIndex?: number;
/** Custom data */
data?: any;
}
/**
* GoogleMap class for map integration
*/
class GoogleMap {
/**
* Check if Google Maps is available
* @returns Promise resolving to availability status
*/
static isAvailable(): Promise<boolean>;
/**
* Create Google Map instance
* @param element HTML element or selector for map container
* @param options Map configuration options
* @returns GoogleMapObject instance
*/
static create(element: string | HTMLElement, options?: GoogleMapOptions): GoogleMapObject;
}Usage Examples:
import { GoogleMap, GoogleMapOptions } from 'ionic-native';
// Initialize map
async function initializeMap(elementId: string) {
try {
const isAvailable = await GoogleMap.isAvailable();
if (!isAvailable) {
console.error('Google Maps not available');
return;
}
const options: GoogleMapOptions = {
center: { lat: 37.7749, lng: -122.4194 },
zoom: 12,
mapType: 'MAP_TYPE_NORMAL',
myLocationEnabled: true,
myLocationButtonEnabled: true,
compassEnabled: true,
zoomControlsEnabled: false,
scrollGesturesEnabled: true,
zoomGesturesEnabled: true,
rotateGesturesEnabled: true,
tiltGesturesEnabled: true
};
const map = GoogleMap.create(elementId, options);
// Set up event listeners
map.on('MAP_READY').subscribe(() => {
console.log('Map is ready');
addMapFeatures(map);
});
map.on('MAP_CLICK').subscribe((event) => {
console.log('Map clicked at:', event.latLng);
});
return map;
} catch (error) {
console.error('Map initialization failed:', error);
}
}
// Add markers and features to map
async function addMapFeatures(map: GoogleMapObject) {
// Add custom markers
const locations = [
{ lat: 37.7749, lng: -122.4194, title: 'San Francisco', snippet: 'The Golden City' },
{ lat: 37.7849, lng: -122.4094, title: 'North Beach', snippet: 'Italian District' },
{ lat: 37.7649, lng: -122.4294, title: 'Mission District', snippet: 'Vibrant Neighborhood' }
];
for (const location of locations) {
await map.addMarker({
position: { lat: location.lat, lng: location.lng },
title: location.title,
snippet: location.snippet,
icon: 'blue',
draggable: false,
data: { type: 'poi', id: location.title.toLowerCase() }
});
}
// Add marker click listener
map.on('MARKER_CLICK').subscribe((marker) => {
console.log('Marker clicked:', marker.title);
showMarkerDetails(marker);
});
}
// Location-based map features
class LocationMap {
private map: GoogleMapObject;
private userMarker: any;
private locationWatcher: any;
async initialize(elementId: string) {
this.map = GoogleMap.create(elementId, {
myLocationEnabled: true,
myLocationButtonEnabled: true,
zoom: 15
});
await this.map.on('MAP_READY').toPromise();
this.startLocationTracking();
}
async startLocationTracking() {
try {
const position = await Geolocation.getCurrentPosition({
enableHighAccuracy: true
});
// Center map on user location
this.map.animateCamera({
target: {
lat: position.coords.latitude,
lng: position.coords.longitude
},
zoom: 16,
duration: 1000
});
// Add user marker
this.userMarker = await this.map.addMarker({
position: {
lat: position.coords.latitude,
lng: position.coords.longitude
},
title: 'You are here',
icon: 'red'
});
// Watch position changes
this.locationWatcher = Geolocation.watchPosition({
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 1000
}).subscribe((pos) => {
this.updateUserPosition(pos.coords.latitude, pos.coords.longitude);
});
} catch (error) {
console.error('Location tracking failed:', error);
}
}
private async updateUserPosition(lat: number, lng: number) {
if (this.userMarker) {
// Update marker position
this.userMarker.setPosition({ lat, lng });
// Optionally animate camera to follow user
this.map.animateCamera({
target: { lat, lng },
duration: 500
});
}
}
async addNearbyPlaces(places: any[]) {
for (const place of places) {
await this.map.addMarker({
position: { lat: place.lat, lng: place.lng },
title: place.name,
snippet: place.description,
icon: this.getPlaceIcon(place.type),
data: place
});
}
}
private getPlaceIcon(type: string): string {
const iconMap: { [key: string]: string } = {
restaurant: 'orange',
gas_station: 'green',
hospital: 'red',
school: 'blue',
park: 'green'
};
return iconMap[type] || 'gray';
}
destroy() {
if (this.locationWatcher) {
this.locationWatcher.unsubscribe();
}
if (this.map) {
this.map.remove();
}
}
}