smart_update_manager 0.1.0
smart_update_manager: ^0.1.0 copied to clipboard
A plug-and-play solution to detect app updates and enforce soft or force updates on Android, iOS, macOS, Windows, and Linux.
import 'package:flutter/material.dart';
import 'package:smart_update_manager/smart_update_manager.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Update Manager Example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const UpdateDemoPage(),
);
}
}
class UpdateDemoPage extends StatefulWidget {
const UpdateDemoPage({super.key});
@override
State<UpdateDemoPage> createState() => _UpdateDemoPageState();
}
class _UpdateDemoPageState extends State<UpdateDemoPage> {
bool _usePlatformSpecific = false;
// Global versions (for all platforms)
String _minRequiredGlobal = '1.0.0';
String _latestAvailableGlobal = '1.2.0';
// Platform-specific versions
String _minRequiredAndroid = '2.1.0';
String _latestAvailableAndroid = '3.0.1';
String _minRequiredIOS = '2.8.0';
String _latestAvailableIOS = '2.9.0';
String _minRequiredMacOS = '1.5.0';
String _latestAvailableMacOS = '1.8.0';
String _minRequiredWindows = '1.2.0';
String _latestAvailableWindows = '1.5.0';
String _minRequiredLinux = '1.0.0';
String _latestAvailableLinux = '1.3.0';
@override
void initState() {
super.initState();
// Example of checking on launch
WidgetsBinding.instance.addPostFrameCallback((_) {
_checkUpdate(silent: true);
});
}
Future<void> _checkUpdate({bool silent = false}) async {
UpdateConfig config;
if (_usePlatformSpecific) {
// Platform-specific version configuration
config = UpdateConfig(
// Android versions
minimumRequiredAndroidVersion: AppVersion.parse(_minRequiredAndroid),
latestAndroidVersion: AppVersion.parse(_latestAvailableAndroid),
androidId: 'com.example.app',
// iOS versions
minimumRequiredIOSVersion: AppVersion.parse(_minRequiredIOS),
latestIOSVersion: AppVersion.parse(_latestAvailableIOS),
iosId: '123456789',
// macOS versions
minimumRequiredMacOSVersion: AppVersion.parse(_minRequiredMacOS),
latestMacOSVersion: AppVersion.parse(_latestAvailableMacOS),
macAppStoreId: '987654321',
// Windows versions
minimumRequiredWindowsVersion: AppVersion.parse(_minRequiredWindows),
latestWindowsVersion: AppVersion.parse(_latestAvailableWindows),
windowsStoreId: '9WZDNCRFJ3QB',
// Linux versions
minimumRequiredLinuxVersion: AppVersion.parse(_minRequiredLinux),
latestLinuxVersion: AppVersion.parse(_latestAvailableLinux),
linuxUpdateUrl: 'https://example.com/linux-update',
);
} else {
// Global version configuration (same for all platforms)
config = UpdateConfig(
minimumRequiredVersion: AppVersion.parse(_minRequiredGlobal),
latestAvailableVersion: AppVersion.parse(_latestAvailableGlobal),
androidId: 'com.example.app',
iosId: '123456789',
macAppStoreId: '987654321',
windowsStoreId: '9WZDNCRFJ3QB',
linuxUpdateUrl: 'https://example.com/linux-update',
);
}
if (silent) {
// Automatic check on launch
await SmartUpdateManager.checkAndShowUpdate(
context,
config: config,
);
} else {
// Manual check triggered by button
final state = await SmartUpdateManager.checkUpdate(config);
if (!mounted) return;
if (state == UpdateState.none) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Your app is already up to date!')),
);
} else {
await SmartUpdateManager.checkAndShowUpdate(
context,
config: config,
softUpdateTitle: 'New Version Available',
softUpdateMessage:
'A new version is available. Would you like to update?',
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Update Manager Demo'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Icon(Icons.system_update, size: 80, color: Colors.deepPurple),
const SizedBox(height: 24),
Text(
'Test Update Scenarios',
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
const Text(
'Test global or platform-specific version configurations.',
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
// Toggle between global and platform-specific
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const Text(
'Configuration Mode:',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
SegmentedButton<bool>(
segments: const [
ButtonSegment(
value: false,
label: Text('Global'),
icon: Icon(Icons.public),
),
ButtonSegment(
value: true,
label: Text('Platform-Specific'),
icon: Icon(Icons.dashboard),
),
],
selected: {_usePlatformSpecific},
onSelectionChanged: (set) => setState(() => _usePlatformSpecific = set.first),
),
],
),
),
),
const SizedBox(height: 24),
if (!_usePlatformSpecific) ...[
// Global configuration UI
const Text(
'Global Configuration',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(height: 16),
_buildVersionControl(
title: 'Force Update Threshold (Min Required)',
value: _minRequiredGlobal,
onChanged: (v) => setState(() => _minRequiredGlobal = v),
options: ['0.9.0', '1.0.0', '1.5.0'],
),
const SizedBox(height: 24),
_buildVersionControl(
title: 'Soft Update Threshold (Latest)',
value: _latestAvailableGlobal,
onChanged: (v) => setState(() => _latestAvailableGlobal = v),
options: ['1.0.0', '1.2.0', '2.0.0'],
),
] else ...[
// Platform-specific configuration UI
const Text(
'Platform-Specific Configuration',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(height: 8),
const Text(
'Different versions for each platform',
style: TextStyle(color: Colors.grey),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
// Android
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.android, color: Colors.green),
SizedBox(width: 8),
Text('Android', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Min Required: $_minRequiredAndroid',
value: _minRequiredAndroid,
onChanged: (v) => setState(() => _minRequiredAndroid = v),
options: ['2.0.0', '2.1.0', '2.5.0'],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Latest: $_latestAvailableAndroid',
value: _latestAvailableAndroid,
onChanged: (v) => setState(() => _latestAvailableAndroid = v),
options: ['2.5.0', '3.0.1', '3.2.0'],
),
],
),
),
),
const SizedBox(height: 16),
// iOS
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.apple, color: Colors.grey),
SizedBox(width: 8),
Text('iOS', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Min Required: $_minRequiredIOS',
value: _minRequiredIOS,
onChanged: (v) => setState(() => _minRequiredIOS = v),
options: ['2.7.0', '2.8.0', '2.9.0'],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Latest: $_latestAvailableIOS',
value: _latestAvailableIOS,
onChanged: (v) => setState(() => _latestAvailableIOS = v),
options: ['2.8.0', '2.9.0', '3.0.0'],
),
],
),
),
),
const SizedBox(height: 16),
// macOS
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.computer, color: Colors.black),
SizedBox(width: 8),
Text('macOS', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Min Required: $_minRequiredMacOS',
value: _minRequiredMacOS,
onChanged: (v) => setState(() => _minRequiredMacOS = v),
options: ['1.4.0', '1.5.0', '1.6.0'],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Latest: $_latestAvailableMacOS',
value: _latestAvailableMacOS,
onChanged: (v) => setState(() => _latestAvailableMacOS = v),
options: ['1.7.0', '1.8.0', '2.0.0'],
),
],
),
),
),
const SizedBox(height: 16),
// Windows
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.window, color: Colors.blue),
SizedBox(width: 8),
Text('Windows', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Min Required: $_minRequiredWindows',
value: _minRequiredWindows,
onChanged: (v) => setState(() => _minRequiredWindows = v),
options: ['1.1.0', '1.2.0', '1.3.0'],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Latest: $_latestAvailableWindows',
value: _latestAvailableWindows,
onChanged: (v) => setState(() => _latestAvailableWindows = v),
options: ['1.4.0', '1.5.0', '1.6.0'],
),
],
),
),
),
const SizedBox(height: 16),
// Linux
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.keyboard, color: Colors.orange),
SizedBox(width: 8),
Text('Linux', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Min Required: $_minRequiredLinux',
value: _minRequiredLinux,
onChanged: (v) => setState(() => _minRequiredLinux = v),
options: ['0.9.0', '1.0.0', '1.1.0'],
),
const SizedBox(height: 12),
_buildVersionControl(
title: 'Latest: $_latestAvailableLinux',
value: _latestAvailableLinux,
onChanged: (v) => setState(() => _latestAvailableLinux = v),
options: ['1.2.0', '1.3.0', '1.4.0'],
),
],
),
),
),
],
const SizedBox(height: 48),
ElevatedButton.icon(
onPressed: () => _checkUpdate(),
icon: const Icon(Icons.refresh),
label: const Text('Simulate Update Check'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(16),
textStyle: const TextStyle(fontSize: 18),
),
),
const SizedBox(height: 16),
const Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
Text(
'Logic Explanation:',
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text('• Current < Min -> Force Update (Non-dismissible)'),
Text('• Current < Latest -> Soft Update (Optional)'),
Text('• Current >= Latest -> Up to date'),
],
),
),
),
],
),
),
);
}
Widget _buildVersionControl({
required String title,
required String value,
required ValueChanged<String> onChanged,
required List<String> options,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
SegmentedButton<String>(
segments: options
.map((o) => ButtonSegment(value: o, label: Text(o)))
.toList(),
selected: {value},
onSelectionChanged: (set) => onChanged(set.first),
),
],
);
}
}