How It Works
SwiftPatch delivers JavaScript bundle updates to your React Native app without going through the app store. Think of it like hot-swapping the engine of a car while it is parked -- the body (native code) stays the same, but the engine (JavaScript) gets replaced.
The SDK detects updates, downloads a differential patch, verifies its integrity, and swaps the bundle at the next restart. A three-slot architecture ensures automatic fallback if anything goes wrong.
Architecture
SwiftPatch has three components:
| Component | What it does |
|---|---|
CLI (swiftpatch) | Bundles JavaScript, generates patches, and publishes releases |
| Dashboard | Web interface for managing projects, rollouts, installs, and rollbacks |
SDK (react-native-swiftpatch) | Checks for updates, downloads patches, verifies integrity, manages bundle slots |
The CLI pushes releases to the API. The API stores patches on a CDN (Content Delivery Network -- servers worldwide that deliver downloads from the nearest location). The SDK polls the API, discovers releases, pulls patches from the CDN, and applies them locally.
Update Lifecycle
Here is what happens every time your app checks for an update:
Every step has built-in safety checks. If the download fails, the patch is corrupt, or the hash does not match, the SDK discards the update and users continue with the current bundle.
Bundle Management
Stock Bundle
Every React Native app ships with a JavaScript bundle in the binary. This is the stock bundle -- the baseline from the app store. It lives in DEFAULT_SLOT and is always available as a fallback.
OTA Bundles
When you publish an update, the SDK downloads and stores the new bundle. On the next launch, the SDK loads the OTA bundle instead of the stock bundle.
Three-Slot Architecture
Think of this like having three parking spots for bundles. If the newest one causes problems, the app can always fall back to an older, trusted one.
| Slot | Role | Fallback on failure |
|---|---|---|
DEFAULT_SLOT | Original app store bundle | Always available |
STABLE_SLOT | Verified OTA bundle | Falls back to DEFAULT_SLOT |
NEW_SLOT | Freshly installed OTA bundle, pending verification | Falls back to STABLE_SLOT or DEFAULT_SLOT |
Promotion flow:
- New update installs into
NEW_SLOT - App launches successfully for
autoStabilizeAfterLaunchestimes - SDK promotes
NEW_SLOTtoSTABLE_SLOT - If crashes are detected before promotion, the SDK reverts automatically
See Rollbacks for details.
Update Detection
The SDK checks for updates at four points:
| Trigger | When | Configuration |
|---|---|---|
| App launch | When SwiftPatchProvider mounts | Always enabled |
| App resume | Return from background | checkOnResume: true |
| Manual check | When you call checkForUpdate() | On demand |
| Throttled | Minimum interval between checks | checkInterval (default: 60s) |
Patch Application
Step 1: Download -- Differential patch from CDN (or full bundle for the first OTA update).
Step 2: Patch -- bspatch (a binary patching tool that reconstructs files from patches) applies the diff to produce the new bundle.
Step 3: Verify hash -- SHA-256 (a cryptographic function that creates a unique fingerprint for any file) compared against the server's expected hash.
Step 4: Verify signature -- JWT (JSON Web Token -- a compact, signed data format) signature verified with your public key (if signing is enabled).
Step 5: Store -- Bundle written to disk, NEW_SLOT updated.
Step 6: Install -- App restarts based on installMode.
Safety Mechanisms
Hash Verification
Every bundle has a SHA-256 hash computed at publish time. After patching, the SDK verifies the result matches exactly. Mismatches are discarded.
Crash Detection
- After an update, the bundle enters
NEW_SLOT - On launch,
SwiftPatchProvidercallsmarkMounted()to signal success - If the app crashes before
markMounted()withincrashDetectionWindowMs, the SDK counts it - After
maxCrashesBeforeRollbackcrashes (default: 2), the SDK rolls back
See Crash Detection.
Automatic Rollback
If crashes are detected:
NEW_SLOTbundle is abandonedSTABLE_SLOTorDEFAULT_SLOTis restoredROLLBACK_PRODevent is emitted- Rollback is reported to the API
See Rollbacks.
End-to-End Example
Scenario: Your app is at version 1.2.0 with OTA release r-42. You need to fix a broken checkout button.
Step 1: You publish the fix. The CLI bundles JavaScript, diffs against r-42, signs (if enabled), and uploads.
Step 2: The SDK detects the update. On launch, the SDK loads r-42 from STABLE_SLOT, calls markMounted(), and checks the API. The API returns r-43 metadata.
Step 3: The patch is applied. The SDK downloads the patch (typically 10-100 KB), applies it with bspatch, verifies the hash, and writes the result to NEW_SLOT.
Step 4: The app restarts. Based on installMode, the user gets the fix on next resume or restart.
Step 5: Stabilization. After successful launches with no crashes, r-43 is promoted to STABLE_SLOT.
Next Steps
- Differential Updates -- How patches are generated
- Rollouts -- Ship updates to a percentage of users
- Crash Detection -- Tune crash thresholds
- Rollbacks -- Automatic and manual rollback strategies
- Bundle Signing -- RSA code signing for security