Giter Site home page Giter Site logo

larryaasen / upgrader Goto Github PK

View Code? Open in Web Editor NEW
516.0 10.0 253.0 2.59 MB

A Flutter package for prompting users to upgrade when there is a newer version of the app in the store.

License: MIT License

Ruby 0.90% Swift 0.53% Objective-C 0.01% Dart 83.45% HTML 1.26% CMake 6.01% C++ 7.39% C 0.46%
flutter dart widget upgrade

upgrader's Introduction

Upgrader

Build Status codecov pub package GitHub Stars Buy me a coffee Twitter

A Flutter package for prompting users to upgrade when there is a newer version of the app in the store.

Overview

When a newer app version is available in the app store, a simple alert prompt or card is displayed.

With today's modern app stores, there is little need to persuade users to upgrade their apps because most are already using the auto upgrade feature. However, there may be times when an app needs to be updated more quickly than usual, and nagging a user to upgrade will entice the upgrade sooner. Also, with Flutter supporting more than just Android and iOS platforms, it will become more likely that users on other app stores need to be nagged about upgrading.

Platform Support

Platform Automatically Supported? Appcast Supported?
ANDROID ✅ Yes ✅ Yes
IOS ✅ Yes ✅ Yes
LINUX ❌ No ✅ Yes
MACOS ❌ No ✅ Yes
WEB ❌ No ✅ Yes
WINDOWS ❌ No ✅ Yes

Widgets

The widgets come in two flavors: alert or card. The UpgradeAlert widget is used to display the popup alert prompt, and the UpgradeCard widget is used to display the inline material design card.

There are three buttons displayed to the user: IGNORE, LATER, and UPDATE NOW.

Tapping IGNORE prevents the alert from being displayed again for that version.

Tapping the LATER button just closes the alert allowing the alert to be displayed sometime in the future.

Tapping the UPDATE NOW button takes the user to the App Store (iOS) or Google Play Store (Android) where the user is expected to initiate the update process.

Alert Example

Just wrap your home widget in the UpgradeAlert widget, and it will handle the rest.

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Upgrader Example',
      home: UpgradeAlert(
          child: Scaffold(
        appBar: AppBar(title: Text('Upgrader Example')),
        body: Center(child: Text('Checking...')),
      )),
    );
  }
}

Screenshot of alert

image

Cupertino alert example

You can also display a Cupertino style dialog by using the dialogStyle parameter.

  body: UpgradeAlert(
    dialogStyle: UpgradeDialogStyle.cupertino,
    child: Center(child: Text('Checking...')),
  )

Screenshot of Cupertino alert

image

Card Example

Just return an UpgradeCard widget in your build method and a material design card will be displayed when an update is detected. The widget will have width and height of 0.0 when no update is detected.

return Container(
        margin: EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 0.0),
        child: UpgradeCard());

Screenshot of card

image

Localization

The text displayed in the upgrader package is localized in many languages, and supports customization.

Release Notes

The release notes are displayed by default when a new version is available. On Android the release notes are taken from the the WHAT'S NEW section on Google Play when available, otherwise the main app description is used. On iOS the release notes are taken from the App Store What's New section. For appcast), the release notes are taken from the description field.

Customization

The alert can be customized by changing the DialogTheme on the MaterialApp, or by overriding methods in the UpgradeAlert class. See these examples for more details:

The card can be customized by changing the CardTheme on the MaterialApp, or by overriding methods in the UpgradeCard class. See these examples for more details:

Here are the custom parameters for UpgradeAlert:

  • barrierDismissible: used to indicate whether tapping on the barrier will dismiss the dialog, which defaults to false
  • cupertinoButtonTextStyle: the text style for the cupertino dialog buttons, which defaults to null
  • dialogStyle: the upgrade dialog style, either material or cupertino, defaults to material, used only by UpgradeAlert, works on Android and iOS.
  • onIgnore: called when the ignore button is tapped, defaults to null
  • onLater: called when the later button is tapped, defaults to null
  • onUpdate: called when the update button is tapped, defaults to null
  • shouldPopScope: called to determine if the dialog blocks the current route from being popped, which defaults to null
  • showIgnore: hide or show Ignore button, which defaults to true
  • showLater: hide or show Later button, which defaults to true
  • showReleaseNotes: hide or show release notes, which defaults to true

Here are the custom parameters for UpgradeCard:

  • margin: The empty space that surrounds the card, defaults to null
  • maxLines: An optional maximum number of lines for the text to span, wrapping if necessary, defaults to null
  • onIgnore: called when the ignore button is tapped, defaults to null
  • onLater: called when the later button is tapped, defaults to null
  • onUpdate: called when the update button is tapped, defaults to null
  • overflow: How visual overflow should be handled, defaults to null
  • showIgnore: hide or show Ignore button, which defaults to true
  • showLater: hide or show Later button, which defaults to true
  • showReleaseNotes: hide or show release notes, which defaults to true

The Upgrader class can be customized by setting parameters in the constructor, and passing it

  • client: an HTTP Client that can be replaced for mock testing, defaults to http.Client().
  • clientHeaders: Provide the HTTP headers used by client, which defaults to null
  • countryCode: the country code that will override the system locale, which defaults to null
  • debugDisplayAlways: always force the upgrade to be available, defaults to false
  • debugDisplayOnce: display the upgrade at least once, defaults to false
  • debugLogging: display logging statements, which defaults to false
  • durationUntilAlertAgain: duration until alerting user again, which defaults to 3 days
  • languageCode: the language code that will override the system locale, which defaults to null
  • messages: optional localized messages used for display in upgrader
  • minAppVersion: the minimum app version supported by this app. Earlier versions of this app will be forced to update to the current version. It should be a valid version string like this: 2.0.13. Overrides any minimum app version from UpgraderStore. Defaults to null.
  • storeController: a controller that provides the store details for each platform, defaults to UpgraderStoreController().
  • upgraderDevice: an abstraction of the device_info details which is used for the OS version, defaults to UpgraderDevice().
  • upgraderOS: information on which OS this code is running on, defaults to UpgraderOS().
  • willDisplayUpgrade: called when upgrader determines that an upgrade may or may not be displayed, defaults to null

