Skip to main content

ctrlapp 0.1.3 copy "ctrlapp: ^0.1.3" to clipboard
ctrlapp: ^0.1.3 copied to clipboard

Remote kill-switch, feature flags, forced update, forms and inbox for Flutter, plus diagnostics, device-integrity checks, push permission and hosted login.

ctrlapp — remote control for your Flutter app #

Change how your live app behaves from the CtrlApp dashboard — without publishing a new version.

Turn off a broken feature, show a maintenance screen, force an update, change a button label, or run an experiment, and your users' apps pick it up automatically, usually within a minute.

What you can do #

You want to... You use
Switch off the whole app, or one broken feature, instantly the kill-switch (isBlocked, boolFlag)
Show a "please update" screen to old versions forced update (blockChanges)
Turn features on for 5% of users, then 100% feature flags (boolFlag)
Change numbers, texts, images or links remotely remote config (configValue, text, image)
Test two versions of something (A/B) experiments (treatment)
Collect feedback or sign-ups forms (submitForm) and an in-app inbox
Stop screenshots and screen recording of sensitive screens screen capture protection (a switch in the dashboard)

It keeps working offline: the last known decision is cached on the device, so a killed feature stays killed even if the user opens the app without internet.

Get started in 3 steps #

1. Create an app at ctrlapp.dev and copy its API key (it starts with ck_sdk_).

2. Add the package

flutter pub add ctrlapp

3. Start it when your app launches

import 'package:ctrlapp/ctrlapp.dart';
import 'package:flutter/material.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await CtrlApp.init(apiKey: 'ck_sdk_YOUR_KEY');
  runApp(const MyApp());
}

That's it. From anywhere in your app you can now use CtrlApp.instance.

Everyday use #

final ctrl = CtrlApp.instance;

// Kill-switch: should the app (or a feature) be blocked right now?
if (ctrl.isBlocked) {
  showMaintenanceScreen(ctrl.blockReason());
}

// React when you flip the switch in the dashboard while the app is open.
ctrl.blockChanges.listen((block) {
  if (block.action == 'force_update') openStore(block.forceUpdateUrl);
});

// Feature flag
if (ctrl.boolFlag('new_checkout')) {
  showNewCheckout();
}

// Remote config, text and images (with safe defaults)
final maxItems = ctrl.configValue<int>('cart.max_items', defaultValue: 10);
final title = ctrl.text('home.title', fallback: 'Welcome');
final banner = ctrl.image('home.banner'); // null if not set

// Experiment: which version should this user see?
final variant = await ctrl.treatment('checkout_test', defaultValue: 'control');

// Track what people do
ctrl.track('purchase', props: {'plan': 'pro'});

Every call returns the default you pass in if the control doesn't exist, so your app never breaks because a key is missing.

Screen capture protection #

Turn it on per app in the dashboard (it is off by default). The package then applies it automatically:

  • Android: blocks screenshots and screen recording of your app (FLAG_SECURE). It never clears a flag your own code set.
  • iOS: hides your app's content in the app switcher and covers it while the screen is being recorded or mirrored. Apple provides no way to block a plain screenshot, so iOS cannot prevent those.

More in this package #

Everything is one package. Next to CtrlApp you can use these on their own:

Need Use
Crash and error reports (opt-in, sensitive data removed) CtrlAppDiagnostics, CtrlAppHandlers
Detect rooted / jailbroken devices and emulators CtrlAppIntegrity.detect()
Device model and OS version CtrlAppDeviceInfo.detect()
Ask for notification permission CtrlAppPush.requestPermission()
Re-check the kill-switch while the app stays open CtrlAppBlockWatch
Sign-in with Google and other providers package:ctrlapp/auth.dart
Test your app without a network MockCtrlAppTransport
final diagnostics = CtrlAppDiagnostics();
CtrlAppHandlers(diagnostics).install(); // collects Flutter and platform errors

final signals = await CtrlAppIntegrity.detect();
final permission = await CtrlAppPush.requestPermission();

The sign-in classes have short, generic names (Loading, Offline, ...), so they live in their own import: import 'package:ctrlapp/auth.dart';

Requirements #

  • Flutter 3.10 or newer, Dart 3
  • Android 5.0 (API 21) or newer, iOS 12 or newer

Help #

MIT license.

1
likes
0
points
448
downloads

Documentation

Documentation

Publisher

verified publisherctrlapp.dev

Weekly Downloads

Remote kill-switch, feature flags, forced update, forms and inbox for Flutter, plus diagnostics, device-integrity checks, push permission and hosted login.

Homepage

Topics

#feature-flags #kill-switch #remote-config #forced-update #screen-capture

License

unknown (license)

Dependencies

device_info_plus, flutter, http, package_info_plus, shared_preferences

More

Packages that depend on ctrlapp

Packages that implement ctrlapp