@doorstepai/dropoff-sdk

中文文档
2.2.10发布于 2026/11/06TypeScriptCommonJS近 30 天下载 2473

doorstep.ai dropoff sdk for React Native

原始使用文档
文档目录17 节
  1. 📦 Installation
  2. 🚀 Getting Started
  3. 1. Import Components
  4. 2. Add RootDoorstepAI to Root File
  5. 📲 Example Usage
  6. 🔧 SDK API
  7. Setup
  8. Embedded Doorstep Go map
  9. Deliveries
  10. Route geofencing
  11. Permissions
  12. ✅ Best Practices
  13. 🧪 Debugging
  14. 🔐 Permissions
  15. 📱 iOS
  16. 🤖 Android
  17. Requesting them at runtime

DoorstepAI Dropoff SDK for React Native

The @doorstepai/dropoff-sdk provides a set of tools to integrate delivery tracking into your React Native application. This SDK enables seamless coordination between your delivery interface and DoorstepAI's backend systems.

📦 Installation

npm install @doorstepai/dropoff-sdk

🚀 Getting Started

1. Import Components

import {
  RootDoorstepAI,
  DoorstepAI
} from '@doorstepai/dropoff-sdk';

2. Add RootDoorstepAI to Root File

Place the following component in the root of your App.tsx or main entry file:

import { RootDoorstepAI } from "@doorstepai/dropoff-sdk"

const App = () => {
  return (
    <View>
        <RootDoorstepAI 
          apiKey="YOUR_API_KEY_HERE" 
          notificationTitle="Some Notification Title"
          notificationText="Some Notification Text"
        />
        {/** Your App Components */}
  )
}

This sets the API key, initializes the SDK, and runs the permission sequence when the app launches. Every part of it is available a la carte on DoorstepAI — the component exists so a host that just wants the default flow does not have to write it.

The notification title/text is passed to Android's foreground service, so you get full control over that text.

Optional props:

propdefaultwhat it does
permissions(every bucket)The whitelist handed to requestPermissions: exactly these buckets are requested and nothing else. See Permissions.
requestBackgroundLocationtrueRun the second-phase locationAlways request once foreground location is granted. It has to be a second phase because Android auto-denies a background ask bundled with the foreground one. Turn it off if your own onboarding asks for "Allow all the time".
requestBluetoothtrueDeprecated — use permissions, which can narrow any bucket rather than just this one. false drops the platform's Bluetooth bucket from the default whitelist.
<RootDoorstepAI
  apiKey="YOUR_API_KEY_HERE"
  permissions={['location', 'motion']}   // no Bluetooth, no notifications
/>

📲 Example Usage

Use the SDK's functions to track and update delivery events. Below are common examples using buttons.

import { Button } from 'react-native';
import { DoorstepAI } from "@doorstepai/dropoff-sdk"

// Start a delivery using a Google Place ID
<Button title="Start Delivery" onPress={() => {
  DoorstepAI.startDeliveryByPlaceID('destination_place_id', 'delivery_id_1');
}} />

// Start a delivery using an address
<Button title="Start Delivery by Address" onPress={() => {
  const address = {
    streetNumber: '123',
    route: 'Main St',
    subPremise: 'Apt 4B',
    locality: 'New York',
    administrativeAreaLevel1: 'NY',
    postalCode: '10001'
  };
  DoorstepAI.startDeliveryByAddress(address, 'delivery_id_1');
}} />

// Send "taking_pod" event
<Button title="Taking POD" onPress={() => {
  DoorstepAI.newEvent('taking_pod', 'delivery_id_1');
}} />

// Send "pod_captured" event
<Button title="POD Captured" onPress={() => {
  DoorstepAI.newEvent('pod_captured', 'delivery_id_1');
}} />

// End the delivery
<Button title="End Delivery" onPress={() => {
  DoorstepAI.stopDelivery('delivery_id_1');
}} />

🔧 SDK API

Every method below is a thin pass-through to the native iOS/Android SDK. Where a method exists on only one platform it says so, and it rejects on the other rather than resolving a fabricated value — a helper that quietly resolved true/[] would read as "granted" / "nothing needed" to a cross-platform host.

Setup

