A comprehensive Flutter package for automatically updating your app using GitHub releases, without relying on Google Play Store.
- β Automatic version checking from GitHub releases
- β Download progress tracking with visual feedback
- β Automatic installation after download
- β Customizable UI and callbacks
- β Permission handling for storage and installation
- β Modular design for easy integration
- β Error handling and retry mechanisms
- β Rate limiting to prevent spam checks
- β Release notes support in update dialogs
dependencies:
autoupdate: ^0.0.1Add these permissions to your android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />import 'package:flutter/material.dart';
import 'package:autoupdate/autoupdate.dart';
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with AutoUpdaterMixin {
@override
void initState() {
super.initState();
final config = AutoUpdaterConfig(
githubRepo: 'your-username/your-repo',
apkFileName: 'app-release.apk',
);
initAutoUpdater(config);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('My App')),
body: Center(
child: UpdateCheckButton(
autoUpdater: autoUpdater!,
child: Text('Check for Updates'),
),
),
);
}
}import 'package:flutter/material.dart';
import 'package:autoupdate/autoupdate.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AutoUpdaterWidget(
config: AutoUpdaterConfig(
githubRepo: 'your-username/your-repo',
apkFileName: 'app-release.apk',
checkOnStartup: true,
),
child: MaterialApp(
title: 'My App',
home: MyHomePage(),
),
);
}
}final config = AutoUpdaterConfig(
// Required
githubRepo: 'your-username/your-repo',
apkFileName: 'app-release.apk',
// Optional - UI customization
showReleaseNotes: true,
allowSkip: true,
dialogTitle: 'Update Available',
dialogContent: 'A new version is available!',
updateButtonText: 'Update Now',
skipButtonText: 'Later',
// Optional - Behavior
checkOnStartup: true,
minCheckInterval: Duration(hours: 1),
showProgressDialog: true,
progressDialogTitle: 'Downloading Update',
autoInstall: true,
// Optional - Theme
dialogTheme: ThemeData.light(),
);final callbacks = AutoUpdaterCallbacks(
onUpdateAvailable: (context, versionInfo, currentVersion) async {
// Custom update dialog
return await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
title: Text('π New Update!'),
content: Text('Version ${versionInfo.version} is available'),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx, false),
child: Text('Later'),
),
ElevatedButton(
onPressed: () => Navigator.pop(ctx, true),
child: Text('Update'),
),
],
),
) ?? false;
},
onDownloadProgress: (percent, received, total) {
print('Download: $percent%');
},
onDownloadCompleted: (filePath) {
print('Download completed: $filePath');
},
onInstallCompleted: () {
print('Installation completed!');
},
onVersionCheckFailed: (error) {
print('Version check failed: $error');
},
);- Go to your GitHub repository
- Click on "Releases" β "Create a new release"
- Set a tag (e.g.,
v1.0.1) - Add release notes
- Upload your APK file
- Publish the release
Ensure your APK filename matches the apkFileName in your config:
AutoUpdaterConfig(
apkFileName: 'app-release.apk', // Must match your uploaded file
// ...
)Use semantic versioning for your releases:
v1.0.0v1.0.1v2.0.0
// Using mixin
await checkForUpdates();
// Using standalone instance
await autoUpdater.checkForUpdates(context);// Check if update is in progress
if (autoUpdater.isChecking) {
print('Update check in progress');
}
if (autoUpdater.isDownloading) {
print('Download in progress');
}
// Get last check time
final lastCheck = autoUpdater.lastCheckTime;final callbacks = AutoUpdaterCallbacks(
onDownloadProgress: (percent, received, total) {
// Update your custom progress UI
setState(() {
downloadProgress = percent;
});
},
);The package includes comprehensive error handling:
- Network errors: Automatic retry with exponential backoff
- Permission errors: User-friendly permission request dialogs
- Download errors: Detailed error messages and cleanup
- Installation errors: Fallback options and error reporting
-
"No APK found in release assets"
- Ensure your APK file is uploaded to the GitHub release
- Check that the filename matches your config
-
"Storage permission denied"
- Add required permissions to AndroidManifest.xml
- Request permissions at runtime
-
"Install permission denied"
- Enable "Install unknown apps" in Android settings
- Request MANAGE_EXTERNAL_STORAGE permission
-
"Version check failed"
- Verify your GitHub repository URL
- Check internet connectivity
- Ensure the repository is public or you have proper access
Enable debug logging:
// Add this to see detailed logs
import 'dart:developer' as developer;
// In your callbacks
onVersionCheckFailed: (error) {
developer.log('Version check failed: $error');
},| Property | Type | Default | Description |
|---|---|---|---|
githubRepo |
String | Required | GitHub repository (owner/repo) |
apkFileName |
String | Required | APK filename to download |
showReleaseNotes |
bool | true | Show release notes in dialog |
allowSkip |
bool | true | Allow users to skip updates |
checkOnStartup |
bool | true | Check for updates on app start |
minCheckInterval |
Duration | 1 hour | Minimum time between checks |
showProgressDialog |
bool | true | Show download progress dialog |
autoInstall |
bool | true | Auto-install after download |
| Callback | Parameters | Description |
|---|---|---|
onUpdateAvailable |
context, versionInfo, currentVersion | Custom update dialog |
onDownloadProgress |
percent, received, total | Download progress updates |
onDownloadStarted |
url | Download started |
onDownloadCompleted |
filePath | Download completed |
onDownloadFailed |
error | Download failed |
onInstallStarted |
filePath | Installation started |
onInstallCompleted |
- | Installation completed |
onInstallFailed |
error | Installation failed |
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
If you encounter any issues or have questions:
- Check the troubleshooting section
- Search existing issues
- Create a new issue with detailed information
See CHANGELOG.md for a list of changes and version history.