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, thennpx cap sync ios. - Android: verify API 23+ and run
npx cap sync android. - Confirm the installed package is
@doorstepai/dropoff-sdk-capacitorand the imported object isDoorstepAIDropoffSDK.
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
sessionServerIdAssignedand Android STARTED ids are handled - Native production builds include every requested permission declaration