patch_app 0.1.3
patch_app: ^0.1.3 copied to clipboard
A lightweight helper to patch your Flutter app at runtime using shorebird code push and terminate restart
Patch App #
A lightweight helper to patch your Flutter app at runtime using shorebird_code_push and terminate_restart.
It automatically checks for Shorebird updates, applies patches, and restarts your app safely when accepted.
Features #
- Check and apply Shorebird patches dynamically
- Show a customizable restart confirmation dialog
- Restart the app safely with one line of code
- Built-in
minIntervalto limit check frequency and prevent redundant checks - Optional error handling via callback or
PatchResult - Only report
PatchResult.restartRequiredwhen the restart dialog is accepted (or cannot be shown), while rejected prompts returnPatchResult.cancelled
Setup #
iOS #
Add the following to your Info.plist to enable restarts with terminate_restart:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>
Android #
No configuration required.
Usage #
class App extends StatefulWidget {
const App({super.key});
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
final patchApp = PatchApp(
confirmDialog: (context) => patchAppConfirmationDialog(context),
onError: (error, stack) => debugPrint('Update failed: $error'),
);
@override
void initState() {
super.initState();
patchApp.register(context); // Auto-checks on start & resume
}
@override
void dispose() {
patchApp.unregister(); // Stops lifecycle listener
super.dispose();
}
@override
Widget build(BuildContext context) {
return FilledButton(
onPressed: () => patchApp.checkAndUpdate(context), // Check and update manually
child: const Text('Check and Update'),
);
}
}
register() and unregister() #
-
register(context)Automatically checks for updates when the app starts or resumes. Should be called once ininitState(). -
unregister()Cleans up the lifecycle listener created byregister(). Always call this indispose().
Patch Results #
enum PatchResult {
noUpdate, // No updater or no patch available
upToDate, // Already on the latest version
cancelled, // Restart prompt dismissed or skipped
restartRequired, // Patch applied; restart needed
failed, // Error during the update
}
cancelled is returned when the confirmation dialog is dismissed, while restartRequired is only emitted after the user accepts a restart (or if the dialog cannot be shown because the context was unmounted), signaling that a restart is still needed.
Tips #
-
Always provide an
onErrorcallback in production to capture unexpected failures.- If
onErroris provided, the method returnsPatchResult.failedon error. - If omitted, the error is rethrown.
- If