quickpatch_cli 1.6.128
quickpatch_cli: ^1.6.128 copied to clipboard
QuickPatch — self-hosted OTA code-push for Flutter apps.
1.6.128 #
- Android code push on stable Flutter 3.44.0. Stable Flutter ships a vanilla Android engine with no on-device updater, so patches couldn't apply. The build now maps the vanilla engine to the QuickPatch Android engine (which carries the updater) for the duration of the build, so
libfluttersupports OTA and the snapshot stays consistent. Device-proven: an OTA code patch applies over-the-air, and a patch signed with an untrusted key is rejected (no brick). QUICKPATCH_PUBLIC_KEYSenvironment variable for signing-key rotation (the previousSHOREBIRD_PUBLIC_KEYSname is still accepted as a fallback, so existing setups keep working).- Fix: iOS
--interpreterapps that usequickpatch_code_pushcrashed at module load (Unable to find function ... in dart:isolate / dart:ffi). The generated dynamic-interface (which marks the AOT framework/SDK surface the interpreted app module may call) omitteddart:isolateanddart:ffi, soIsolate.runand the FFI symbols (nullptr/Pointer) thatquickpatch_code_pushuses were tree-shaken out of the base AOT image and the interpreter FATAL'd at module load. The release build now addsdart:isolateanddart:ffito the interface'scallable+can-be-used-as-typesections, so they are retained and resolvable. Rebuild the release with this version. - Fix: iOS engine overlay could silently revert to the stock Flutter engine (white screen).
ensureQuickPatchIosEnginetreated its.quickpatch-engine-revstamp as sufficient proof the overlay was intact. But a partial overlay (interrupted mid-copy) or aflutter precache/ artifact re-materialization can leave the stamp in place whilegen_snapshot_arm64reverts to the stock Flutter build. An app AOT-compiled by a stock gen_snapshot produces a snapshot whose version hash the QuickPatch runtime engine refuses to load — the app boots to a white screen.ensurenow also verifies the on-diskgen_snapshot_arm64actually embeds the engine revision, and re-installs the engine if it doesn't. This most commonly affected a second Flutter version's cache dir (e.g. stable 3.44.0), whose engine had been partially overlaid.
1.6.127 #
- Support for Flutter 3.44.0 stable:
quickpatch release/patchnow work on apps built with stable Flutter 3.44.0 (revision559ffa3f75…), in addition to the 3.44.0-rc3 pin. Stable 3.44.0 pins the identical Dart SDK revision as the rc3 fork, so it reuses the same on-device engine revision (snapshot hash unchanged) — no new engine download is required. Target it by revision:quickpatch release ios --interpreter --flutter-version 559ffa3f75e7402d65a8def9c28389a9b2e6fe42. (getRevisionForVersionalso gained an upstream-tag fallback so a plain--flutter-version 3.44.0resolves to stable on a vanilla-Flutter clone; on the legacy Shorebird-fork clone the fork'sflutter_release/3.44.0branch still points at the rc3 pin, so use the revision there.)
1.6.126 #
- Reliable large-artifact uploads (direct-to-R2): release & patch artifacts now upload directly to object storage via a presigned URL instead of being proxied through the API server. Large release artifacts (the iOS interpreter base is ~40MB+) previously failed with a connection reset when the API server ran behind a memory/edge-limited host (e.g. Railway); they now upload reliably regardless of artifact size or host. Requires the matching server update that returns presigned upload URLs.
1.6.125 #
- Publish-time smoke-test gate (Android): before an Android patch is uploaded,
quickpatch patchnow builds the patched app as an APK, installs and launches it on a connected device/emulator, and verifies it reaches its first frame. If the patched app crashes or hangs on startup, the patch is not published (the command exits non-zero) — so a startup-crashing patch never reaches your users. Detection uses the OS first-frame signal (ActivityManager: Displayed) for success, and logcat crash markers / a render timeout for failure. Runs automatically when a device is connected; skipped (with a warning for thestabletrack) when none is. Control it with--no-smoke-testand--smoke-test-timeout=<seconds>(default 45). Device-proven: a startup-crash patch is blocked; a healthy patch passes and publishes.
1.6.124 #
- iOS
--interpreterpatches now support ANY code change, including new classes/screens (device-proven: a patch that adds a whole new screen opens on a physical iPhone via OTA, no reinstall). The patch is now built as a full app module (the whole changed app behind adyn-module:entry-pointwrapper, like the release's base module) and the on-device bootstrapper loads + runs it vialoadModuleFromByteson the next launch (whole-program replacement) instead of the previous function-merge loader, which could only swap existing functions and crashed when a patch added a new top-level class. - Self-heal against a bad staged patch: a boot-failure counter (bumped before applying a staged patch, reset once the first frame renders) drops a staged patch that crashes repeatedly at load, falling back to the base — so a bad patch can no longer permanently brick the app.
- Note: the bootstrapper is baked into the release, so rebuild your release with this version (
quickpatch release ios --interpreter) before publishing full-module patches to it.
1.6.123 #
- iOS
--interpreterrelease & patch now build end-to-end (device-proven: an arbitrary Dart code change applied over-the-air on a physical iPhone with no reinstall). Completes thedynamic_modulesresolution work from 1.6.122 by fixing three follow-on issues:- The generated
package_config.jsonis written to the build dir, so its relativerootUris are now rebased to absolute — previously the app's ownpackage:<app>/...imports resolved against the wrong base. - The interpreter release now declares
dynamic_modulesas apath:dependency so theflutter build ipastep (which compiles the bootstrapper via the project's own package_config) can resolve it. - The interpreter patch now runs a
flutter pub getwith the vended Flutter before compiling, sopackage:flutterresolves to the engine-matched framework instead of a different system Flutter that fails to compile against the vended platform.
- The generated
1.6.122 #
- Fix iOS
--interpreterpatch/release builds:quickpatch patch ios --interpreter(and the interpreter release path) failed atgen_kernelwithCouldn't resolve the package 'dynamic_modules'. The bootstrapper importspackage:dynamic_modules, whose functions wrapdart:_internaldynamic-module natives that are already present in the engine's platform dill — but the wrapper package itself wasn't resolvable. The CLI now generates that wrapper and an augmentedpackage_config.jsonautomatically before compiling, so no engine change or extra setup is needed. Your project's.dart_tool/package_config.jsonis left untouched.
1.6.121 #
quickpatch init --channel: choose the update channel a build listens to (defaults tostable). Ship a beta build with--channel=beta, publish to it withquickpatch patch --track=beta, and your store build (onstable) stays untouched. The flag writeschannel:intoquickpatch.yaml; the on-device updater already honors it. Stable builds keep a clean config (no channel line written for the default).
1.6.120 #
- Branded CLI experience:
quickpatch initnow opens with a welcome banner — an emerald ANSI "QUICKPATCH" wordmark, tagline, and a short wizard intro — andquickpatch --helpshows the same logo header. Color and art are automatically stripped when output isn't a terminal (pipes, CI, files) and are never emitted in--jsonmode, so scripting output stays clean.
1.6.119 #
- Default endpoints now use the production custom domains: the default hosted server is
https://api.quickpatch.dev(was the Railway origin URL) and the login/console hint points tohttps://quickpatch.dev. These are only defaults —QUICKPATCH_HOSTED_URLand thebase_urlinquickpatch.yamlstill override them, so self-hosting and existing projects are unaffected.
1.6.118 #
- Multi-version foundation: the CLI now resolves the engine revision for a Flutter version from the server's
/api/v1/engine-versionsregistry, falling back to the built-in map if the server is unreachable. This means a newly-built Flutter version becomes usable without shipping a new CLI - the engine-build pipeline just publishes the version to the registry. Behavior is unchanged for the currently-shipped version (it resolves identically), and offline/no-server builds keep working via the fallback.
1.6.117 #
- Signing-key rotation (end to end): a build can now trust more than one patch-signing public key (a primary key plus rotation keys), so a patch signed by a newly-rotated key is accepted alongside one signed by the prior key — letting the signing key be rotated without invalidating installs. The additional keys, supplied as a comma-separated list, are embedded into
quickpatch.yamlfor the Android/data-patch path and baked into the iOS interpreter bootstrapper's trusted-key set; in both cases a patch verifies if its signature matches any trusted key (a valid-but-wrong key is skipped, never accepted). Device-verified on a physical Android device and a physical iPhone: a patch signed with a rotated key is downloaded, verified against the multi-key set, and applied.
1.6.116 #
- Patch signing fix (security): ensure the patch public key is embedded into the app before every Android and iOS build, so on-device patch signature verification is actually enforced. Previously the key could be omitted for QuickPatch projects, leaving the on-device updater unable to verify patches (effectively unsigned). Device-verified on a physical Android device: a patch signed with an untrusted key is now rejected at boot ("Patch signature is invalid"), while one signed with the trusted key applies normally. Applied automatically and idempotently, so existing installs are fixed on the next build.
- Forward additional trusted public keys (for signing-key rotation) to the build environment, so a rotated key can be trusted before the old one is retired.
1.6.115 #
- Self-host without an env var: the storage/mirror base URL now falls back to
quickpatch.yaml'sbase_url(after theQUICKPATCH_HOSTED_URLenv override, before the hosted default), so abase_urlin your config is enough to point both the build-time engine downloads and the on-device updater at your own server — no manualQUICKPATCH_HOSTED_URLexport. With neither set, behaviour is unchanged.
1.6.114 #
- Fix
--versionreporting:version.dartwas not bumped in the previous two releases, soquickpatch --version(and thex-cli-versionrequest header) reported a stale version. Now synced to the package version.
1.6.113 #
- Cleanup: removed the legacy config-file fallback (projects use
quickpatch.yamlexclusively) and tidied source comments. No functional change for existing projects.
1.6.112 #
- Fix onboarding crash:
quickpatch --versionandquickpatch doctorno longer fail with a cache-corrupted error on a fresh install before the pinned Flutter/engine is downloaded. The engine revision now falls back to the install-root pin, and both commands degrade to a readable "not installed (downloaded on first release/patch)" instead of throwing.
1.6.111 #
- iOS arbitrary code push (
--interpreter): release/patch iOS apps with arbitrary Dart changes (new widgets, screens, control-flow) over the air via an on-device Dart interpreter. - Staged OTA: interpreter patches are signature-verified, staged to disk on download, and applied at the next launch's first frame — no flash of the old UI, no live reassemble.
quickpatch upgrade: now performs a real git fast-forward + rebuild instead of printing an upgrade hint.- Fix: declare
asn1libas a direct dependency (used for patch-signature key parsing).
1.6.109 #
flutter versions list: Show newest versions first. Remove.reversedsince server already returns newest-first order.
1.6.108 #
- Fix
flutter versions list: Always fetch from production server using a fixed URL — previous version used the project-levelhostedUriwhich caused silent fallback to local git branches.
1.6.107 #
flutter versions list: Now fetches supported versions directly from your QuickPatch server instead of reading all engine fork branches. Only versions mirrored in R2 are shown — the ones you actually support. Falls back to local git branch listing if server is unreachable.
1.6.106 #
- Fix: When
QUICKPATCH_HOSTED_URLis not set, the CLI now shows a clear error with the exact export command (platform-aware:exporton macOS/Linux,$env:on Windows) instead of a crypticSocketException.
1.6.105 #
- Login: Replaced browser OAuth flow with API key authentication. Run
quickpatch loginand paste your key from the dashboard. - Upgrade:
quickpatch upgradenow shows the correctdart pub global activate quickpatch_cliinstruction instead of crashing with a git error. - Published to pub.dev — install and upgrade via
dart pub global activate quickpatch_cli.