methodnotes
init(notificationTitle?, notificationText?): Promise<void>Android only (no-op on iOS). Handled for you by <RootDoorstepAI />. The title/text go on the foreground-service notification.
setApiKey(apiKey): voidCollection API key.
setDoorstepGoApiKey(apiKey): voidDoorstep Go is a separate credential and realm; a no-op if you do not use it.
configureRemoteLogging({ enabled, minLevel?, flushIntervalSeconds?, batchSize?, maxQueueSize? }): voidiOS only (no-op on Android, which drives remote logging from remote config).
debugStateJson(): Promise<string>iOS only. Free-form internal-state dump for bug reports — never branch on it.
retryGnssCallbacks(): Promise<boolean>Android only. Re-registers raw-GNSS callbacks after the OS silently stops delivering them.
enableDevMode(apiKey) / validateDevModeAccess() / disableDevMode()Dev tooling. The last two are Android-only and answer false on iOS.

Embedded Doorstep Go map

Set the separate Doorstep Go key before mounting the view, then use either the named export or DoorstepAI.EmbedView:

import { DoorstepAI, DoorstepEmbedView } from '@doorstepai/dropoff-sdk';

DoorstepAI.setDoorstepGoApiKey('YOUR_DOORSTEP_GO_API_KEY');

<DoorstepEmbedView
  address="1600 Pennsylvania Avenue NW, Washington, DC"
  deliveryID="delivery-123"
  inlineHeight={300}
  expandedHeight={600}
  borderRadius={16}
  linkAPI="https://api.core.doorstep.ai"
  baseMap="light"
  parkingText="95% of drivers parked here"
  markerColor="#027FB8"
  polygonColor="#3291BC"
  parkingColor="#FF847B"
  onModeChanged={(mode) => console.log('embed mode', mode)}
  onLoad={() => console.log('embed navigation started')}
  onSuccess={() => console.log('embed ready')}
  onError={(message, error) => console.warn(error.code, error.stage, message)}
/>

DoorstepAI.EmbedView accepts the same props. mode is optional: omit it to let the native expand/collapse control own the mode, or provide it as a controlled prop. The component defaults its height to the active mode's inlineHeight or expandedHeight; an explicit style.height overrides that behavior. borderRadius (points/dp, default 0) rounds the native map card itself — use it instead of style.borderRadius, which does not clip the native map. Keep the view mounted while it is visible, because detaching Android's WebGL-backed map destroys its graphics context.

For preloading and revealing the same mounted map only after onSuccess, see embed-preload.example.tsx. It keeps the native view attached at full size with opacity zero while loading, disables touch and accessibility while hidden, and handles errors and a bounded preload timeout. Use show={false} to preload for later, then set it to true to reveal once ready. Keep its parent mounted and avoid navigation that detaches native screens. This retains a live view in memory; it does not download a durable offline map.

onLoad fires when navigation starts after the signed link is created; onLoading remains a compatibility alias. onSuccess fires when the page reports map readiness, so use it to reveal a preloaded map. onLoad alone does not mean the map is ready. These callbacks require the updated JavaScript package and a rebuilt native app on both Android and iOS; an Expo OTA JavaScript update alone cannot add missing native callbacks.

The optional mapStyleToggle, gpsRecenterToggle, streetViewToggle, and expandContractToggle props default to true on both platforms. endpoint={{lat, lng}} forwards destination coordinates, fitGpsOnStart defaults to false, and readyTimeoutSeconds defaults to 15. Native button analytics travel directly through the native SDK's WebView bridge to Doorstep Go; React Native does not need to forward them.

onError(message, error) keeps the legacy message as its first argument and supplies a DoorstepEmbedError as its second: code, stage, message, isRetryable, and optional httpStatusCode/requestId. Both platforms use the same field names and enum values. onLoading reports navigation starting; onSuccess reports page readiness.

Deliveries

All four starters take the same trailing StartDeliveryOptions:

