Skip to main content

Events

The SDK emits events from the native layer for tracking, analytics, and custom UI.


Event Types

EventDescription
DOWNLOAD_PROD_STARTEDDownload started
DOWNLOAD_PROD_COMPLETEDDownload succeeded
DOWNLOAD_PROD_FAILEDDownload failed
INSTALLED_PRODUpdate installed
ROLLBACK_PRODRolled back to previous bundle
STABILIZE_PRODBundle promoted to stable
CORRUPTION_PRODBundle corruption detected
SYNC_ERRORError syncing events with server
VERSION_CHANGEDActive bundle version changed
CRASH_DETECTEDCrash detected within the detection window

Event Shape

interface SwiftPatchEvent {
id: string; // Unique event ID
eventType: SwiftPatchEventType; // One of the types above
timestamp: number; // Unix timestamp
releaseHash?: string; // Associated bundle hash
errorMessage?: string; // Error details (for failures)
metadata?: Record<string, unknown>; // Additional context
}

Native Event Subscriptions

These fire in real time from the native layer -- not through the polled event queue (a queue where the SDK periodically checks for new events from native code).

Step 1: Import the Listeners

import {
onDownloadProgress,
onRollback,
onVersionChanged,
onNativeEvent,
} from '@swiftpatch/react-native';

Step 2: Subscribe in a useEffect

Download Progress

import { onDownloadProgress } from '@swiftpatch/react-native';

useEffect(() => {
const unsubscribe = onDownloadProgress((progress) => {
console.log(`${progress.percentage}% complete`);
});

return unsubscribe;
}, []);

Rollback Events

import { onRollback } from '@swiftpatch/react-native';

useEffect(() => {
const unsubscribe = onRollback((reason) => {
analytics.track('ota_rollback', { reason });
});

return unsubscribe;
}, []);

Version Changes

import { onVersionChanged } from '@swiftpatch/react-native';

useEffect(() => {
const unsubscribe = onVersionChanged((reason) => {
analytics.track('ota_version_changed', { reason });
});

return unsubscribe;
}, []);

All Native Events

import { onNativeEvent } from '@swiftpatch/react-native';

useEffect(() => {
const unsubscribe = onNativeEvent((event) => {
console.log('Native event:', JSON.stringify(event));
});

return unsubscribe;
}, []);
tip

Always return the unsubscribe function from useEffect to clean up listeners.


Event Polling

The SDK also polls the native event queue to ensure no events are lost. This runs automatically inside SwiftPatchProvider.

Adaptive Backoff

Polling uses adaptive backoff (gradually increasing the time between checks when there is no new activity):

TierIntervalCondition
Active3s0-2 empty polls
Cooling6s3-9 empty polls
Idle15s10-19 empty polls
Deep idle60s20+ empty polls

Any received event resets to the Active tier.

Background Behavior

Polling pauses when the app goes to the background and resumes when it returns. This prevents unnecessary battery and network usage.

Polling Cycle

  1. JS calls popEvents() to retrieve queued native events
  2. Events are processed and dispatched to listeners
  3. Events are sent to the server at /sdk/log-bulk-events
  4. Acknowledged events are cleared via acknowledgeEvents()

Analytics Integration

Forward OTA events to your analytics provider:

import { onRollback, onNativeEvent } from '@swiftpatch/react-native';

useEffect(() => {
const subs = [
onRollback((reason) => {
analytics.track('ota_rollback', { reason });
}),

onNativeEvent((event) => {
analytics.track('swiftpatch_event', event);
}),
];

return () => subs.forEach(unsub => unsub());
}, []);

Download Progress via Hook

For UI display, use the useSwiftPatch hook instead -- it provides downloadProgress as reactive state:

import { useSwiftPatch, UpdateStatus } from '@swiftpatch/react-native';

function ProgressBar() {
const { status, downloadProgress } = useSwiftPatch();

if (status !== UpdateStatus.DOWNLOADING || !downloadProgress) return null;

return (
<View>
<Text>{downloadProgress.percentage}%</Text>
<Text>{downloadProgress.downloadedBytes} / {downloadProgress.totalBytes} bytes</Text>
</View>
);
}
info

For most UI use cases, the useSwiftPatch hook is easier than raw event subscriptions. Use native subscriptions for analytics and logging.