Skip to main content

Capacitor SDK Examples

Quickstart

This example uses the current 2.2.2 package, plugin export, object-shaped calls, and string-union dropoff type.

import { Capacitor } from '@capacitor/core';
import { DoorstepAIDropoffSDK } from '@doorstepai/dropoff-sdk-capacitor';

if (Capacitor.isNativePlatform()) {
await DoorstepAIDropoffSDK.init({
notificationTitle: 'Tracking...',
notificationText: 'Tracking your delivery',
});
await DoorstepAIDropoffSDK.setApiKey({ key: API_KEY });

const foreground = await DoorstepAIDropoffSDK.requestPermissions({
permissions: ['locationWhenInUse', 'motion', 'bluetooth'],
});
if (foreground.statuses.locationWhenInUse.state === 'granted') {
await DoorstepAIDropoffSDK.requestBackgroundLocationPermission();
}

await DoorstepAIDropoffSDK.startDeliveryByAddressString({
address: '123 Main St, Apt 4B, San Francisco, CA 94102',
deliveryId: 'delivery_12345',
coordinates: { lat: 37.7749, lng: -122.4194 },
customerId: 'customer_42',
driverId: 'driver_7',
});

await DoorstepAIDropoffSDK.markDropoff({
deliveryId: 'delivery_12345',
dropoffType: 'pod',
});
await DoorstepAIDropoffSDK.stopDelivery({
deliveryId: 'delivery_12345',
});
}

Route-managed lifecycle

Use this version when the SDK should own geofence registration and automatic session starts/stops:

const sessionIds = await DoorstepAIDropoffSDK.addListener(
'sessionServerIdAssigned',
({ deliveryId, serverSessionId }) => {
// iOS server ids arrive here asynchronously.
console.log(deliveryId, serverSessionId);
},
);

const routeEvents = await DoorstepAIDropoffSDK.addListener(
'geofenceSessionEvent',
({ deliveryId, type, reason, serverSessionId }) => {
// Android STARTED events can include serverSessionId.
console.log({ deliveryId, type, reason, serverSessionId });
},
);

await DoorstepAIDropoffSDK.startRouteGeofencing({
stops: [
{
deliveryId: 'delivery_12345',
address: '123 Main St, San Francisco, CA',
latitude: 37.7749,
longitude: -122.4194,
radiusMeters: 250,
},
{
deliveryId: 'delivery_67890',
address: '500 Market St, San Francisco, CA',
latitude: 37.7899,
longitude: -122.4009,
},
],
options: {
defaultRadiusMeters: 250,
timeoutSeconds: 1800,
},
});

// When dispatch changes:
await DoorstepAIDropoffSDK.updateRouteStops({ stops: updatedStops });

// At logout or shift end:
await DoorstepAIDropoffSDK.stopRouteGeofencing();
await routeEvents.remove();
await sessionIds.remove();

Call resumeRouteGeofencingIfNeeded() after setApiKey on every app launch. Call markDropoff when the driver completes a stop; a later fence EXIT can then stop that route session.

Permission-state handling

Use detailed states to distinguish a user choice from a host-configuration bug:

const { statuses } = await DoorstepAIDropoffSDK.checkPermissions();

switch (statuses.locationAlways.state) {
case 'granted':
break;
case 'whenInUseOnly':
// Explain why background tracking is needed, then request the second phase.
await DoorstepAIDropoffSDK.requestBackgroundLocationPermission();
break;
case 'permanentlyDenied':
case 'restricted':
// Direct the user to Settings or explain the device restriction.
break;
case 'notDeclared':
// Fix AndroidManifest.xml or Info.plist in the app build.
break;
}

Troubleshooting

Plugin is not implemented on web

The SDK is native-only. Guard calls with Capacitor.isNativePlatform(), invoke them after Capacitor bootstraps, and run npx cap sync after installing or updating the package. In Next.js, import and call it only from a 'use client' module.

A permission reports notDeclared

The host build is missing a matching Android manifest entry or iOS usage-description key. This is not a user denial. Compare the bucket with the declarations in the installation guide.

Background tracking or route events do not fire

Check statuses.locationAlways.state; whenInUseOnly is insufficient. Request background location only after locationWhenInUse is granted. On every relaunch, set the API key before calling resumeRouteGeofencingIfNeeded().

Android cannot distinguish a permanent denial

Capacitor does not automatically forward onRequestPermissionsResult to this plugin. If your permission UI needs reliable permanentlyDenied reporting, forward the callback from MainActivity:

import ai.doorstep.dropoffsdk.capacitor.DoorstepAIDropoffSDKPlugin

class MainActivity : BridgeActivity() {
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
DoorstepAIDropoffSDKPlugin.notePermissionRequestResult(
this,
permissions,
grantResults
)
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}

Build or linkage failures

  • iOS: run cd ios/App && pod install, then npx cap sync ios.
  • Android: verify API 23+ and run npx cap sync android.
  • Confirm the installed package is @doorstepai/dropoff-sdk-capacitor and the imported object is DoorstepAIDropoffSDK.

Release checklist

  • SDK initialization and API-key setup succeed on both platforms
  • Foreground and background permission phases are tested on physical devices
  • Manual delivery start, event, mark, and stop calls succeed
  • Route events survive an app relaunch
  • iOS sessionServerIdAssigned and Android STARTED ids are handled
  • Native production builds include every requested permission declaration