The UpgraderStoreController class is a controller that provides the store details for each platform.

  • onAndroid: defaults to UpgraderPlayStore() that extends UpgraderStore.
  • onFuchsia: defaults to UpgraderAppStore() that extends UpgraderStore.
  • oniOS: defaults to null.
  • onLinux: defaults to null.
  • onMacOS: defaults to null.
  • onWeb: defaults to null.
  • onWindows: defaults to null.

To change the UpgraderStore for a platform, replace the platform with a different store. Here is an example of using an Appcast on iOS.

final upgrader = Upgrader(
  storeController: UpgraderStoreController(
    onAndroid: () => UpgraderPlayStore(),
    oniOS: () => UpgraderAppcastStore(appcastURL: appcastURL),
  ),
);

You can even subclass UpgraderStore or an existing store class like UpgraderPlayStore to provide your own customization.

Minimum App Version

The upgrader package can enforce a minimum app version simply by adding a version number to the description field in the app stores.

For the Android Play Store, use this format:

[Minimum supported app version: 1.2.3]

For the iOS App Store, use this format:

[:mav: 1.2.3]

Using that text says that the minimum app version is 1.2.3 and that earlier versions of this app will be forced to update to the current version. The Ignore and Later buttons will automatically be hidden.

image

After the app containing this text has been submitted for review, approved, and released on the app store, the version number will be visible to the upgrader package. When the minimum app version is updated in the future, all previously installed apps with this package will recognize and honor that value.

This overrides any value supplied in the minAppVersion parameter.

Android

Add this text to the bottom of the full description field in the Google Play Console under the main store listing.

iOS

Add this text to the bottom of the description field in App Store Connect in the description field.

Go Router

When using GoRouter (package go_router) with upgrader, you may need to provide a navigatorKey to the UpgradeAlert widget so that the correct route context is used. Below is part of the code you will need for this. Also, checkout the example/lib/main-gorouter.dart example for a more complete example.

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'Upgrader GoRouter Example',
      routerConfig: routerConfig,
      builder: (context, child) {
        return UpgradeAlert(
          navigatorKey: routerConfig.routerDelegate.navigatorKey,
          child: child ?? Text('child'),
        );
      },
    );
  }

Android Back Button

When using the UpgradeAlert widget, the Android back button will not dismiss the alert dialog by default. To allow the back button to dismiss the dialog, use shouldPopScope and return true like this:

UpgradeAlert(shouldPopScope: () => true);

Country Code

On iOS, when your app is not in the US App Store, which is the default, you must use the countryCode parameter mentioned above. The upgrader package does not know which country app store to use because it is not provided by iOS. It assumes the app is in the US App Store.

On Android, the upgrader package uses the system locale to determine the country code.

Android Language Code

Android description and release notes language default to en.

Limitations

These widgets work on both Android and iOS. When running on Android the Google Play Store will provide the latest app version. When running on iOS the App Store will provide the latest app version. In all cases, the widget will display the prompt at the appropriate times.

On Android, the version number is often not available from the Google Play Store, such as with the Google Maps app. In this case, the version is listed as Varies with device. That is not a valid version for upgrader and cannot be used. The upgrader widget will not be displayed in this case.

There is an appcast that can be used to remotely configure the latest app version. See appcast below for more details.

Appcast

The upgrader package supports Appcast as an UpgraderStore.

An appcast is an RSS feed with one channel that has a collection of items that each describe one app version. The appcast will describe each app version and will provide the latest app version to upgrader that indicates when an upgrade should be recommended.

Appcast is based on the Sparkle framework by Andy Matuschak. You can read the Sparkle documentation here: https://sparkle-project.org/documentation/publishing/.

The appcast must be hosted on a server that can be reached by everyone from the app. The appcast XML file can be autogenerated during the release process, or just manually updated after a release is available on the app store.

The class UpgraderAppcastStore, in this Flutter package, is used by upgrader to download app details from an appcast.

Appcast Example

This is an Appcast example for Android.

static const appcastURL =
    'https://raw.githubusercontent.com/larryaasen/upgrader/master/test/testappcast.xml';
final upgrader = Upgrader(
  storeController: UpgraderStoreController(
    onAndroid: () => UpgraderAppcastStore(appcastURL: appcastURL),
  ),
);

@override
Widget build(BuildContext context) {
  return MaterialApp(
    title: 'Upgrader Example',
    home: Scaffold(
        appBar: AppBar(title: Text('Upgrader Appcast Example')),
        body: UpgradeAlert(
          upgrader: upgrader,
          child: Center(child: Text('Checking...')),
        )),
  );
}

Appcast Sample File

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
    <channel>
        <title>Debt Now App - Appcast</title>
        <item>
            <title>Version 1.15.0</title>
            <description>Minor updates and improvements.</description>
            <pubDate>Sun, 30 Dec 2018 12:00:00 +0000</pubDate>
            <enclosure url="https://play.google.com/store/apps/details?id=com.moonwink.treasury" sparkle:version="1.15.0" sparkle:os="android" />
        </item>
    </channel>