type StartDeliveryOptions = {
  timeoutSeconds?: number;              // hard session cap; OMIT for none
  manualForeground?: boolean;           // Android only: host owns the FGS
  customerId?: string;
  driverId?: string;
};
methodnotes
startDeliveryByAddressString(address, deliveryId, timeoutSeconds?, coordinates?, options?)Preferred. Pass coordinates when you have them.
startDeliveryByAddress(address: AddressType, deliveryId, timeoutSeconds?, coordinates?, options?)Structured address.
startDeliveryByPlaceID(placeID, deliveryId, timeoutSeconds?, options?)Google Place ID.
startDeliveryByLatLng(lat, lng, subUnit, deliveryId, timeoutSeconds?, options?)Deprecated — use an address method with coordinates.
startDeliveryByPlusCode(plusCode, deliveryId, timeoutSeconds?, options?)Deprecated — same.
markDropoff(deliveryId, 'pod' | 'non_pod'): Promise<void>Records completion and gates the route-geofence EXIT stop.
stopDelivery(deliveryId): Promise<void>
newEvent(eventName, deliveryId, timestamp?): Promise<...>timestamp is optional epoch seconds.
type AddressType = {
  streetNumber: string;
  route: string;
  subPremise: string;                 // apartment, suite, unit
  locality: string;                   // city
  administrativeAreaLevel1: string;   // state/province
  postalCode: string;
};

timeoutSeconds omitted means NO backstop, which is the native behaviour on both platforms. (An older version of this wrapper substituted 3600 s here and force-stopped every delivery at one hour.)

One cross-platform difference the wrapper does not paper over: Android resolves the server session id ({"id":"<uuid>"}) from a starter and iOS resolves nothing — native returns Void there. Treat a resolved promise as the success signal, not a truthy return value. On iOS, listen for the SDK's sessionServerIdAssignedNotification natively if you need the id.

Route geofencing

The SDK fences each stop and auto-starts a delivery on qualified ENTER. The server owns radius and EXIT policy (misc.geofence.waitForDropoff): true/missing requires markDropoff before EXIT stops the session; false permits unmarked EXIT and keeps the stop armed. Whole-route telemetry is also server controlled. Background routes require location authorization and the native SDK's supported foreground/background execution setup; Always authorization provides the broadest recovery support.

type DeliveryStop = {
  deliveryId: string;
  address: string;
  latitude: number;
  longitude: number;
  routeStopId?: string;    // stable identity; defaults to deliveryId
  radiusMeters?: number;   // deprecated, ignored; radius is server controlled
  customerId?: string;
  driverId?: string;
};

type RouteOptions = {
  defaultRadiusMeters?: number;          // deprecated, ignored
  timeoutSeconds?: number;               // per auto-started session
  autoStopAfterDropoffSeconds?: number;
  manualForeground?: boolean;            // Android only; ignored on iOS
  maxAgeSeconds?: number;                 // Android only
  clientRouteId?: string;
  driverId?: string;
  metadata?: Record<string, string>;
};
// RouteGeofenceOptions remains a deprecated alias for source compatibility.

For Android routes using a host-owned location foreground service, start that service while the app is visible, then await readiness before starting the route:

await Location.startLocationUpdatesAsync(LOCATION_TASK, locationOptions);
await DoorstepAI.waitForHostForegroundService({
  timeoutMs: 10_000,
  serviceClassName: 'expo.modules.location.services.LocationTaskService',
});
await DoorstepAI.startRouteGeofencing(stops, { manualForeground: true });

waitForHostForegroundService(options?): Promise<void> is Android-only and rejects on iOS. It checks immediately, then every 100 ms using Android's own-app running-service query. timeoutMs defaults to 10000 and accepts integer values from 0 to 120000; zero performs one immediate check. Omit serviceClassName to accept any foreground service in your app except Doorstep's tracking service. For Expo, match its service class as above so unrelated services cannot satisfy the wait. Rejections have native codes HOST_FGS_TIMEOUT, HOST_FGS_CHECK_FAILED, or HOST_FGS_CANCELLED (module teardown). The query is deprecated but still supports inspecting the caller's own services.

Success is a snapshot of foreground state, not proof of location-service type, permissions, fresh fixes, or future uptime. Keep the host location service alive for the entire route. This method does not start a service, initialize tracking, or alter manualForeground. Updating JavaScript alone is insufficient: rebuild the native Android app after updating the SDK.

