shorebird_code_push 1.1.5 shorebird_code_push: ^1.1.5 copied to clipboard
Check for and download Shorebird code push updates from your app.
import 'package:flutter/material.dart';
import 'package:restart_app/restart_app.dart';
import 'package:shorebird_code_push/shorebird_code_push.dart';
// Create an instance of ShorebirdCodePush. Because this example only contains
// a single widget, we create it here, but you will likely only need to create
// a single instance of ShorebirdCodePush in your app.
final _shorebirdCodePush = ShorebirdCodePush();
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Shorebird Code Push Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.red),
useMaterial3: true,
),
home: const MyHomePage(title: 'Shorebird Code Push'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({required this.title, super.key});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _isShorebirdAvailable = _shorebirdCodePush.isShorebirdAvailable();
int? _currentPatchVersion;
bool _isCheckingForUpdate = false;
@override
void initState() {
super.initState();
// Request the current patch number.
_shorebirdCodePush.currentPatchNumber().then((currentPatchVersion) {
if (!mounted) return;
setState(() {
_currentPatchVersion = currentPatchVersion;
});
});
}
Future<void> _checkForUpdate() async {
setState(() {
_isCheckingForUpdate = true;
});
// Ask the Shorebird servers if there is a new patch available.
final isUpdateAvailable =
await _shorebirdCodePush.isNewPatchAvailableForDownload();
if (!mounted) return;
setState(() {
_isCheckingForUpdate = false;
});
if (isUpdateAvailable) {
_showUpdateAvailableBanner();
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('No update available'),
),
);
}
}
void _showDownloadingBanner() {
ScaffoldMessenger.of(context).showMaterialBanner(
const MaterialBanner(
content: Text('Downloading...'),
actions: [
SizedBox(
height: 14,
width: 14,
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
],
),
);
}
void _showUpdateAvailableBanner() {
ScaffoldMessenger.of(context).showMaterialBanner(
MaterialBanner(
content: const Text('Update available'),
actions: [
TextButton(
onPressed: () async {
ScaffoldMessenger.of(context).hideCurrentMaterialBanner();
await _downloadUpdate();
if (!mounted) return;
ScaffoldMessenger.of(context).hideCurrentMaterialBanner();
},
child: const Text('Download'),
),
],
),
);
}
void _showRestartBanner() {
ScaffoldMessenger.of(context).showMaterialBanner(
const MaterialBanner(
content: Text('A new patch is ready!'),
actions: [
TextButton(
// Restart the app for the new patch to take effect.
onPressed: Restart.restartApp,
child: Text('Restart app'),
),
],
),
);
}
void _showErrorBanner() {
ScaffoldMessenger.of(context).showMaterialBanner(
MaterialBanner(
content: const Text('An error occurred while downloading the update.'),
actions: [
TextButton(
onPressed: () {
ScaffoldMessenger.of(context).hideCurrentMaterialBanner();
},
child: const Text('Dismiss'),
),
],
),
);
}
// Note: this is only run if an update is reported as available.
// [isNewPatchReadyToInstall] returning false does not always indicate an
// error with the download.
Future<void> _downloadUpdate() async {
_showDownloadingBanner();
await Future.wait([
_shorebirdCodePush.downloadUpdateIfAvailable(),
// Add an artificial delay so the banner has enough time to animate in.
Future<void>.delayed(const Duration(milliseconds: 250)),
]);
final isUpdateReadyToInstall =
await _shorebirdCodePush.isNewPatchReadyToInstall();
if (!mounted) return;
ScaffoldMessenger.of(context).hideCurrentMaterialBanner();
if (isUpdateReadyToInstall) {
_showRestartBanner();
} else {
_showErrorBanner();
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final heading = _currentPatchVersion != null
? '$_currentPatchVersion'
: 'No patch installed';
return Scaffold(
appBar: AppBar(
backgroundColor: theme.colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Current patch version:'),
Text(
heading,
style: theme.textTheme.headlineMedium,
),
const SizedBox(height: 20),
if (!_isShorebirdAvailable)
Text(
'Shorebird Engine not available.',
style: theme.textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.error,
),
),
if (_isShorebirdAvailable)
ElevatedButton(
onPressed: _isCheckingForUpdate ? null : _checkForUpdate,
child: _isCheckingForUpdate
? const _LoadingIndicator()
: const Text('Check for update'),
),
],
),
),
);
}
}
class _LoadingIndicator extends StatelessWidget {
const _LoadingIndicator();
@override
Widget build(BuildContext context) {
return const SizedBox(
height: 14,
width: 14,
child: CircularProgressIndicator(strokeWidth: 2),
);
}
}