</rss>

Appcast Class

final appcast = Appcast();
final items = await appcast.parseAppcastItemsFromUri('https://raw.githubusercontent.com/larryaasen/upgrader/master/test/testappcast.xml');
final bestItem = appcast.bestItem();

Customizing the strings

The strings displayed in upgrader can be customzied by extending the UpgraderMessages class to provide custom values.

As an example, to replace the Ignore button with a custom value, first create a new class that extends UpgraderMessages, and override the buttonTitleIgnore function. Next, when calling UpgradeAlert (or UpgradeCard), add the parameter messages with an instance of your extended class. Here is an example:

class MyUpgraderMessages extends UpgraderMessages {
  @override
  String get buttonTitleIgnore => 'My Ignore';
}

UpgradeAlert(Upgrader(messages: MyUpgraderMessages()));

Language localization

The strings displayed in upgrader are already localized in 34 languages. New languages will be supported in the future with minor updates. It also supports right to left languages.

Languages supported:

  • English ('en')
  • Arabic ('ar')
  • Bengali ('bn')
  • Chinese ('zh')
  • Danish ('da')
  • Dutch ('nl')
  • Filipino ('fil')
  • French ('fr')
  • German ('de')
  • Greek ('el')
  • Haitian Creole ('ht')
  • Hebrew ('he')
  • Hindi ('hi')
  • Hungarian ('hu')
  • Indonesian ('id')
  • Italian ('it')
  • Japanese ('ja')
  • Kazakh ('kk')
  • Khmer ('km')
  • Korean ('ko')
  • Lithuanian ('lt')
  • Mongolian ('mn')
  • Norwegian ('nb')
  • Persian ('fa')
  • Polish ('pl')
  • Portuguese ('pt')
  • Russian ('ru')
  • Spanish ('es')
  • Swedish ('sv')
  • Tamil ('ta')
  • Telugu ('te')
  • Turkish ('tr')
  • Ukrainian ('uk')
  • Vietnamese ('vi')

The upgrader package can be supplied with additional languages in your code by extending the UpgraderMessages class to provide custom values.

As an example, to add the Spanish (es) language (which is already provided), first create a new class that extends UpgraderMessages, and override the message function. Next, add a string for each of the messages. Finally, when calling UpgradeAlert (or UpgradeCard), add the parameter messages with an instance of your extended class. Here is an example:

class MySpanishMessages extends UpgraderMessages {
  /// Override the message function to provide custom language localization.
  @override
  String message(UpgraderMessage messageKey) {
    if (languageCode == 'es') {
      switch (messageKey) {
        case UpgraderMessage.body:
          return 'es A new version of {{appName}} is available!';
        case UpgraderMessage.buttonTitleIgnore:
          return 'es Ignore';
        case UpgraderMessage.buttonTitleLater:
          return 'es Later';
        case UpgraderMessage.buttonTitleUpdate:
          return 'es Update Now';
        case UpgraderMessage.prompt:
          return 'es Want to update?';
        case UpgraderMessage.releaseNotes:
          return 'es Release Notes';
        case UpgraderMessage.title:
          return 'es Update App?';
      }
    }
    // Messages that are not provided above can still use the default values.
    return super.message(messageKey);
  }
}

UpgradeAlert(upgrader: Upgrader(messages: MySpanishMessages()));

You can even force the upgrader package to use a specific language, instead of the system language on the device. Just pass the language code to an instance of UpgraderMessages when displaying the alert or card. Here is an example:

UpgradeAlert(upgrader: Upgrader(messages: UpgraderMessages(code: 'es')));

Semantic Versioning

The upgrader package uses the version package that is in compliance with the Semantic Versioning spec at http://semver.org/. It converts any version string to a 3 digit version: MAJOR.MINOR.PATCH. For versions that only use 1 digit (MAJOR), it converts it to a 3 digit version: MAJOR.0.0, and for versions that only use 2 digits (MAJOR.MINOR), it converts it to a 3 digit version: MAJOR.MINOR.0, to be compliant with Semantic Versioning.

Examples

There are plenty of examples that cover various different situations that may help you customize the upgrader experience for your app. Check these out.

main.dart main_alert_again.dart main_alert_theme.dart
main_appcast.dart main_card.dart main_card_theme.dart
main_cupertino.dart main_custom_alert.dart main_custom_card.dart
main_dialog_key.dart main_driver.dart main_gorouter.dart
main_localized_rtl.dart main_macos.dart main_messages.dart
main_min_app_version.dart main_multiple.dart main_stateful.dart
main_subclass.dart

iTunes Search API

There is a class in this Flutter package used by the upgrader widgets to download app details from the iTunes Search API. The class ITunesSearchAPI can be used standalone to query iTunes for app details.

ITunesSearchAPI Example

final iTunes = ITunesSearchAPI();
final resultsFuture = iTunes.lookupByBundleId('com.google.Maps');
resultsFuture.then((results) {
    print('results: $results');
});

Results

image

Command Line App - Android

There is a command line app used to display the results from Google Play Store. The code is located in bin/playstore_lookup.dart, and can be run from the command line like this:

$ cd bin
$ dart playstore_lookup.dart id=com.google.android.apps.mapslite

Results:

playstore_lookup releaseNotes: • Support plus.codes URLs• Bug fixes
playstore_lookup version: 152.0.0
...

Command Line App - iOS

There is a command line app used to display the results from iTunes Search. The code is located in bin/itunes_lookup.dart, and can be run from the command line like this:

$ dart itunes_lookup.dart bundleid=com.google.Maps

Results:

upgrader: download: https://itunes.apple.com/lookup?bundleId=com.google.Maps
upgrader: response statusCode: 200
itunes_lookup bundleId: com.google.Maps
itunes_lookup releaseNotes: Thanks for using Google Maps!
itunes_lookup trackViewUrl: https://apps.apple.com/us/app/google-maps-transit-food/id585027354?uo=4
itunes_lookup version: 5.58
itunes_lookup all results:
{resultCount: 1, results:
...

Reporting Issues

Please submit issue reports here on GitHub. To better assist in analyzing issues, please include all of the upgrader log, which can be enabled by setting debugLogging to true.

It should look something like this:

flutter: upgrader: operatingSystem: ios, version: Version 17.0.1 (Build 21A342)
flutter: upgrader: packageInfo packageName: com.google.Maps
flutter: upgrader: packageInfo appName: Upgrader
flutter: upgrader: packageInfo version: 1.0.0
flutter: upgrader: current locale: en_US
flutter: upgrader: countryCode: US
flutter: upgrader: languageCode: en
flutter: upgrader: download: https://itunes.apple.com/lookup?bundleId=com.google.Maps&country=US&_cb=1708305624824631
flutter: upgrader: response statusCode: 200
flutter: upgrader: UpgraderAppStore: version info: appStoreListingURL: https://apps.apple.com/us/app/google-maps/id585027354?uo=4, appStoreVersion: 6.102.3, installedVersion: 1.0.0, isCriticalUpdate: null, minAppVersion: null, releaseNotes: Thanks for using Google Maps! This release brings bug fixes that improve our product to help you discover new places and navigate to them.
flutter: upgrader: need to evaluate version
flutter: upgrader: blocked: false
flutter: upgrader: debugDisplayAlways: false
flutter: upgrader: debugDisplayOnce: false
flutter: upgrader: hasAlerted: false
flutter: upgrader: installedVersion: 1.0.0
flutter: upgrader: minAppVersion: null
flutter: upgrader: isUpdateAvailable: true
flutter: upgrader: shouldDisplayUpgrade: true
flutter: upgrader: shouldDisplayReleaseNotes: true
flutter: upgrader: current locale: en_US
flutter: upgrader: languageCode: en
flutter: upgrader: showTheDialog title: Update App?
flutter: upgrader: showTheDialog message: A new version of Upgrader is available! Version 6.102.3 is now available-you have 1.0.0.
flutter: upgrader: showTheDialog releaseNotes: Thanks for using Google Maps! This release brings bug fixes that improve our product to help you discover new places and navigate to them.

Also, please include the upgrader version number from the pubspec.lock file, which should look something like this:

  upgrader:
    dependency: "direct main"
    description:
      path: ".."
      relative: true
    source: path
    version: "3.6.0"

Contributing

All comments and pull requests are welcome.

Donations / Sponsor

Please sponsor or donate to the creator of upgrader on Flattr or Patreon.

Builds

Build Status

Codemagic

CircleCI

GitHub main workflow

upgrader's People

Contributors

ahmet-fennel avatar akirakakar avatar alhamri avatar azharxes avatar clarekang avatar elmoiv avatar esentis avatar fpscolton avatar humanolaranja avatar ishworpanta10 avatar jrc2139 avatar k9i-0 avatar kartik1225 avatar larryaasen avatar luiges90 avatar mend-bolt-for-github[bot] avatar mohammadhprp avatar mulvad avatar nnowakowski avatar nwparker avatar ponnamkarthik avatar rodolfosilva avatar ruukas97 avatar samcho0608 avatar senne021 avatar stacksharebot avatar supposedlysam avatar supposedlysam-bb avatar williano avatar zazo032 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

upgrader's Issues

Parse data?

image
How can we parse this data?

I was to check if the bool value of isUpdateAvailable

If true then open updater card
if false open main page

Publish to AppStore

I used this useful pub, and now i want to publish my app to the appstore,
is there any setting that i should do before publish
for example I think I should add notification to my app id in app store pannel
could you please guide me about this issue?

Where is the full example for android and iOS?

Hi,

Sorry for my English but how to I get my app version from android and iOS. I couldn't find any good example, alse I want to force to update.

I use your example but I am not sure where to put my android app on google palay and iOS app on appstore.

you have:

For Android:

final appcast = Appcast();
final items = await appcast.parseAppcastItemsFromUri('https://raw.githubusercontent.com/larryaasen/upgrader/master/test/testappcast.xml');
final bestItem = appcast.bestItem();

For iOS:

final iTunes = ITunesSearchAPI();
final resultsFuture = iTunes.lookupByBundleId('com.google.Maps');
resultsFuture.then((results) {
    print('results: $results');
});

For iOS I think I will replace this com.google.Maps to my app but for android how to do it?
Also for Android you said 'On Android, setup the Appcast.' how can I set the app cast and where?

If you can created a step by step example it will be good for us

Thanks

Why call _sendUserToAppStore when it is running on Android?

void onUserUpdated(BuildContext context, bool shouldPop) {
   if (debugLogging) {
     print('upgrader: button tapped: $buttonTitleUpdate');
   }

   // If this callback has been provided, call it.
   var doProcess = true;
   if (this.onUpdate != null) {
     doProcess = onUpdate();
   }

   if (doProcess) {
     _sendUserToAppStore();
   }

   if (shouldPop) {
     _pop(context);
   }
 }

App Name shows null

I used UpgradeAlert in my app. In the UpgradeAlert, my app name is shown null. How can I resolve this issue?

Behavior on Android is different from specified in Readme

According to the Readme:

On Android, this widget does nothing as there is no easy way to query the Google Play Store for metadata about an app. Without the metadata, the widget cannot compare the app version with the latest Play Store version. It will not disrupt the widget tree and can be included in an Android without any issues.

However, in my application (not using an Appcast) the upgrader popup was shown to Android users, redirecting them to the AppStore. Looking at the code, it seems like the check has been commented:

//      // If this platform is not iOS, skip the iTunes lookup
//      if (!Platform.isIOS) {
//        return false;
//      }

How to change the default text?

First, congratulate them on the application. It works very well.

Is there any way to change the default text "A new version of [app_name] is available! Version [X.X] is now available you have [X.0.0]" to customText ?. To be able to change it to any language like buttonTitleIgnore, buttonTitleLater, buttonTitleUpdate, title or prompt.

Tag for CriticalIssue should not pop the alert dialog

When an item includes a critical issue tag in the RSS feed for android the alert dialog should not pop after pressing the "Update Now" button.

If the user presses this button and goes back to the app without upgrading, they are no longer gated by the alert dialog (because it was popped).

Expected:
Alert dialog gates the user if they haven't upgraded.

Actual:
Alert dialog goes away after clicking the "Upgrade Now" button.

Message localization.

Hi, thank you for the great package!

Do I understand correctly that there is no way to make localization for the message with version number?

String message() {
    return 'A new version of ${appName()} is available! Version ${currentAppStoreVersion()} is now available-you have ${currentInstalledVersion()}.';
  }

(file upgrader.dart)

If not possible can you please make the property with this String for customization, please?

_updateVersionInfo doesn't pass in mocked client

Mocking the rss feed for this package isn't currently possible without alteration to the upgrader.dart file. Although you can override the client on the Upgrader class, a new instance of the Appcast class is created inside of the _updateVersionInfo method. Since the Upgraders client isn't passed into the Appcast constructor, a new Client is created and the mocked client is not used.

Suggestion

Alter line 155 of the upgrader.dart from this:
final appcast = Appcast();
to this:
final appcast = Appcast(client: client);

version solving failed

The current Flutter SDK version is 1.14.3.

Because xXx depends on upgrader >=0.10.1 which requires Flutter SDK version >=1.12.0 <1.13.0, version solving failed.

Where to put the UpgradeAlert

Hi @larryaasen ,

In my app, before the MaterialApp, I have long initializing process, which including the user authentication as well. During the initializing process, there will be a loading screen display. After the initialization, MaterialApp will be called and home is routed to a Login page. In the Login page, it checks if user has been successfully authenticated (during initialization) so it would re-route to the App main page.
So my question is, where should I apply the UpgradeAlert?

Thanks in advance.

Update Alert working but auto updated app still showing the alert on Android

Hi, I don't know how to avoid this thing.
I checked my flutter.versionName is the new one that I remotely share with XML file.
My new flutter.versionName= 1.1.1
But even the app updated it is still showing existed app as 1.0 .
Is that affected by auto-update that is not change the flutter.versionName?

do you have any idea?

Thanks

Critical compile error

After flutter upgrade to 1.20 I get compile error

Launching lib/main.dart on AOSP on IA Emulator in debug mode...
Running Gradle task 'assembleDebug'...
../../flutter/.pub-cache/hosted/pub.dartlang.org/upgrader-2.5.0/lib/src/appcast.dart:86:36: Error: Method not found: 'XmlDocument.parse'.
      final document = XmlDocument.parse(xmlString);
                                   ^^^^^

It can be fixed by changing
final document = XmlDocument.parse(xmlString);
to
final document = parse(xmlString);

in
/.pub-cache/hosted/pub.dartlang.org/upgrader-2.5.0/lib/src/appcast.dart

But it not solution, because it package cash.

[✓] Flutter (Channel stable, 1.20.0, on Mac OS X 10.14.5 18F132, locale en-US)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.3)
[✓] Android Studio (version 3.6)
[✓] IntelliJ IDEA Ultimate Edition (version 2019.3.2)
[✓] VS Code (version 1.42.1)
[✓] Connected device (2 available)