methodnotes
startRouteGeofencing(stops, options?): Promise<void>Rejects if no stop has a deliveryId + coordinates.
updateRouteStops(stops): Promise<void>Replaces the list in place. Removing a stop that has an active session stops it immediately (reason removed_from_route) — not EXIT-driven, not dropoff-gated. Does not extend the route lease.
stopRouteGeofencing(): Promise<void>Teardown is handed to the tracking service / region manager, so getMonitoredStops() can still show the old list for a moment.
resumeRouteGeofencingIfNeeded(): Promise<void>Call this on every launch. A per-launch host obligation: without it Android silently loses route monitoring across a process kill.
getMonitoredStops(): Promise<DeliveryStop[]>The SDK's intent registry, not the OS's registered-region set.
isRouteGeofencingActive(): Promise<boolean>Durable route intent, independent of an active delivery.
getActiveRouteId(): Promise<string | null>Canonical SDK route UUID on either platform.
getActiveRouteRevision(): Promise<number | null>Current manifest revision, or null without a route.
addMetadata(deliveryId, metadata): Promise<void>Attach JSON metadata before or after a delivery session starts.
addGeofenceSessionListener(cb): EmitterSubscription | undefined{ deliveryId, type: 'STARTED' | 'STOPPED', reason }. Call .remove() to unsubscribe.
const sub = DoorstepAI.addGeofenceSessionListener(({ deliveryId, type, reason }) => {
  console.log(type, deliveryId, reason);
});
await DoorstepAI.startRouteGeofencing(stops, { clientRouteId: 'route-123', driverId: 'driver-123' });
// ...later
sub?.remove();

Permissions

checkPermissions, checkPermissionsJson, requestPermissions, allPermissionBuckets, notePermissionRequestResult, and the Android-only query helpers. See Permissions below — that section is the reference.


✅ Best Practices

  • Always wrap DoorstepAI API calls in try/catch or use .catch() for better error handling when applicable.
  • Use the RootDoorstepAI component only once at the root of your app.
  • Ensure your API key is securely stored and never hardcoded in production.
  • Always provide a unique deliveryId for each delivery session.
  • Keep track of the deliveryId throughout the delivery lifecycle as it's required for all operations.

🧪 Debugging

If something isn't working as expected:

  • Check console logs for DoorstepAI initialized or error messages.
  • Verify that the API key is valid and accepted by the SDK.
  • Ensure your permissions (e.g., location) are correctly set up on the device.
  • Verify that you're using the correct deliveryId for each operation.

🔐 Permissions

To use the @doorstepai/dropoff-sdk effectively, you must include the appropriate permissions in your mobile app's configuration files.

📱 iOS

In your Info.plist, include the following usage descriptions:

<!-- Location Usage Descriptions -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app requires access to your location for delivery tracking.</string>
<key>NSLocationAlwaysAndWhenInUseUsage</key>
<string>This app requires access to your location to provide continuous tracking even in the background.</string>

<!-- Optional: Motion & Sensor Data (if applicable) -->
<key>NSMotionUsageDescription</key>
<string>This app uses motion data to enhance delivery tracking accuracy.</string>

<!-- Required if you let Bluetooth default to on (see the permission API below).
     Without this key the SDK skips the Bluetooth request with a warning. -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to improve delivery location accuracy.</string>

<!-- Background Location Mode -->
<key>UIBackgroundModes</key>
<array>
    <string>location</string>
</array>

🤖 Android

The SDK's own manifest already declares every permission it needs, so manifest merging supplies them to your app. Declare these only if you want them visible in your own AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-feature android:name="android.hardware.sensor.accelerometer" />
<uses-feature android:name="android.hardware.sensor.gyroscope" />
<uses-feature android:name="android.hardware.sensor.barometer" />
<uses-feature android:name="android.hardware.sensor.compass" />
<uses-feature android:name="android.hardware.sensor.proximity" />

Requesting them at runtime

<RootDoorstepAI /> does this for you. Use the API directly if you drive permissions from your own onboarding flow — every method delegates to the native SDK's own whitelist permission API, so the buckets, the states, the prompt order and the "what will I decline to ask, and why" planning stay whatever the SDK says they are.

