smart_update_manager 0.0.1
smart_update_manager: ^0.0.1 copied to clipboard
A plug-and-play solution to detect app updates and enforce soft or force updates on Android and iOS.
example/lib/main.dart
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> {
// Simulator state: these would normally come from your API/Remote Config
String _minRequired = '1.0.0';
String _latestAvailable = '1.2.0';
@override
void initState() {
super.initState();
// Example of checking on launch
WidgetsBinding.instance.addPostFrameCallback((_) {
_checkUpdate(silent: true);
});
}
Future<void> _checkUpdate({bool silent = false}) async {
final config = UpdateConfig(
minimumRequiredVersion: AppVersion.parse(_minRequired),
latestAvailableVersion: AppVersion.parse(_latestAvailable),
androidId: 'com.example.app', // Placeholder
iosId: '123456789', // Placeholder
);
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 ($_latestAvailable) 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(
'Change the thresholds below to simulate different update states. '
'The current app version is usually fetched automatically.',
textAlign: TextAlign.center,
),
const SizedBox(height: 32),
_buildVersionControl(
title: 'Force Update Threshold (Min Required)',
value: _minRequired,
onChanged: (v) => setState(() => _minRequired = v),
options: ['0.9.0', '1.0.0', '1.5.0'],
),
const SizedBox(height: 24),
_buildVersionControl(
title: 'Soft Update Threshold (Latest)',
value: _latestAvailable,
onChanged: (v) => setState(() => _latestAvailable = v),
options: ['1.0.0', '1.2.0', '2.0.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),
),
],
);
}
}