Unhandled Exception: FormatException: Not a properly formatted version string

Hi, how can I solve this error when implementing the plugin, I did tests and the string that cannot be parse is samsung/hero2ltexx/hero2lte:7.0/NRD90M/G935FXXU2DRB6:user/release-keys

I/flutter (20116): Version: samsung/hero2ltexx/hero2lte:7.0/NRD90M/G935FXXU2DRB6:user/release-keys E/flutter (20116): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: FormatException: Not a properly formatted version stringE/flutter (20116): #0 Version.parse (package:version/version.dart:134)

I am stuck how to use this for iOS?

Hi,

I am trying to use this package for my iOS app which is in App Store. But I am not sure where to start. Is the example file is enough? Or can you post more deatils now not use for iOS. Also I want to force user to update always. how to disable other 2 buttons? Thanks

RangeError (index): Invalid value

I am getting the following error message:

flutter: upgrader: RangeError (index): Invalid value: Valid value range is empty: 0

Not sure if I am doing something wrong here, the examples are not clear.

Is not an issue. Check iOS Update before showing UpgradeAlert.

initState I call below code _checkForIOSUpdate() to see if iOS update available. Based on this result I show UpgradeAlert() or not.

(A) In Build Widget I run _checkUpdate = true ? UpgradeAlert() : new Container() so if no update user doesn't need to see UpgradeAlert() checking...