One requester, both platforms. No argument requests everything; an argument is a whitelist and nothing outside it is ever asked for. Do not branch on Platform.OS to ask for permissions — the branch is inside the wrapper, on DoorstepAI.requestPermissions(_ permissions:…) (iOS) and DoorstepAI.requestPermissions(activity, permissions) (Android).

await DoorstepAI.requestPermissions();                       // every bucket
await DoorstepAI.requestPermissions(['locationWhenInUse']);   // only this one
await DoorstepAI.requestPermissions({                         // object form
  permissions: ['location', 'motion'],
  onlyIfNotDetermined: true,   // iOS
  timeoutSeconds: 60,
});

Buckets

A bucket is one user-visible OS decision. They are deliberately OS-specific, because the platforms are — only the two location buckets exist on both:

bucketiOSAndroid
locationWhenInUserequestWhenInUseAuthorizationACCESS_FINE_LOCATION + ACCESS_COARSE_LOCATION
locationAlwaysrequestAlwaysAuthorizationACCESS_BACKGROUND_LOCATION
motionFitnessMotion & Fitness—
activityRecognition—ACTIVITY_RECOGNITION
bluetoothCBCentralManager—
bluetoothScan—BLUETOOTH_SCAN (API 31+)
nearbyWifiDevices—NEARBY_WIFI_DEVICES (API 33+)
notifications—POST_NOTIFICATIONS (API 33+)

You can pass either platform's name on either platform: the wrapper translates the counterpart (motionFitness ⇄ activityRecognition, bluetooth ⇄ bluetoothScan), so one whitelist works on both without a Platform.OS branch. A name with no counterpart at all (notifications on iOS) comes back in unsupported rather than being dropped in silence. The coarse aliases 'location' (→ both location buckets), 'motion' / 'activity' and 'bluetooth' are still accepted — they are what the published 2.x API took.

DoorstepAI.allPermissionBuckets() returns this platform's list if you want to build a permission screen without hardcoding it.

States

Eight states, the same names on both platforms, so host code branches once:

statemeaning
grantedheld right now
notDeterminednever asked; a request will show a dialog
whenInUseOnlyforeground location held, background not. Only ever reported for locationAlways
deniedrefused, another prompt is still possible (Android only)
permanentlyDeniedrefused, no further prompt possible — deep-link to Settings. Every iOS refusal lands here
restrictedblocked by device policy / MDM / Screen Time
unavailablethe OS version or the hardware does not have it. Not a failure
notDeclaredyour build is missing the declaration (<uses-permission> / NS…UsageDescription). Not a user refusal — fixable by you

whenInUseOnly is the load-bearing one: never treat it as granted. Background collection and route geofencing do not work in it.

// Read the current state. Pure observation — never shows a dialog.
const { statuses } = await DoorstepAI.checkPermissions();
if (statuses.locationAlways?.state === 'whenInUseOnly') {
  // foreground-only: no background collection, no route geofencing
}
if (statuses.locationWhenInUse?.state === 'permanentlyDenied') {
  // a request would be answered instantly with no dialog — send them to Settings
}

What a request answers with

requestPermissions resolves only after the user has answered, with the settled state — a status read while a prompt is still up would be a lie. Everything native declined to ask comes back explained rather than silently not happening:

const result = await DoorstepAI.requestPermissions();
result.requested;          // buckets a dialog was actually raised for
result.alreadyDetermined;  // already answered, so left alone
result.unavailable;        // absent on this device / missing from this build
result.deferred;           // deliberately skipped, with the reason
result.statuses;           // state of every whitelisted bucket, after settling
result.permissions;        // legacy { location, motion, bluetooth } view
result.unsupported;        // whitelist entries this platform has no bucket for

Expect locationAlways in deferred on a full-whitelist call. It is only ever asked alone and only after foreground location is granted — Android auto-denies a bundled background ask, and iOS shows the When-In-Use prompt first and offers the Always upgrade later on its own schedule. So the standard two-phase flow is:

const first = await DoorstepAI.requestPermissions();
if (first.statuses.locationWhenInUse?.state === 'granted') {
  await DoorstepAI.requestPermissions(['locationAlways']);
}

