SankofaDeploy class

Sankofa Deploy — Flutter Code OTA updates.

Constructed automatically by Sankofa.init(enableDeploy: true) and exposed via Sankofa.deploy. Mirrors the React-Native SDK's SankofaDeploy class but renamed to be a real instance (not a static-only class) so the namespaced access pattern Sankofa.deploy.notifyAppReady() reads as expected.

Server overrides client. The host's enableDeploy: true flag in Sankofa.init is an intent — the SDK constructs the module and registers it with SankofaModuleRegistry. The handshake response from GET /api/v1/handshake includes a modules.deploy.enabled boolean and (when enabled) any pending update payload. If the server says enabled: false (subscription suspended, project disabled, kill-switch flipped) the registry skips routing — the module receives no instructions and the host's Sankofa.deploy.checkForUpdate() call goes through the platform plugin's own HTTP fetch, which the server also refuses on the server side. Either way the host can't ship updates the server hasn't authorized.

The OTA mechanism itself lives in: • libsankofa_updater_ffi.so (Rust updater bundled in the AAB via the plugin's jniLibs) — does the SHA-verified libapp.so download + atomic install + boot-counter rollback; • SankofaFlutterActivity (Kotlin) — overrides getFlutterShellArgs() to add --aot-shared-library-name=... pointing at the patched libapp.so when one is staged.

This Dart class is just the host-facing API around those pieces.

Properties

hashCode int
The hash code for this object.
no setterinherited
name SankofaModuleName
no setter
nativeUpdaterReady bool
True when the legacy native (Android libapp.so) updater half initialized. iOS Path-C apps stay false by design — the KBC pipeline (fetchAndApplyKbcPatch / tryApplyStagedKbcPatch) never needs the native plugin. Exposed so the bootstrap can decide which startup auto-check to drive (native vs KBC).
no setter
options SankofaDeployOptions
final
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
serverSigningKeysB64 List<String>
Snapshot of the active server-distributed signing keys. Exposed mostly for debugging — production code never has to read this because the apply pipeline pulls it via _effectiveSigningPubkeys.
no setter

Methods

applyHandshake(Map<String, dynamic> config) Future<void>
Called by SankofaModuleRegistry.routeHandshake when the server returns a non-empty modules.deploy payload AND that payload's enabled field is true. The registry skips this entirely when the server says enabled: false — there's no kill-switch path here because there's no opt-out: the server simply refuses to issue patches for disabled customers.
applyKbcPatchFromBytes(Uint8List envelopeBytes, {required KbcLoaderFn loader}) Future<KbcPatchResult>
β.3 + ε + β.4 + η: apply a Sankofa Deploy: Flutter Code KBC patch.
applyKbcPatchFromFile(String path, {required KbcLoaderFn loader}) Future<KbcPatchResult>
Convenience wrapper around applyKbcPatchFromBytes. Reads the envelope file off disk, then dispatches as above.
checkForUpdate({String? endpoint, String? apiKey, String? appVersion, String? engineVersion, String? distinctId, String? platform, String? currentLabel, String? flavor, Duration timeout = const Duration(seconds: 30)}) Future<SankofaUpdateCheckResult>
Probe the server for a new patch WITHOUT downloading. The result carries the patch label, size, sha256, signed download URL, and SankofaUpdate.isMandatory flag — enough to drive a confirmation dialog. Hosts then call downloadKbcUpdate when ready.
checkIntegration() Future<ModuleIntegrationStatus>
Self-audit the host's Deploy integration. Returns a structured status describing whether the manifest, MainActivity, permissions and updater FFI are all wired up.
clearBannedKbcLabels() Future<Set<String>>
Clear the banned-label set so previously rolled-back patches can be re-applied. Useful when a customer ships a fix re-using the same label as a broken one (rare). Returns the labels that were cleared, for logging / telemetry.
consumeLastAutoDisabledPatchLabel() Future<String?>
Returns the label of the most recently auto-disabled patch (and clears the marker so next call returns null). Dashboards can show "we rolled back release X for you" the next time the app phones home. Empty string when no rollback has happened.
disableCurrentPatch() Future<void>
Disable the currently active patch, forcing the next launch to boot from the baseline libapp.so. Useful for support workflows ("turn off the bad patch for this user, we'll re-roll").
downloadUpdate(SankofaUpdate update, {void onProgress(int received, int total)?, Duration timeout = const Duration(minutes: 5)}) Future<String>
Download the envelope discovered by checkForUpdate and stage it on disk for tryApplyStagedKbcPatch to pick up on the next launch. Streams the response so onProgress fires on every chunk with the running (received, total) bytes — drives a progress bar without buffering the whole envelope in memory.
fetchAndApplyKbcPatch({required KbcLoaderFn loader, String? endpoint, String? apiKey, String? appVersion, String? engineVersion, String? distinctId, String? platform, String? currentLabel, bool persistToDisk = true, Duration timeout = const Duration(seconds: 30)}) Future<KbcFetchResult>
η v1: in-app fetch + apply for iOS Path C.
getActiveVersion() Future<String?>
Returns the active patch label (e.g. "v1.2.0-patch.3") or the baseline label if no patch is active.
getBannedKbcLabels() Future<Set<String>>
Returns the current set of banned patch labels — patches that auto-rolled-back and won't be re-applied. Dashboards / support flows can show these; clearBannedKbcLabels resets the set.
getCurrentLibappPath() Future<String?>
Absolute filesystem path of the currently active libapp.so. Mostly useful for debugging — production code shouldn't need this.
getStagedKbcPatchInfo() Future<KbcStagedPatchInfo?>
Describes the patch currently staged at the canonical persistence path — what tryApplyStagedKbcPatch would re-apply on the next cold boot. Returns null when no patch is staged. Does NOT touch the loader; safe to call from a dashboard / debug screen at any time. Reads metadata only — the KBC payload is not parsed.
legacyAndroidCheckForUpdate() Future<UpdateStatus>
Legacy Android-only libapp.so binary-diff check. Calls into the native plugin and stages a binary-diff patch on next boot. Most hosts should use the cross-platform checkForUpdate (no args, works on iOS + Android) instead — kept exposed only because the auto-startup hook still calls it on Android. Will become fully internal once the libapp.so path is sunset in favour of β.3 KBC.
legacyAndroidNotifyAppReady() Future<void>
Legacy Android-only "app ready" hook for the libapp.so path. Most hosts should use notifyAppReady (cross-platform) instead.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
notifyKbcPatchReady() Future<int>
Reset the rollback boot-counter — call this from the host's first-frame callback (or any "the app survived initial render" signal). Without this call, a bad patch will crash-loop the app until kKbcCrashThreshold quick-crash boots (each within kKbcCrashWindow of the previous), then auto-disable itself.
readCurrentPatch() Future<SankofaCurrentPatch?>
Returns metadata for the patch currently believed to be live on this device. The SDK reads the last_good/patch.skdp envelope — the patch that survived a notifyKbcPatchReady confirmation — and surfaces its label.
reportCrash() Future<void>
Tell the updater that a fatal error was caught — equivalent to a hard crash from the rollback perspective. Optional; the native crash bridge fires this automatically for uncaught exceptions.
shutdown() Future<void>
Tear down the platform plugin. Called by Sankofa.dispose(); hosts almost never need this directly.
toString() String
A string representation of this object.
inherited
tryApplyStagedKbcPatch({required KbcLoaderFn loader}) Future<KbcPatchResult?>
Look for a KBC patch that a previous session staged on disk and apply it now, before runApp. Returns the apply result, or null if no patch was staged (or the staged patch is invalid).

Operators

operator ==(Object other) bool
The equality operator.
inherited

Static Properties

instance SankofaDeploy?
no setter

Static Methods

initInternal({required String apiKey, required String endpoint, required SankofaDeployOptions options, String? appVersion, String? flavor, String distinctIdResolver()?, void onLifecycleEvent(String eventType, {String? label, String? releaseId})?}) Future<SankofaDeploy>
Internal hook used by Sankofa.init — DO NOT call directly. The per-product enableDeploy flag triggers this. Idempotent.

Constants

kbcRollbackThreshold → const int
Legacy boot-count threshold (pre-time-window). Kept as a public const for API stability — the new model uses kKbcCrashThreshold
kKbcAutoConfirmDelay → const Duration
kKbcCrashThreshold → const int
Threshold of consecutive quick-boot crashes that triggers rollback. Mirrors RN's CRASH_THRESHOLD.
kKbcCrashWindow → const Duration
A boot is considered a "crash" only if the previous boot didn't confirm healthy and was within this window of the current boot. Mirrors RN's CRASH_WINDOW_MS.