(B) initState I call _checkForIOSUpdate

/// CHECK FOR IOS UPDATE
  Future _checkForIOSUpdate() async {

    Upgrader().clearSavedSettings();
    Upgrader().debugDisplayAlways = false;
    Upgrader().debugDisplayOnce = false;
    await Upgrader().initialize();
    bool _isAvailable = Upgrader().isUpdateAvailable();
    await Future.delayed(Duration(milliseconds: 250));

    print('_isAvailable: $_isAvailable');

    if (_isAvailable == true) {
      setState(() {
        _checkUpdate = true;
      });
    } else {
      setState(() {
        _checkUpdate = false;
      });
    }
  }


How to force updates?

So I have a few questions here on how the package works.

I want to force updates base on the semantic versioning. So if the app updates from 1.0.0 to 2.0.0, I want to be able to force my users to see the message and update, otherwise just pop the alert with default settings.

But for that I would need the version, what is the best way to do that? Because I don't see any public Futures or methods with callbacks.

something like that?

Upgrader().installAppStoreListingURL(myURL);
if (Upgrader().currentAppStoreVersion().someparsing() > Upgrader().currentInstalledVersion().someparsing()) {
 bool  _shouldForceUpgrade = true;
}

I still don't know how to use it on Android

what is Appcast and how to configure Appcast?

Appcast Example

final appcast = Appcast();
final items = await appcast.parseAppcastItemsFromUri('https://raw.githubusercontent.com/larryaasen/upgrader/master/test/testappcast.xml');
final bestItem = appcast.bestItem();

What is this URL "https://raw.githubusercontent.com/larryaasen/upgrader/master/test/testappcast.xml"?

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
    <channel>
        <title>Debt Now App - Appcast</title>
        <item>
            <title>Version 1.15.0</title>
            <description>desc</description>
            <pubDate>Sun, 30 Dec 2018 12:00:00 +0000</pubDate>
            <enclosure url="https://play.google.com/store/apps/details?id=com.moonwink.treasury" sparkle:version="1.15.0" sparkle:os="android" />
        </item>
    </channel>
</rss>

Where do I need to configure the XML

final appcastURL = 'https://www.mydomain.com/myappcast.xml';
  final cfg = AppcastConfiguration(url: appcastURL, supportedOS: ['android']);

what is the appcastURL?

Debug Issue

Hi,
Im currently developing an app using flutter with your library. With debug version the Upgrade Alert still not appear in my app even it printed out build UpgradeAlert in the debug console (my app bundle is already on app store with the version of 1.1.3 and my current xcode build version is 0.0.1). This is my code:

body: UpgradeAlert( debugLogging: true, debugDisplayOnce: true, debugAlwaysUpgrade: true, child: SizedBox.expand( child: PageView( controller: _pageController, onPageChanged: (index) { setState(() => _currentIndex = index); }, children: buildListContentPageView(context), ), ), ),
and this is my debug console result:
Screenshot 2020-08-21 at 12 59 55
Is it not working with non-realease version if it does how can i debug it and use it in my code?
Thanks for your support.
Edit 1: Im using upgrader version 2.2.0 due to version coflict with xml version.

Update now not working

When i choose update now. The package only redirect to app store. But my device is using android.

Test Flight

Hi, does this package work for testFlight?

bug help systemName":"iOS","systemVersion":"13.6.1","utsname.machine:":"iPhone11,2", AND systemName":"iOS","systemVersion":"13.6","utsname.machine:":"iPhone12,1","

MESSAGE:#0 _StringBase.replaceAll (dart:core-patch/string_patch.dart:637)
#1 Upgrader.message (package:upgrader/src/upgrader.dart:248)
#2 Upgrader.checkVersion. (package:upgrader/src/upgrader.dart:264)
#3 new Future.delayed. (dart:async/future.dart:325)
#4 _rootRun (dart:async/zone.dart:1182)
#5 _CustomZone.run (dart:async/zone.dart:1093)
#6 _CustomZone.runGuarded (dart:async/zone.dart:997)
#7 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1037)
#8 _rootRun (dart:async/zone.dart:1190)
#9 _CustomZone.run (dart:async/zone.dart:1093)
#10 _CustomZone.bindCallback. (dart:async/zone.dart:1021)
#11 SemanticsConfiguration._addArgumentlessAction. (package:flutter/src/semantics/semantics.dart:2847)
#12 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:397)
#13 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:428)
#14 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168)

Unhandled Exception: Invalid argument(s) (replacement): Must not be null

I'm getting this error in debug.

flutter version 1.20.4 channel stable
upgrader version 2.5.0
xml version 4.2.0

--on ios--
flutter: upgrader: build UpgradeAlert
flutter: upgrader: package info packageName: com.kolayyakit.KolayYakit
flutter: upgrader: package info version: 2.6
flutter: upgrader: countryCode: US
flutter: upgrader: build UpgradeAlert
[VERBOSE-2:ui_dart_state.cc(166)] Unhandled Exception: Invalid argument(s) (replacement): Must not be null
#0 _StringBase.replaceAll (dart:core-patch/string_patch.dart:637:30)
#1 Upgrader.message (package:upgrader/src/upgrader.dart:248:15)
#2 Upgrader.checkVersion. (package:upgrader/src/upgrader.dart:264:24)
#3 new Future.delayed. (dart:async/future.dart:325:39)
#4 _rootRun (dart:async/zone.dart:1182:47)
#5 _CustomZone.run (dart:async/zone.dart:1093:19)
#6 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
#7 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1037:23)
#8 _rootRun (dart:async/zone.dart:1190:13)
#9 _CustomZone.run (dart:async/zone.dart:1093:19)
#10 _CustomZone.bindCallback. (dart:async/zone.dart:1021:23)
#11 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15)
#12 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:<…>

--on android--
I/flutter (13693): upgrader: build UpgradeAlert
I/flutter (13693): upgrader: build UpgradeAlert
I/flutter (13693): upgrader: package info packageName: com.ilerleyen.kolayyakit
I/flutter (13693): upgrader: package info version: 2.6.1
I/flutter (13693): upgrader: appcast is available for this platform
E/flutter (13693): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: NoSuchMethodError: The method 'replaceAll' was called on null.
E/flutter (13693): Receiver: null
E/flutter (13693): Tried calling: replaceAll("{{appName}}", "Kolay Yakıt")
E/flutter (13693): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
E/flutter (13693): #1 Upgrader.message (package:upgrader/src/upgrader.dart:248:15)
E/flutter (13693): #2 Upgrader.checkVersion. (package:upgrader/src/upgrader.dart:264:24)
E/flutter (13693): #3 new Future.delayed. (dart:async/future.dart:325:39)
E/flutter (13693): #4 _rootRun (dart:async/zone.dart:1182:47)
E/flutter (13693): #5 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (13693): #6 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
E/flutter (13693): #7 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1037:23)
E/flutter (13693): #8 _rootRun (dart:async/zone.dart:1190:13)
E/flutter (13693): #9 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (13693): #10 _CustomZone.bindCallback. (dart:async/zone.dart:1021:23)
E/flutter (13693): #11 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15)
E/flutter (13693): #12 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:397:19)
E/flutter (13693): #13 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:428:5)
E/flutter (13693): #14 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
E/flutter (13693):
I/flutter (13693): "<" expected at 1:1
I/flutter (13693): upgrader: appcast item count: 0

UpdateAlert not working properly

I used updateAlert as the way the example uses. However, when I download the app version 1.01 from App Store, it still asks me to update even though I have the newest version. Why did that happen?

First timer facing XML Document issue

Hello there!

I am new to this package and tried installing upgrader 2.4.0 following the tutorial, but got the following error after "Flutter Run":

Compiler message:
../../sdk/flutter/.pub-cache/hosted/pub.dartlang.org/upgrader-2.4.0/lib/src/appcas
t.dart:86:36: Error: Method not found: 'XmlDocument.parse'.
final document = XmlDocument.parse(xmlString);
^^^^^

Could you kindly guide me in the right direction?

Thanks for your contribution!

currentInstalledVersion is null

I'm getting an error with version 2.2.0 (I have to use 2.2.0 because >=2.2.1 breaks iOS with Method not found: 'XmlDocument.parse'.

Looks like _installedVersion is not getting set soon enough, because _packageInfo.version returns a string. You can see from the stack trace, but UpgradeAlert calls Text(Upgrader().message()), which calls currentInstalledVersion(), which is null.

It only happens on when upgrader is show as app first loads. Hot reloading fixes the issue, but a hot restart that loads the upgrader on the first page is throwing this error.

Tried calling WidgetsFlutterBinding.ensureInitialized(); in case that fixes anything, but no luck.

Flutter version 1.20.1

flutter: [2020-08-10 17:17:39.177563 | ConsoleHandler | INFO] ---------- ERROR ----------
flutter: [2020-08-10 17:17:39.177938 | ConsoleHandler | INFO] Invalid argument(s) (replacement): Must not be null
flutter: [2020-08-10 17:17:39.178612 | ConsoleHandler | INFO]
flutter: [2020-08-10 17:17:39.179452 | ConsoleHandler | INFO] ------- STACK TRACE -------
flutter: [2020-08-10 17:17:39.180092 | ConsoleHandler | INFO] #0      _StringBase.replaceAll (dart:core-patch/string_patch.dart:637:30)
flutter: [2020-08-10 17:17:39.180469 | ConsoleHandler | INFO] #1      Upgrader.message (package:upgrader/src/upgrader.dart:251:15)
flutter: [2020-08-10 17:17:39.180754 | ConsoleHandler | INFO] #2      UpgradeCard.build.<anonymous closure> (package:upgrader/src/upgrade_alert.dart:216:43)
flutter: [2020-08-10 17:17:39.181070 | ConsoleHandler | INFO] #3      _FutureBuilderState.build (package:flutter/src/widgets/async.dart:740:55)
flutter: [2020-08-10 17:17:39.181429 | ConsoleHandler | INFO] #4      StatefulElement.build (package:flutter/src/widgets/framework.dart:4663:28)
flutter: [2020-08-10 17:17:39.181869 | ConsoleHandler | INFO] #5      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4546:15)
flutter: [2020-08-10 17:17:39.182208 | ConsoleHandler | INFO] #6      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4719:11)
flutter: [2020-08-10 17:17:39.182470 | ConsoleHandler | INFO] #7      Element.rebuild (package:flutter/src/widgets/framework.dart:4262:5)
flutter: [2020-08-10 17:17:39.182786 | ConsoleHandler | INFO] #8      BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2667:33)
flutter: [2020-08-10 17:17:39.183146 | ConsoleHandler | INFO] #9      WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:866:20)
flutter: [2020-08-10 17:17:39.183440 | ConsoleHandler | INFO] #10     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:286:5)
flutter: [2020-08-10 17:17:39.183782 | ConsoleHandler | INFO] #11     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
flutter: [2020-08-10 17:17:39.184135 | ConsoleHandler | INFO] #12     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1056:9)
flutter: [2020-08-10 17:17:39.184480 | ConsoleHandler | INFO] #13     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:972:5)
flutter: [2020-08-10 17:17:39.184796 | ConsoleHandler | INFO] #14     _rootRun (dart:async/zone.dart:1190:13)
flutter: [2020-08-10 17:17:39.185188 | ConsoleHandler | INFO] #15     _CustomZone.run (dart:async/zone.dart:1093:19)
flutter: [2020-08-10 17:17:39.185543 | ConsoleHandler | INFO] #16     _CustomZone.runGuarded (dart:async/zone.dart:997:7)
flutter: [2020-08-10 17:17:39.185855 | ConsoleHandler | INFO] #17     _invoke (dart:ui/hooks.dart:253:10)
flutter: [2020-08-10 17:17:39.186180 | ConsoleHandler | INFO] #18     _drawFrame (dart:ui/hooks.dart:211:3)
flutter: [2020-08-10 17:17:39.186911 | ConsoleHandler | INFO]
flutter: [2020-08-10 17:17:39.187507 | ConsoleHandler | INFO] ======================================================================
flutter: [2020-08-10 17:17:39.216065 | Catcher | INFO] Report result: true

Dismiss on press back button android

can you add parameter for dismiss on press back button?
canDismissDialog is parameter for tap outside alert dialog but if use android we also can dismiss dialog with back button

Looking for new language translations

I am looking for language translations of message strings for this upgrader package. I already have English and Spanish languages. Looking for many more including Chinese, Japanese, Korean, Russian, French, German, Italian. Please place a comment in this issue with the six translated strings for the language of your choice.

Use this empty form below to get started. Copy this and fill it out:
Language name:
language code:
body:
ignore button:
later button:
update button:
prompt:
release notes:
title:

Note: The body string supports mustache style template variables such as {{appName}}.

Language name: English
language code: en
body: A new version of {{appName}} is available! Version {{currentAppStoreVersion}} is now available-you have {{currentInstalledVersion}}.
ignore button: IGNORE
later button: LATER
update button: UPDATE NOW
prompt: Would you like to update it now?
release notes: Release Notes
title: Update App?

Language name: Spanish
language code: es
body: ¡Una nueva versión de {{appName}} está disponible! La versión {{currentAppStoreVersion}} ya está disponible, usted tiene {{currentInstalledVersion}}.
ignore button: IGNORAR
later button: MÁS TARDE
update button: ACTUALIZAR
prompt: ¿Le gustaría actualizar ahora?
release notes: Notas De Lanzamiento
title: ¿Actualizar la aplicación?

_appStoreVersion & _installedVersion always null at the First Time app running

when isUpdateAvailable() called at the first time app running,
_appStoreVersion & _installedVersion always null, so the dialog will not show,

in my case, i put UpgradeAlert as a child of scaffold in my Home view,.
when application run, and load the home view, i debug the _appStoreVersion & _installedVersion always null
but, when i switch to other page in my app, and back to Home, the _appStoreVersion & _installedVersion filled, and the Popup Alert show..

how to solve this ?

Initial Setup

I want to use this lib in my app
could you please tell me the steps?
should I need change anything in xCode runner?
where should i add or change versions?
I recieved this error: upgrader.ITunesResults.version: RangeError (index): Invalid value: Valid value range is empty: 0
and this: upgrader.ITunesResults.trackViewUrl: RangeError (index): Invalid value: Valid value range is empty: 0
I just wraped my Splash Screen Widget with UpgradeAlert widget.

The alert is not shown on iOS

I'm using the latest version and have integrated UpgradeAlert to my home screen:

UpgradeAlert(
      debugLogging: true,
      minAppVersion: leastIosVersion,
      child: _buildBody(),
    )

when the app version is lower than minAppVersion, the alert is shown and the update is forced.
when the app is higher than minAppVersion, despite I see an update is available in logs, the alert is not shown:

flutter: upgrader: package info packageName: com.xxx.app
flutter: upgrader: package info version: 0.00.30
flutter: upgrader: countryCode: MY
 flutter: upgrader: appStoreVersion: 0.00.50
flutter: upgrader: installedVersion: 0.00.30
 flutter: upgrader: isUpdateAvailable: true

Support flutter 1.17.0 stable

Because app depends on upgrader >=0.10.1 which requires Flutter SDK version >=1.12.0 <1.13.0, version solving failed.

Workaround

Add this your pubspec.yaml

dependency_overrides:
  upgrader: ^0.10.4

By the way, many thanks for the nice work. 👍

Not supported in Flutter SDK version 1.13.6, help

I use the latest version from pub.dev: upgrader: ^0.10.1
Then I got this
How to solve it? Thank you

Running "flutter pub get" in BuangDuit...                       
The current Flutter SDK version is 1.13.6.

Because buangduit depends on upgrader >=0.10.1 which requires Flutter SDK version >=1.12.0 <1.13.0, version solving failed.
pub get failed (1; Because buangduit depends on upgrader >=0.10.1 which requires Flutter SDK version >=1.12.0 <1.13.0, version solving failed.)
exit code 1

Theme.of(context).textTheme.headline6

pub-cache/hosted/pub.flutter-io.cn/upgrader-0.11.1/lib/src/upgrade_alert.dart:388:46: Error: The getter 'headline6' isn't defined for the class 'TextTheme'.

Version details not showing

I can see my package, but installed and available version is not displaying.

Faced issues.

  1. After than not able view the version details only alert with appname "A new version of xxx is available! Version null is now available-you have null"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.