Device-measured, Moto G stylus 5G / Android 14: a full-whitelist call raises the five askable dialogs in one batch and returns deferred: { locationAlways: 'ACCESS_BACKGROUND_LOCATION cannot be requested before foreground location is granted…' }. iPhone 16 Pro / iOS 26.6: it raises locationAlways, motionFitness and bluetooth one at a time and returns deferred: { locationWhenInUse: 'covered by the locationAlways prompt in this call…' }.

A second call made while one is still in flight does not interleave prompt sequences: iOS reports every bucket as deferred, Android rejects with E_PERMISSION_REQUEST_IN_FLIGHT. If the user never answers, the wait gives up after timeoutSeconds (default 120 s) and resolves with the state as it stands.

iOS guidance from the SDK: call it once, from a user-initiated flow, not from app launch.

Android: forward your grant results (optional, worth doing)

Android reports identical signals for "permanently denied" and "never asked", and a cancelled dialog leaves the same trace as a denial. The SDK refuses to guess, so without a real answer a refusal reports as the re-askable denied. Forward the result and you get permanentlyDenied — and the JS promise settles on the answer itself instead of on a window-focus heuristic:

// MainActivity.kt
import com.doorstepai.dropoffsdk.DoorstepAIModule

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

There is a JS entry point too (DoorstepAI.notePermissionRequestResult(permissions, grantResults)) if the values reach you there instead.

Legacy three-value view

statuses is the real answer, but every result also carries the { location, motion, bluetooth } × granted | denied | prompt map the published 2.x API returned, so existing hosts keep working. It is collapsed from statuses: whenInUseOnly and unavailable → granted, notDetermined → prompt, everything else (including notDeclared) → denied.

Two things it cannot tell you, which is why it is deprecated: While-In-Use vs Always, and a host-build mistake vs a user refusal.

motion stays unconditionally granted on Android, exactly as in 2.x. That is the honest answer to what the key asks — Android's IMU streams (accel, gyro, mag, rotation vectors, barometer) need no runtime grant, so motion collection is always possible there. activityRecognition adds only the step-counter streams, and the SDK never blocks a session on it; read statuses.activityRecognition for its real state. On iOS motion does track Motion & Fitness, which genuinely gates CMMotionActivityManager, CMSensorRecorder and absolute altitude.

Android-only query helpers

These reject on iOS rather than resolving true/[], which a cross-platform host would read as "granted" / "nothing needed".

await DoorstepAI.hasRequiredPermissions();          // -> boolean
await DoorstepAI.hasBackgroundLocationPermission(); // -> boolean
await DoorstepAI.requestBackgroundLocationPermission();

// Want the grant results in JS? Request the SDK's own flat list with RN's API.
const required = await DoorstepAI.getRequiredPermissions();
await PermissionsAndroid.requestMultiple(required);

requestPermissions(['locationAlways']) is the cross-platform way to express the same intent as requestBackgroundLocationPermission(), and it reports back why if the OS would have refused to show the prompt.


版本与发布记录

@doorstepai/dropoff-sdk 共发布 56 个版本,首次发布于 2025/04/17;过去 12 个月发布了 23 个版本。

版本发布日期距今
2.2.10latest2026/11/067 天前
2.2.92026/10/1529 天前
2.2.82026/10/121 个月前
2.2.72026/10/011 个月前
2.2.62026/10/011 个月前
2.2.52026/10/011 个月前

关于 @doorstepai/dropoff-sdk 的常见问题

@doorstepai/dropoff-sdk 是什么?

doorstep.ai dropoff sdk for React Native

如何安装 @doorstepai/dropoff-sdk?

在项目目录运行 npm install @doorstepai/dropoff-sdk,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(*)、react-native(*)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@doorstepai/dropoff-sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@doorstepai/dropoff-sdk 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@doorstepai/dropoff-sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.11.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@doorstepai/dropoff-sdk 可以商用吗?

@doorstepai/dropoff-sdk 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@doorstepai/dropoff-sdk 的下载量有多少?

根据 npm 官方下载统计,@doorstepai/dropoff-sdk 在 2026/10/13 – 2026/11/11 这 30 天内被下载 2,473 次,日均约 82 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@doorstepai/dropoff-sdk 还在维护吗?

最新版本 2.2.10 发布于 2026/11/06(7 天前);至今共发布 56 个版本,其中过去 12 个月发布了 23 个;首次发布于 2025/04/17。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。