Skip to main content

3-Step Remote Config Gatekeeper

In a standard naive OTA setup (auto_update: true), every cold start of the mobile application initiates a POST /api/v1/patches/check HTTP request toward the OTA server. Across an active fleet of millions of devices, this produces millions of redundant daily requests when no patch has actually been released, consuming backend bandwidth and draining users' cellular data plans.

The RemoteConfigGatekeeper (lib/src/gatekeeper/remote_config_gatekeeper.dart) solves this inefficiency by evaluating 3 cumulative conditions locally in memory against a lightweight JSON payload (delivered via your standard startup config channel: Firebase Remote Config, launch API endpoint, etc.).

Architecture and Decision Flow​

Gatekeeper Evaluation Sequence
  1. Startup Health Check: Validates previous launch state and processes active revocations.
  2. Security Compliance: Evaluates local device security and runtime policies.
  3. Update Query: Checks in with the TkushPatch server with environment parameters.
  4. Download & Activation: Downloads and seals the patch if all conditions are satisfied.

The 3 Cumulative Conditions​

The RemoteConfigGatekeeper.evaluate(...) method assesses the following rules in strict order:

  1. Condition 1 — Release Version Match (targetReleaseVersion):

    • Compares installedReleaseVersion.trim() with remoteConfig.targetReleaseVersion.trim().
    • If either string is empty or if installed != target, the Gatekeeper immediately returns GatekeeperVerdict.skippedVersionMismatch (shouldCallOtaServer: false).
    • Purpose: an end-user still running version 1.0.0+2 (or newly upgraded to 1.0.0+4) never queries the server for a hotfix compiled specifically for 1.0.0+3.
  2. Condition 2 — Availability Kill-Switch (patchAvailable):

    • Asserts that remoteConfig.patchAvailable == true.
    • If false, returns GatekeeperVerdict.skippedNoPatchAvailable (shouldCallOtaServer: false).
    • Purpose: enables operators to immediately silence all OTA polling across the fleet with a single toggle in Remote Config without republishing the mobile app.
  3. Condition 3 — Strict Patch Monotonicity (latestPatchNumber):

    • Reads the patch number currently running in the Rust engine (currentPatchNumber ?? 0) and compares it against remoteConfig.latestPatchNumber.
    • If currentPatch >= latestPatch, returns GatekeeperVerdict.skippedAlreadyUpToDate (shouldCallOtaServer: false).
    • If currentPatch < latestPatch, all 3 conditions are fulfilled: returns GatekeeperVerdict.allowed (shouldCallOtaServer: true).

The OtaRemoteConfig Model​

The OtaRemoteConfig class (lib/src/models/ota_remote_config.dart) supports both snake_case and camelCase keys when instantiated via OtaRemoteConfig.fromJson(Map<String, dynamic> json):

Dart PropertyJSON Keys Accepted by fromJsonTypeDefaultRole
targetReleaseVersiontarget_release_version, targetReleaseVersionString''Target application release version (x.y.z+build).
patchAvailablepatch_available, patchAvailableboolfalseEnables or closes patch checks for this release version.
latestPatchNumberlatest_patch_number, latestPatchNumberint0Latest published patch number (int, num, or numeric String).
forceUpdateforce_update, forceUpdate, force_critical_updateboolfalsefalse = silent background download; true = blocking critical update modal.
releaseNotesrelease_notes, releaseNotesString?nullOptional descriptive message passed to onCriticalUpdateRequired.

Remote Config JSON Payloads Examples​

Scenario A: No Patch Published for Current Release (0 Network Calls)​

{
"target_release_version": "1.0.0+3",
"patch_available": false,
"latest_patch_number": 0,
"force_update": false
}

Scenario B: Silent Background Update Available (Patch #2)​

{
"target_release_version": "1.0.0+3",
"patch_available": true,
"latest_patch_number": 2,
"force_update": false,
"release_notes": "Performance optimizations for transaction history loading."
}

Scenario C: Critical Forced Update with Blocking Modal​

{
"target_release_version": "1.0.0+3",
"patch_available": true,
"latest_patch_number": 3,
"force_update": true,
"release_notes": "Mandatory security update required to complete operations."
}

Verdicts Matrix (GatekeeperVerdict) and Execution Modes (OtaUpdateExecutionMode)​

Device StateOtaRemoteConfig PayloadGatekeeperVerdictOtaUpdateExecutionModenetworkCallPerformedrestartRequired
Invalid APK certificate or Root detected(Any)null (halted earlier)blockedBySecurityShieldfalsefalse
Version 1.0.0+2, Patch nulltarget: "1.0.0+3", available: true, latest: 1skippedVersionMismatchblockedByGatekeeperfalsefalse
Version 1.0.0+3, Patch nulltarget: "1.0.0+3", available: false, latest: 1skippedNoPatchAvailableblockedByGatekeeperfalsefalse
Version 1.0.0+3, Patch #2target: "1.0.0+3", available: true, latest: 2skippedAlreadyUpToDateblockedByGatekeeperfalsefalse
Version 1.0.0+3, Patch #1, on 4G (requireWifi: true)target: "1.0.0+3", available: true, latest: 2, force: falsealloweddeferredToBackgroundTaskfalsefalse
Version 1.0.0+3, Patch #1, Wi-Fi & Battery OKtarget: "1.0.0+3", available: true, latest: 2, force: falseallowedsilentBackgroundUpdatetruefalse
Version 1.0.0+3, Patch #1, on 4Gtarget: "1.0.0+3", available: true, latest: 2, force: trueallowedcriticalForcedUpdatetruetrue (if downloaded)
enableGatekeeper: falseforce: false (Wi-Fi/Battery OK)bypassedGatekeeperDisabledsilentBackgroundUpdatetruefalse
Critical Mode Overrides Network Constraints

When forceUpdate: true, the SDK bypasses requireWifiForSilentUpdate and minBatteryPercentageForSilentUpdate so that high-priority security patches are downloaded without waiting for Wi-Fi or battery thresholds.