Skip to content

Repository files navigation

Ripstop

Ripstop Flutter SDK

CIlicense: MIT

Remote config for shipped apps. Update walls and maintenance mode built in, signed, verified on device.


Six months after you ship, a backend change breaks every install older than 3.3.0. You open the panel, set the oldest version you still support, and within seconds those installs show a wall telling them to update. That moment is the product.

Installation

Not yet on pub.dev. Until then, depend on the repository directly:

dependencies:
ripstop:
git: https://github.com/ripstop-dev/ripstop-flutter.git

or on a local checkout:

dependencies:
ripstop:
path: ../ripstop-flutter

Quick start

import'package:ripstop/ripstop.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final ripstop =awaitRipstop.init(apiKey:'rs_pub_your_key');
runApp(RipstopShell(gate: ripstop, child:constMyApp()));
}

That's the whole integration. RipstopShell shows your app until a decision says otherwise, then renders the right wall.

The version comes from the bundle, so there is no literal to forget to bump. Pass appVersion: when you need to override it (a staged rollout pretending to be an older build, or a test) and yours wins. If the platform will not say what it is running, the SDK has no opinion and your app runs.

Or drive it yourself

switch (await ripstop.check()) {
caseRsForceUpdate(:final title, :final body, :final storeUrl):// Blocked. Not dismissible.caseRsSoftUpdate(:final title, :final canSnooze):// A nudge. `ripstop.snooze()` records it and re-evaluates.caseRsMaintenance(:final message, :final endsAt):// You are down on purpose.caseRsNone():// Carry on.
}

The switch is exhaustive: if the protocol ever grows a decision, your app stops compiling instead of silently showing nobody anything.

Remote config

Values ride in the same signed payload as the rules, so reading one costs no extra request:

final enabled = ripstop.values['checkout_enabled'] asbool???true;

What it does when things break

This is the part worth reading, because a config service that can lock users out of their own app is worse than no config service.

SituationWhat happens
No networkThe last signed payload drives the decision
No network, no cacheRsNone, so your app runs unrestricted
Server returns 500Cache, then RsNone
Signature doesn't verifyTreated as a failure. A forged payload can never wall your app
Cache file edited on deviceRe-verified on read, so it grants nothing

The SDK fails open, always. Every payload is Ed25519-signed and verified on device against a pinned key, so a compromised CDN cannot show your users anything, because it does not have the signing key.

Everything else

minFetchIntervalHow long a payload is fresh enough to skip the network. Default 6 hours
timeoutFetch budget. Default 5 seconds, then cache
storageSwap SharedPreferencesStorage for your own, or InMemoryStorage
localeWhich language the wall copy resolves to; falls back to en per key
signingKeysOverride the pinned keys, for self-hosted deployments
onOpenUrlHow to open the store. Wire url_launcher here; the SDK doesn't depend on it

Example app

example/ is a full runnable app that boots against a signed local stub, so you can flip through every wall without an account. It is the same app we use for store-quality screenshots.

Conformance

All five Ripstop SDKs run the same 62 golden vectors from vectors.json: version ordering, evaluation order, snooze accounting, the fail-open state machine. flutter test runs them here. If this package and the TypeScript reference implementation ever disagree about a single comparison, CI goes red.

Full docs: ripstop.dev/docs/flutter

License

MIT

About

Ripstop SDK for Flutter. Required updates, update nudges, maintenance mode and remote config.

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages