A easy alert immediate or card is displayed when a more moderen app model is out there within the Google Play Retailer or Apple App Retailer. Most customers reap the benefits of this auto-upgrade characteristic to keep away from having to replace every app individually on their telephones.
Nevertheless, there are occasions when an app must be up to date extra rapidly than common, and the consumer have to be notified straight slightly than counting on a retailer alert. This direct notification can also be useful for reaching people who find themselves not subscribed to auto updates.
This situation is particularly vital when you’re following a launch early, launch typically philosophy; incessantly including new content material and options to your app, and releasing new variations at a reasonably excessive cadence.
Having a number of variations of your app on the market could cause model fragmentation points, which is a gigantic downside for app improvement. Luckily, there’s an ideal Flutter plugin that helps you alert customers and immediate them to replace their app to the most recent model: upgrader
.
On this tutorial, we’ll focus on how upgrader
works and we’ll exhibit totally different methods that can be utilized to deal with app model upgrades.
Soar forward:
Stipulations
To comply with together with this information, it’s best to have the next:
- Fundamental data of Flutter, stateful widgets, and bundle versioning
- Working data of pushing cellular apps to the Google Play Retailer and Apple App Retailer
Getting began
The tutorial portion of this text will use the Days With out Incidents (DWI) app to exhibit ideas. DWI is an easy incident counter app that helps a number of counters, kinds, and a easy consumer interface.
To comply with alongside, obtain the open supply code obtainable through GitHub and guarantee you’re utilizing Flutter v3.0+.
Open the challenge along with your most well-liked IDE, and keep in mind to get the dependencies with flutter pub get
.
Right here’s a fast rundown of some vital recordsdata try to be conscious of:
lib/primary.dart
: Normal primary file required for Flutter taskslib/core
: Core widgets and utilities shared between two or extra optionslib/options
: Makes use of characteristic grouping to summary totally different elements of the UIpackages
: Accommodates the information and area layers
To raised perceive the necessities, you can even try this GitHub pull request. It has all of the modifications required to deal with app updates and model restrictions by yourself.
Understanding how upgrader
works
As talked about beforehand, model fragmentation will happen when there are too many variations of an app out there. Every model might have totally different options, gadget help, display help, and even API variations. Your infrastructure and providers might want to help all these variations, leading to dearer enterprise operations.
So, what’s the answer?
There are three issues you are able to do to cut back the impression of model fragmentation:
- Have a manageable record of variations that you simply help
-
Implement a minimal model you’re supporting
-
Information the consumer by way of updates if their app shouldn’t be working the most recent model
That is the place upgrader
turns out to be useful; it helps you set in place all these mechanisms in your app with out an excessive amount of overhead.
upgrader
is a Flutter plugin that helps handle the consumer’s put in model of your app. It lets you examine if the consumer has the most recent model put in and if they don’t, it guides the consumer to put in it through an app retailer with a dialog or widget.
The plugin can even implement a minimal app model and gives inbuilt help RSS feeds with the Appcast customary utilized by Sparkle (we’ll focus on this additional later on this article).
Sufficient chit-chat; it’s time you dive into some code!
Displaying alerts if the app is outdated
One of the frequent use circumstances for upgrader
is to show a dialog field when the presently put in app is outdated in comparison with the shop itemizing.
To do that out, open the lib/options/time_counter/pages/counter_page.dart
file and alter the CountersPage
construct
to the next:
@override Widget construct(BuildContext context) { return Scaffold( appBar: const DWIAppBar(), physique: UpgradeAlert( little one: const SafeArea( little one: _Body(), ), ), ); }
UpgradeAlert
can wrap a widget, permitting you to put it as a wrapper of the physique
property and never have to fret about guide checks to the model.
N.B., keep in mind so as to add this import on the high of the file: import 'bundle:upgrader/upgrader.dart';
In the event you construct and run the app proper now, you’ll see the next:
The plugin gives restricted model customization for the dialog field. The dialogStyle
property in Upgrader
has two totally different choices: UpgradeDialogStyle.cupertino
and the default UpgradeDialogStyle.materials
.
Change the construct
once more and alter the model to be cupertino
, like so:
@override Widget construct(BuildContext context) { return Scaffold( appBar: const DWIAppBar(), physique: UpgradeAlert( upgrader: Upgrader(dialogStyle: UpgradeDialogStyle.cupertino), little one: const SafeArea( little one: _Body(), ), ), ); }
Now, construct and run the app. It ought to look one thing like this:
Subsequent, go forward and go away the construct
because it was at first:
@override Widget construct(BuildContext context) { return const Scaffold( appBar: DWIAppBar(), physique: SafeArea( little one: _Body(), ), ); }
One other frequent situation is having an indicator within the UI to show that the put in model of the app shouldn’t be updated. Once more, the plugin has a very good implementation for this through UpgradeCard
.
Let’s add UpgradeCard
and see the way it appears to be like. Open the lib/options/time_counter/widgets/counter_list.dart
file and add the next code above Expanded
in order that it’s displayed on the high of the display:
UpgradeCard(),
In the event you construct and run the app, that is the way it ought to look:
As you may see, UpgradeCard
shows a card styled with Materials Design, it makes use of the identical content material as UpgradeAlert
however exhibits it inline as a substitute of with a dialog field. For the reason that card doesn’t look nice, on this case, go forward and delete the code you simply added (delete line 81). We’ll contemplate another choices as a substitute.
Now, generally these two inbuilt behaviors (UpgradeAlert
and UpgradeCard
) are usually not sufficient when it comes to consumer expertise. For instance, you could wish to present an IconButton
when there’s an replace obtainable for the app.
Let’s give this instance a attempt.
You’ll have to create a brand new widget that may work like UpgradeAlert
and UpgradeCard
. Actually, when you take a better have a look at the library’s code, you’ll discover that each lengthen UpgradeBase
which can make issues a bit simpler.
Begin by making a lib/core/widgets/upgrade_widget.dart
file and add the next code:
import 'dart:developer'; import 'bundle:flutter/materials.dart'; import 'bundle:upgrader/upgrader.dart'; /// Defines a builder operate that lets you create a customized widget /// that's displayed in a similar way as [UpgradeCard] typedef UpgradeWidgetBuilder = Widget Perform( BuildContext context, Upgrader upgrader, ); /// A widget to show by checking upgrader data obtainable. class UpgradeWidget extends UpgradeBase { /// Creates a brand new [UpgradeWidget]. UpgradeWidget({ Key? key, Upgrader? upgrader, required this.builder, }) : tremendous(upgrader ?? Upgrader.sharedInstance as Upgrader, key: key); /// Defines how the widget will probably be constructed. Permits the implementation of customized /// widgets. last UpgradeWidgetBuilder builder; /// Describes the a part of the consumer interface represented by this widget. @override Widget construct(BuildContext context, UpgradeBaseState state) { if (upgrader.debugLogging) { log('UpgradeWidget: construct UpgradeWidget'); } return FutureBuilder( future: state.initialized, builder: (BuildContext context, AsyncSnapshot<bool> processed) { if (processed.connectionState == ConnectionState.executed && processed.information != null && processed.information!) { if (upgrader.shouldDisplayUpgrade()) { if (upgrader.debugLogging) { log('UpgradeWidget: will name builder'); } return builder.name(context, upgrader); } } return const SizedBox.shrink(); }, ); } }
Right here’s a fast overview of the code we simply added:
Within the above code, UpgradeWidget
is a wrapper widget that implements the identical primary conduct that UpgradeCard
and UpgradeAlert
share. It extends UpgradeBase
and does primary checks when the custom-made construct
is executed. It should help you wrap any widget and show details about updating the app if wanted.
Extra nice articles from LogRocket:
UpgradeWidget
receives an elective Upgrader
implementation but in addition has the default implementation, so each the UpgradeCard
and UpgradeAlert
work. Making the customized widget use the identical rules lets you maintain interoperability between your customized widget and the library’s API.
UpgradeWidgetBuilder
is an alias for the builder
operate used to render the content material widget. It has Upgrader
as a parameter as a result of that may present entry to the knowledge required for constructing a customized widget. We’ll focus on this in additional element somewhat later on this article.
Now that you simply’ve arrange a reusable UpgradeWidget
, open the lib/core/widgets/dwi_appbar.dart
file and duplicate this code on the backside of the file:
class _UpdateButton extends StatelessWidget { const _UpdateButton({ Key? key, }) : tremendous(key: key); @override Widget construct(BuildContext context) { return UpgradeWidget( upgrader: Upgrader( //! This can be a little bit of a hack to permit the alert dialog to be proven //! repeatedly. durationUntilAlertAgain: const Length(milliseconds: 500), showReleaseNotes: false, showIgnore: false, ), builder: (context, upgrader) => CircleAvatar( little one: IconButton( onPressed: () { upgrader.checkVersion(context: context); }, icon: const Icon(Icons.add), ), ), ); } }
_UpdateButton
is a handy, non-public widget that enables us to set the conduct for our customized UpgradeWidget
. On this case, the thought is to showcase the upgrader
alert dialog when the IconButton
is tapped. This may be achieved by calling checkVersion
and passing the context as a parameter; the plugin will take over when the operate known as and a brand new UpgradeAlert
needs to be displayed.
For higher readability, the showReleaseNotes
and showIgnore
flags are set to false
since each components take up an excessive amount of house within the UI. Additionally, DWI app customers are accustomed to easy consumer expertise, so you may skip exhibiting these for now.
One final caveat is that at any time when the consumer faucets Later in UpgradeAlert
, the library shops a timestamp to keep away from exhibiting the dialog field too typically or at undesired occasions. It should solely reshow the dialog field as soon as a while has handed (the default is three days).
You’ll have to bypass this characteristic for the DWI app and present the dialog field each time the consumer faucets on the replace IconButton
. To perform this, we’ll override the default durationUntilAlertAgain
with a Length
of 500ms. This manner, the library will mark the dialog field as prepared because it’s closed by the consumer.
N.B., it is a considerably hacky answer, as a result of it wouldn’t be wanted if the library trusted us to show the alert dialog at any level we desired. Sadly, on the time of writing, upgrader
doesn’t provide inbuilt help for this type of conduct.
Now, let’s add _UpdateButton(),
to actions
simply above _AddCounterButton
. Additionally, ensure you add the corresponding imports for the library on the high of the file:
import 'bundle:dwi/core/widgets/widgets.dart'; import 'bundle:upgrader/upgrader.dart';
After you construct and run, it’s best to see the next:
Implementing a minimal model within the app
One other nice characteristic of upgrader
is its means to implement a minimal app model just by including predefined textual content to the outline within the app shops or by defining a minimal app model inside Upgrader
, like so:
Upgrader( minAppVersion: '3.0.0', ),
In the event you’re wanting to make use of app retailer descriptions, maintain the next codecs in thoughts:
- Format for the Google Play Retailer (Android apps):
[Minimum supported app version: 1.2.3]
- Format for the Apple App Retailer (iOS apps):
[:mav: 1.2.3]
Utilizing the above textual content format will outline the minimal app model as 1.2.3.
Which means that earlier variations of this app will probably be compelled to replace to the most recent model obtainable.
Controlling your individual model listings
An vital restrict of upgrader
is that its default conduct leverages the present Apple App Retailer and Google Play Retailer listings of your app, which means:
- If Google or Apple decides to cease displaying the app model or limits the allowed description codecs then
upgrader
‘s default conduct will cease working -
In case your app shouldn’t be distributed through public shops,
upgrader
won’t work as meant out of the field -
You aren’t in charge of the record of variations that you simply help and there’s no historical past about them
To resolve this, upgrader
gives help for working with Appcast, which relies on the Sparkle framework by Andy Matuschak. Sparkle is a extensively used customary that lists all of the variations of an app with an XML format. The Appcast feed describes every model of an app and offers upgrader
with the newest model.
Right here’s an instance from the Sparkle documentation exhibiting how an Appcast file might look:
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/components/1.1/" model="2.0"> <channel> <title>Sparkle Take a look at App Changelog</title> <hyperlink>http://sparkle-project.org/recordsdata/sparkletestcast.xml</hyperlink> <description>Most up-to-date modifications with hyperlinks to updates.</description> <language>en</language> <merchandise> <title>Model 2.0</title> <hyperlink>https://sparkle-project.org</hyperlink> <sparkle:model>2.0</sparkle:model> <description> <![CDATA[ <ul> <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</li> <li>Suspendisse sed felis ac ante ultrices rhoncus. Etiam quis elit vel nibh placerat facilisis in id leo.</li> <li>Vestibulum nec tortor odio, nec malesuada libero. Cras vel convallis nunc.</li> <li>Suspendisse tristique massa eget velit consequat tincidunt. Praesent sodales hendrerit pretium.</li> </ul> ]]> </description> <pubDate>Sat, 26 Jul 2014 15:20:11 +0000</pubDate> <enclosure url="https://sparkle-project.org/recordsdata/Sparklepercent20Testpercent20App.zip" size="107758" kind="utility/octet-stream" sparkle:edSignature="7cLALFUHSwvEJWSkV8aMreoBe4fhRa4FncC5NoThKxwThL6FDR7hTiPJh1fo2uagnPogisnQsgFgq6mGkt2RBw=="/> </merchandise> </channel> </rss>
This file needs to be hosted on a server accessible to anybody who makes use of the app. It additionally may be auto generated through the launch course of, or you may manually replace it after a launch is out there within the app shops.
Utilizing upgrader
with an Appcast is comparatively easy as effectively. Right here’s an instance from the library’s documentation:
import 'bundle:flutter/materials.dart'; import 'bundle:upgrader/upgrader.dart'; void primary() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({ Key key, }) : tremendous(key: key); @override Widget construct(BuildContext context) { last appcastURL = 'https://uncooked.githubusercontent.com/larryaasen/upgrader/grasp/check/testappcast.xml'; last appcastConfig = AppcastConfiguration(url: appcastURL, supportedOS: ['android', 'ios']); return MaterialApp( title: 'Upgrader Instance', residence: Scaffold( appBar: AppBar( title: Textual content('Upgrader Instance'), ), physique: UpgradeAlert( Upgrader(appcastConfig: appcastConfig), little one: Middle(little one: Textual content('Checking...')), )), ); } }
Nice work! Now you realize precisely the best way to maintain customers working the most recent model of your app and also you’re additionally conscious of the principle “gotchas” that you simply would possibly discover alongside the best way.
What’s subsequent?
On this article, we reviewed totally different methods for dealing with Flutter app updates utilizing upgrader
. You possibly can view an entire record of all of the modifications wanted in this PR of Days With out Incidents.
I hope you loved this tutorial. In the event you discovered it helpful, please contemplate sharing it with others. I’ll be comfortable to deal with any questions left within the feedback part beneath.