Skip to main content

Environment Management and Device Conditions (OtaEnvironment)

In tk_ota_push, environment management covers two key facets:

  1. Runtime Physical Condition Inspection (lib/src/environment/ota_environment.dart): network connectivity type (OtaConnectivityType), battery level (OtaDeviceConditions), and deferred background scheduling (OtaBackgroundScheduler).
  2. Application Environment Resolution (dev, staging, prod, uat) and Runtime Track Switching (enableQaMode() / disableQaMode() and FlutterProject.deduceEnvironmentName).

1. Physical Conditions: Network & Battery (ota_environment.dart)​

When a patch is flagged for silent download (forceUpdate: false), the SDK inspects physical device conditions via OtaEnvironmentMonitor.checkConditions() before starting the download.

Connectivity Types (OtaConnectivityType)​

enum OtaConnectivityType {
wifi,
ethernet,
mobile,
none,
}

Device Physical Conditions (OtaDeviceConditions)​

The OtaDeviceConditions class provides:

  • connectivity (OtaConnectivityType): active connection type.
  • batteryPercentage (int, default 100): remaining battery percentage.
  • isCharging (bool, default false): whether the device is connected to a power source.
  • isUnmeteredWifi (bool): computed getter returning true if connectivity == OtaConnectivityType.wifi || connectivity == OtaConnectivityType.ethernet.
  • isOnline (bool): computed getter returning true if connectivity != OtaConnectivityType.none.

Silent Mode Decision Rules (TkOtaPush.syncWithRemoteConfig)​

In lib/src/tk_ota_push_sdk.dart, a silent update (forceUpdate: false) executes immediately if and only if all three criteria are satisfied:

  1. conditions.isOnline == true
  2. wifiOk: !requireWifiForSilentUpdate || conditions.isUnmeteredWifi
  3. batteryOk: conditions.isCharging || conditions.batteryPercentage >= minBatteryPercentageForSilentUpdate

If any of these conditions fails (e.g., user is on 3G/4G cellular data while requireWifiForSilentUpdate: true, or battery is at 15% without a charger while minBatteryPercentageForSilentUpdate: 20):

  • No immediate OTA network call is performed (networkCallPerformed: false).
  • The SDK enqueues _backgroundScheduler.scheduleSilentUpdateTask(...) using unique key tk_ota_silent_patch_${remoteConfig.targetReleaseVersion}_${remoteConfig.latestPatchNumber}.
  • syncWithRemoteConfig returns OtaUpdateExecutionMode.deferredToBackgroundTask.

Connecting connectivity_plus and battery_plus to OtaEnvironmentMonitor​

The SDK provides DefaultOtaEnvironmentMonitor (which defaults to wifi and 100% battery so no native plugins are forced). To connect your real production hardware monitors:

import 'package:tk_ota_push/tk_ota_push.dart';

class ProductionEnvironmentMonitor implements OtaEnvironmentMonitor {

Future<OtaDeviceConditions> checkConditions() async {
// Example integration with native device plugins
return const OtaDeviceConditions(
connectivity: OtaConnectivityType.wifi,
batteryPercentage: 75,
isCharging: false,
);
}
}

Connecting workmanager to OtaBackgroundScheduler​

Similarly, replace InMemoryOtaBackgroundScheduler with an implementation delegating to workmanager:

import 'package:tk_ota_push/tk_ota_push.dart';

class WorkmanagerBackgroundScheduler implements OtaBackgroundScheduler {

Future<void> scheduleSilentUpdateTask({
required String taskUniqueName,
required bool requireWifi,
required bool requireBatteryNotLow,
}) async {
// Register deferred background worker with Android WorkManager / iOS BGTaskScheduler
}
}

2. Application Environments (dev, staging, prod) and URL Resolution​

Resolving base_url per Environment​

The OTA server URL (base_url) is determined according to the following precedence order:

  1. At CLI build and publish time:
    • --server <url> flag
    • base_url key in shorebird.yaml
    • OTA_SERVER_URL environment variable
    • Fallback default: http://localhost:8080
  2. At mobile runtime in the Rust engine:
    • Reads the embedded base_url key from flutter_assets/shorebird.yaml.
    • When a phone queries POST {base_url}/api/v1/patches/check, the TkushPatch Server backend (ShorebirdUpdaterController.resolveClientReachableUrl) inspects X-Forwarded-Host, Host, and X-Forwarded-Proto headers to rewrite download URLs pointing to localhost or 127.0.0.1 into the actual client-reachable endpoint.

Automatic Environment Name Deduction (deduceEnvironmentName)​

During multi-environment builds (dev, staging, prod, uat), FlutterProject.deduceEnvironmentName (lib/src/cli/project.dart) automatically infers the active target by evaluating:

  1. Explicit --env <name> flag (e.g., --env staging).
  2. --flavor <name> flag (e.g., --flavor dev).
  3. --dart-define arguments matching ENV=..., ENVIRONMENT=..., or FLAVOR=....
  4. Target entrypoint file --target matching main_<env>.dart or main-<env>.dart (e.g., -t lib/main_dev.dart infers dev).
  5. File name in --dart-define-from-file (e.g., env/dev.json or .env.staging infers dev or staging).

3. Dynamic Runtime Track Switching (stable / staging)​

Within a single compiled release, the TkOtaPush instance listens by default to UpdateTrack.stable. You can dynamically switch a device to UpdateTrack.staging (e.g., from a hidden QA menu) without recompiling the app:

final ota = TkOtaPush.instance;

// Switch to UpdateTrack.staging
ota.enableQaMode();
print(ota.track.name); // "staging"

// Check and download the latest patch on the staging channel
final updated = await ota.checkAndUpdate();

// Revert to the public UpdateTrack.stable channel
ota.disableQaMode();
print(ota.track.name); // "stable"