dart_patch_updater
🚀 In-app updates for Flutter — without the App Store
Update your Flutter app's business logic instantly from your own server or GitHub Releases.
No Play Store review. No App Store wait. Ship fixes in minutes.
✨ Features
- 🔄 Hot updates — Push business logic changes without app store reviews
- 🔒 Secure — SHA-256 checksum + RSA signature verification
- ⏪ Auto-rollback — Automatically reverts on failure
- 📦 GitHub Releases support — Use GitHub as your update server
- 📱 Cross-platform — Android, iOS, macOS, Windows, Linux
- 🌐 Offline-safe — Won't brick your app if update fails
- 🎯 Version targeting — Control which app versions receive updates
📋 What Can Be Updated?
| ✅ Can Update | ❌ Cannot Update |
|---|---|
| Feature flags | Compiled Dart code |
| Pricing rules | Native code (Java/Swift) |
| Validation rules | Flutter framework |
| Workflow definitions | App permissions |
| Business logic configs | App icons/splash |
| API endpoints | Native plugins |
Note: Flutter uses AOT compilation, so you cannot download arbitrary
.dartfiles. This package updates data-driven business logic via a JSON rule engine.
🚀 Quick Start
Installation
dependencies:
dart_patch_updater: ^0.1.0
Basic Usage
import 'package:dart_patch_updater/dart_patch_updater.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final updateManager = UpdateManager(
config: UpdateConfig(
serverUrl: 'https://raw.githubusercontent.com/you/repo/main/update.json',
appId: 'com.example.myapp',
appVersion: '2.1.0',
publicKey: '-----BEGIN PUBLIC KEY-----\n...',
useStaticJson: true, // For GitHub Releases
),
);
await updateManager.initialize();
runApp(MyApp(updateManager: updateManager));
}
Check & Apply Updates
// Check for updates
final result = await updateManager.checkForUpdates();
if (result.updateAvailable) {
// Download and apply
final updateResult = await updateManager.downloadAndApply(
onProgress: (progress) => print('${progress.percentage}%'),
);
if (updateResult.success) {
print('Updated to ${updateResult.newVersion}!');
}
}
Use Updated Business Logic
// Feature flags
final isDarkMode = updateManager.getModuleData('feature_flags')?['dark_mode'] ?? false;
// Pricing rules
final discount = updateManager.getModuleData('pricing_rules')?['discount'] ?? 0.1;
🔧 Configuration Options
| Parameter | Type | Default | Description |
|---|---|---|---|
serverUrl |
String |
required | Update metadata URL |
appId |
String |
required | Your app's unique ID |
appVersion |
String |
'1.0.0' |
Current app version |
publicKey |
String |
required | RSA public key for verification |
useStaticJson |
bool |
false |
true for GitHub, false for API |
checkOnLaunch |
bool |
true |
Auto-check on app start |
autoDownload |
bool |
false |
Auto-download when available |
autoApply |
bool |
false |
Auto-apply without confirmation |
maxBackupVersions |
int |
3 |
Backup count for rollback |
validateSignatures |
bool |
true |
Verify RSA signatures |
validateChecksums |
bool |
true |
Verify SHA-256 checksums |
📁 Server Setup
Option 1: GitHub Releases (Recommended)
1. Create update.json in your repo:
{
"update_available": true,
"patch": {
"version": "1.1.0",
"min_app_version": "2.0.0",
"max_app_version": "3.0.0",
"download_url": "https://github.com/you/repo/releases/download/v1.1.0/patch.zip",
"checksum": "sha256:a1b2c3...",
"signature": "base64_signature...",
"mandatory": false,
"released_at": "2025-01-01T00:00:00Z"
}
}
2. Create your patch bundle:
patch.zip
├── manifest.json
└── modules/
├── feature_flags.json
└── pricing_rules.json
3. Upload to GitHub Releases
Option 2: Custom API Server
UpdateConfig(
serverUrl: 'https://api.yourserver.com',
checkEndpoint: '/api/updates/check',
useStaticJson: false, // Uses POST request
)
📦 Patch Bundle Structure
manifest.json
{
"version": "1.1.0",
"created_at": "2025-01-01T00:00:00Z",
"requires_restart": false,
"modules": [
{ "name": "feature_flags", "path": "modules/feature_flags.json", "type": "json" },
{ "name": "pricing_rules", "path": "modules/pricing_rules.json", "type": "json" }
]
}
modules/feature_flags.json
{
"dark_mode": true,
"premium_features": true,
"new_checkout_flow": false
}
modules/pricing_rules.json
{
"default_discount": 0.15,
"rules": [
{
"condition": { "gte": ["$order.total", 100] },
"action": { "type": "return", "value": 0.25 }
}
]
}
🔒 Security
Generate an RSA keypair for signing patches:
# Generate private key (keep secret!)
openssl genrsa -out private_key.pem 2048
# Extract public key (embed in your app)
openssl rsa -in private_key.pem -pubout -out public_key.pem
# Sign your patch
openssl dgst -sha256 -sign private_key.pem -out patch.sig patch.zip
base64 patch.sig > signature.txt
⏪ Rollback
// Rollback to previous version
final result = await updateManager.rollback();
// Get available versions
final versions = await updateManager.getAvailableRollbackVersions();
// Rollback to specific version
await updateManager.rollbackToVersion('1.0.0');
📱 Platform Support
| Platform | Supported |
|---|---|
| Android | ✅ |
| iOS | ✅ |
| macOS | ✅ |
| Windows | ✅ |
| Linux | ✅ |
| Web | ❌ |
📄 License
MIT License — see LICENSE for details.
Made with ❤️ for the Flutter community
Libraries
- dart_patch_updater
- Flutter in-app update package for fetching and applying Dart code patches from a custom server without app store dependencies.