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

Overview

Upgrader

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

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

When a newer app version is availabe 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 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 in the future, it will become more likely that users on other app stores need to be nagged about upgrading.

UI

The UI comes in two flavors: alert or card. The UpgradeAlert class is used to display the popup alert prompt, and the UpgradeCard class is used to display the inline material design card.

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.

Minimum App Version

The upgrader package can use a forced upgrade version (minimum app version) simply by adding that version number to the description field in the app stores. 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.

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 (version 3.9.0+) will recognize and honor that vaule.

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 AppStoreConnet in the Desctiption field.

Alert Example

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

import 'package:flutter/material.dart';
import 'package:upgrader/upgrader.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  MyApp({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Upgrader Example',
      home: Scaffold(
          appBar: AppBar(
            title: Text('Upgrader Example'),
          ),
          body: UpgradeAlert(
            child: 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

Customization

The UpgradeAlert widget can be customized by setting parameters in the constructor of the UpgradeAlert widget.

  • appcastConfig: the appcast configuration, defaults to null
  • client: an HTTP Client that can be replaced for mock testing, defaults to null
  • durationUntilAlertAgain: duration until alerting user again, which defaults to 3 days
  • debugDisplayAlways: always force the upgrade to be available, defaults to false
  • debugDisplayOnce: display the upgrade at least once once, defaults to false
  • debugLogging: display logging statements, which defaults to false
  • messages: optional localized messages used for display in upgrader
  • 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 when the back button is tapped, 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
  • canDismissDialog: can alert dialog be dismissed on tap outside of the alert dialog, which defaults to false (not used by UpgradeCard)
  • countryCode: the country code that will override the system locale, which defaults to null (iOS only)
  • minAppVersion: the minimum app version supported by this app. Earlier versions of this app will be forced to update to the current version. Defaults to null.
  • dialogStyle: the upgrade dialog style, either material or cupertino, defaults to material, used only by UpgradeAlert, works on Android and iOS.

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,
);

iOS Country Code

When your app is not in the iOS 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 Apple. It assumes the app is in the US App Store.

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 class Appcast, in this Flutter package, is used by the upgrader widgets to download app details from an appcast, based on the Sparkle framework by Andy Matuschak. You can read the Sparkle documentation here: https://sparkle-project.org/documentation/publishing/.

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

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 Appcast class can be used stand alone or as part of upgrader.

Appcast Example

This is an Appcast example for Android.

@override
Widget build(BuildContext context) {
  // On Android, setup the Appcast.
  // On iOS, the default behavior will be to use the App Store version.
  final appcastURL =
      'https://raw.githubusercontent.com/larryaasen/upgrader/master/test/testappcast.xml';
  final cfg = AppcastConfiguration(url: appcastURL, supportedOS: ['android']);

  return MaterialApp(
    title: 'Upgrader Example',
    home: Scaffold(
        appBar: AppBar(
          title: Text('Upgrader Example'),
        ),
        body: UpgradeAlert(
          appcastConfig: cfg,
          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 display

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 paramter messages with an instance of your extended class. Here is an example:

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

UpgradeAlert(messages: MyUpgraderMessages());

Language localization

The strings displayed in upgrader are already localized in various languages. New languages will be supported in the future with minor updates.

Languages supported:

  • English ('en')
  • Arabic ('ar')
  • Bengali ('bn')
  • Filipino ('fil')
  • French ('fr')
  • German ('de')
  • Greek ('el')
  • Hungarian ('hu')
  • Indonesian ('id')
  • Italian ('it')
  • Kazakh ('kk')
  • Korean ('ko')
  • Lithuanian ('lt')
  • Norwegian ('nb')
  • Persian ('fa')
  • Polish ('pl')
  • Portuguese ('pt')
  • Russian ('ru')
  • Spanish ('es')
  • Tamil ('ta')
  • 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 paramter 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.title:
          return 'es Update App?';
      }
    }
    // Messages that are not provided above can still use the default values.
    return super.message(messageKey);
  }
}

UpgradeAlert(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(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/.

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:

$ 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 should look something like this:

flutter: upgrader: languageCode: en
flutter: upgrader: build UpgradeAlert
flutter: upgrader: default operatingSystem: ios 11.4
flutter: upgrader: operatingSystem: ios
flutter: upgrader: platform: TargetPlatform.iOS
flutter: upgrader: package info packageName: com.google.Maps
flutter: upgrader: package info appName: Upgrader
flutter: upgrader: package info version: 1.0.0
flutter: upgrader: countryCode: US
flutter: upgrader: blocked: false
flutter: upgrader: debugDisplayAlways: false
flutter: upgrader: debugDisplayOnce: false
flutter: upgrader: hasAlerted: false
flutter: upgrader: appStoreVersion: 5.81
flutter: upgrader: installedVersion: 1.0.0
flutter: upgrader: minAppVersion: null
flutter: upgrader: isUpdateAvailable: true
flutter: upgrader: shouldDisplayUpgrade: true
flutter: upgrader: shouldDisplayReleaseNotes: true
flutter: upgrader: showDialog title: Update App?
flutter: upgrader: showDialog message: A new version of Upgrader is available! Version 5.81 is now available-you have 1.0.0.
flutter: upgrader: showDialog 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.

Comments
  • PlayStoreResults.redesignedVersion exception: FormatException: Not a properly formatted version string. And also, will it work for updates with VersionCode Changes or do have to update Version Name as well ?

    PlayStoreResults.redesignedVersion exception: FormatException: Not a properly formatted version string. And also, will it work for updates with VersionCode Changes or do have to update Version Name as well ?

    To better assist in analyzing issues, please include all of the upgrader log, which should look something like this:

    upgrader: build UpgradeAlert
    I/flutter (27502): upgrader: languageCode: en
    I/flutter (27502): upgrader: default operatingSystem: android QKQ1.190828.002 test-keys
    I/flutter (27502): upgrader: operatingSystem: android
    I/flutter (27502): upgrader: platform: TargetPlatform.android
    I/flutter (27502): upgrader: isAndroid: true, isIOS: false, isLinux: false, isMacOS: false, isWindows: false, isFuchsia: false, isWeb: false
    I/flutter (27502): upgrader: instantiated.
    I/flutter (27502): upgrader: build UpgradeAlert
    I/flutter (27502): upgrader: languageCode: en
    I/flutter (27502): upgrader: default operatingSystem: android QKQ1.190828.002 test-keys
    I/flutter (27502): upgrader: operatingSystem: android
    I/flutter (27502): upgrader: platform: TargetPlatform.android
    I/flutter (27502): upgrader: isAndroid: true, isIOS: false, isLinux: false, isMacOS: false, isWindows: false, isFuchsia: false, isWeb: false
    I/flutter (27502): upgrader: package info packageName: com.searchmi.da
    I/flutter (27502): upgrader: package info appName: SearchMI
    I/flutter (27502): upgrader: package info version: 1.0.0
    I/flutter (27502): upgrader: countryCode: IN
    I/flutter (27502): upgrader: package info packageName: com.searchmi.da
    I/flutter (27502): upgrader: package info appName: SearchMI
    I/flutter (27502): upgrader: package info version: 1.0.0
    I/flutter (27502): upgrader: countryCode: IN
    I/flutter (27502): upgrader: instantiated.
    I/flutter (27502): upgrader: build UpgradeAlert
    I/flutter (27502): upgrader: languageCode: en
    I/flutter (27502): upgrader: default operatingSystem: android QKQ1.190828.002 test-keys
    I/flutter (27502): upgrader: operatingSystem: android
    I/flutter (27502): upgrader: platform: TargetPlatform.android
    I/flutter (27502): upgrader: isAndroid: true, isIOS: false, isLinux: false, isMacOS: false, isWindows: false, isFuchsia: false, isWeb: false
    I/flutter (27502): upgrader: package info packageName: com.searchmi.da
    I/flutter (27502): upgrader: package info appName: SearchMI
    I/flutter (27502): upgrader: package info version: 1.0.0
    I/flutter (27502): upgrader: countryCode: IN
    I/flutter (27502): upgrader: instantiated.
    I/flutter (27502): upgrader: build UpgradeAlert
    I/flutter (27502): upgrader: languageCode: en
    I/flutter (27502): upgrader: default operatingSystem: android QKQ1.190828.002 test-keys
    I/flutter (27502): upgrader: operatingSystem: android
    I/flutter (27502): upgrader: platform: TargetPlatform.android
    I/flutter (27502): upgrader: isAndroid: true, isIOS: false, isLinux: false, isMacOS: false, isWindows: false, isFuchsia: false, isWeb: false
    I/flutter (27502): upgrader: package info packageName: com.searchmi.da
    I/flutter (27502): upgrader: package info appName: SearchMI
    I/flutter (27502): upgrader: package info version: 1.0.0
    I/flutter (27502): upgrader: countryCode: IN
    I/flutter (27502): upgrader: PlayStoreResults.redesignedVersion exception: FormatException: Not a properly formatted version string
    I/flutter (27502): upgrader: PlayStoreResults.redesignedVersion exception: FormatException: Not a properly formatted version string
    I/flutter (27502): upgrader: PlayStoreResults.redesignedVersion exception: FormatException: Not a properly formatted version string
    I/flutter (27502): upgrader: blocked: false
    I/flutter (27502): upgrader: debugDisplayAlways: true
    I/flutter (27502): upgrader: debugDisplayOnce: false
    I/flutter (27502): upgrader: hasAlerted: false
    I/flutter (27502): upgrader: shouldDisplayUpgrade: true
    I/flutter (27502): upgrader: shouldDisplayReleaseNotes: true
    I/flutter (27502): upgrader: showDialog title: Update App?
    I/flutter (27502): upgrader: showDialog message: A new version of SearchMI is available! Version  is now available-you have 1.0.0.
    I/flutter (27502): upgrader: showDialog releaseNotes: Get the best business out of your area !
    I/flutter (27502): upgrader: PlayStoreResults.redesignedVersion exception: FormatException: Not a properly formatted version string
    

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

       upgrader:
        dependency: "direct main"
        description:
          name: upgrader
          url: "https://pub.dartlang.org"
        source: hosted
        version: "4.4.2"
    

    --> Also Latest Version From Play Store is Missing. My App is in Internal Testing but it is Available on Play Store

    image

    enhancement Resolved Android 
    opened by Kishan-Somaiya 27
  • Playstore updated layout

    Playstore updated layout

    The PlayStore has changed its layout page, or at least is in the process of changing it (releasing partially the new visual). So I guess the play_store_search_api.dart will no longer work, since the classes searched on the page no longer exists. This requires an update to the API.

    Page from waybackmachine:

    Image

    The new layout:

    Image

    The app version is now inside the About this app dialog.

    Image
    bug Resolved Android 
    opened by JHBitencourt 23
  • Google play rejection - anyone else?

    Google play rejection - anyone else?

    Hi - I just got a Google play rejection for metadata call out as:

    We found an issue in the following area(s): Full description (en_US): “[:mav: 2.1.11]”

    I've been doing many releases with the description as is and using the upgrader package with success up until yesterday.

    Just posting this to see if anyone else is encountering an issue currently for Android that maybe the [mav] tag is throwing something off suddenly on google side? I've removed the [mav] tag and attempting to resubmit for review, as i'm not sure why the description that has been fine for months is no longer ok and wondering if there is an issue with parsing this tag somehow at the end of the description? Certainly realize this could be something unrelated...just trying to get a data point.

    thanks

    bug Resolved Android 
    opened by nholmvio 22
  • Android Update Without Appcast

    Android Update Without Appcast

    1. Android Without Appcast I have implemented a functionality that will allow Android updates without Appcast. The feature will pull the App's latest version and release notes from the PlayStore just like how the iTunes version of the iOS is implemented. It also allow developers to optionally enter the Android ID of their apps in UpgradeAlert and UpgradeCard if it is different from what is currently in their app. The only package I added was dart html to parse the html I am downloading from the PlayStore.

    2. AlertDialog Buttons I have changed the UpdateNow button to an ElevatedButton since is a call to action button and must be different from Ignore and Later.

    Screenshot_20210628-041918

    enhancement need more information Android 
    opened by Williano 22
  • Version details not showing

    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"
    need more information 
    opened by Anand3777 21
  • The update button is not showing

    The update button is not showing

    I/flutter (13003): end I/flutter (13003): upgrader: build UpgradeAlert I/flutter (13003): upgrader: blocked: true I/flutter (13003): upgrader: debugDisplayAlways: true I/flutter (13003): upgrader: debugDisplayOnce: false I/flutter (13003): upgrader: hasAlerted: false I/flutter (13003): upgrader: shouldDisplayUpgrade: true I/flutter (13003): upgrader: shouldDisplayReleaseNotes: true I/flutter (13003): upgrader: showDialog title: Update App? I/flutter (13003): upgrader: showDialog message: A new version of Salwa & Fairouz is available! Version 0.0.1 is now available-you have 2.2.3. I/flutter (13003): upgrader: showDialog releaseNotes: de Screenshot_20211206-133639

    How To? Android 
    opened by mohammad-alnimer1 20
  • First timer facing XML Document issue

    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!

    bug need more information 
    opened by mystarhub 19
  • I am stuck how to use this for iOS?

    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

    need more information 
    opened by NTMS2017 16
  • Issue with lastversion alerted during testing

    Issue with lastversion alerted during testing

    image

    Hi, I am using the upgrader plugin for my application. While testing I am getting the error 'Null check operator used on a null value' on _lastVersionAlerted. Please find attached the screenshot confirming the same.

    Is this normal or am I making a mistake ?

    Regards, Ameya

    need more information 
    opened by ameya730 15
  • upgrader.ITunesResults.version

    upgrader.ITunesResults.version

    I get an error like the one below, can anyone help me?

    flutter: upgrader.ITunesResults.version: RangeError (index): Invalid value: Valid value range is empty: 0 flutter: upgrader.ITunesResults.trackViewUrl: RangeError (index): Invalid value: Valid value range is empty: 0

    need more information How To? 
    opened by abdulrojak288 15
  • New update PopUp dialogue not showing!

    New update PopUp dialogue not showing!

    I'm having some trouble trying to show a pop up dialogue when a new version is available.

    As you can notice from the logs there are some exceptions happening PlayStoreResults.version, PlayStoreResults.releaseNotes and PlayStoreResults.description and I'm not sure why.

    Some Context This version 1.3.4 is already uploaded to the playstore internal testing environment yet the internal testers (with the version v1.3.3) don't receive any popup about the newer version.

    Flutter Code

    ...
    UpgradeAlert(
            upgrader: Upgrader(
              debugLogging: true,
            ),
            child: const HomeScreen(),
          ),
    

    Logs

    I/flutter ( 7859): upgrader: instantiated.
    I/flutter ( 7859): upgrader: build UpgradeAlert
    I/flutter ( 7859): upgrader: languageCode: en
    I/flutter ( 7859): upgrader: default operatingSystem: android QP1A.190711.020.J600FXXSACVB1
    I/flutter ( 7859): upgrader: operatingSystem: android
    I/flutter ( 7859): upgrader: platform: TargetPlatform.android
    I/flutter ( 7859): upgrader: isAndroid: true, isIOS: false, isLinux: false, isMacOS: false, isWindows: false, isFuchsia: false, isWeb: false
    I/flutter ( 7859): upgrader: package info packageName: com.wilayat.app
    I/flutter ( 7859): upgrader: package info appName: wilayat
    I/flutter ( 7859): upgrader: package info version: 1.3.4
    I/flutter ( 7859): upgrader: countryCode: US
    I/flutter ( 7859): upgrader: PlayStoreResults.version exception: Bad state: No element
    I/flutter ( 7859): upgrader: PlayStoreResults.releaseNotes exception: RangeError (index): Invalid value: Valid value range is empty: 0
    I/flutter ( 7859): upgrader: PlayStoreResults.description exception: RangeError (index): Invalid value: Valid value range is empty: 0
    I/flutter ( 7859): upgrader: blocked: false
    I/flutter ( 7859): upgrader: debugDisplayAlways: false
    I/flutter ( 7859): upgrader: debugDisplayOnce: false
    I/flutter ( 7859): upgrader: hasAlerted: false
    I/flutter ( 7859): upgrader: appStoreVersion: null
    I/flutter ( 7859): upgrader: installedVersion: 1.3.4
    I/flutter ( 7859): upgrader: minAppVersion: null
    I/flutter ( 7859): upgrader: isUpdateAvailable: false
    I/flutter ( 7859): upgrader: shouldDisplayUpgrade: false
    I/flutter ( 7859): upgrader: shouldDisplayReleaseNotes: false
    

    The pubspec.lock file:

      upgrader:
        dependency: "direct main"
        description:
          name: upgrader
          url: "https://pub.dartlang.org"
        source: hosted
        version: "4.2.0"
    
    bug Resolved Android 
    opened by GitGud31 14
  • Added an optional bundleId property to the Upgrader class. if present…

    Added an optional bundleId property to the Upgrader class. if present…

    Added an optional bundleId property to the Upgrader class. if present, this will override which Bundle ID is used to query the iTunes stores.

    This addresses issue #250

    opened by proxy2501 1
  • Upgrader possibly queries the wrong bundleId on iOS

    Upgrader possibly queries the wrong bundleId on iOS

    Hi, I'm having an issue with getting a good response from the Apple Store, and I suspect it has to do with the package name that is being used to make the query.

    Background

    We originally decided on an application id based on the (apparent) convention of naming Flutter apps with underscores. So our app's applicationID in ./android/app/build.gradle ended up being com.[company].xxx_yyy_zzz:

    defaultConfig {
            applicationId "com.[company].xxx_yyy_zzz"
            minSdkVersion 21
            targetSdkVersion 31
            versionCode flutterVersionCode.toInteger()
            versionName flutterVersionName
        }
    

    However, when we later tried to release on Apple Store, we were unable to use this as our bundle id, because underscores are not allowed.

    So we chose the following bundle id instead: com.[company].xxxYyyZzz

    This works fine in-so-far as simply specifying this as our PRODUCT_BUNDLE_IDENTIFIER in ./ios/Runner.xcodeproj/project.pbxproj instead. The app compiles and releases just fine, and is currently released on both Google Play and Apple Store with these settings.

    The problem

    We have created an instance of Upgrader and provided it to an UpgradeAlert inside of the Widget tree as described in the readme.

    We have tested and confirmed that this works correctly on Android with newer versions on Google Play. The Upgrader queries the Google Play version and gets a good response.

    These are the debug logs when running on Android:

    I/flutter ( 4832): upgrader: build UpgradeAlert
    I/flutter ( 4832): upgrader: languageCode: en
    I/flutter ( 4832): upgrader: default operatingSystem: android RSR1.201013.001
    I/flutter ( 4832): upgrader: operatingSystem: android
    I/flutter ( 4832): upgrader: platform: TargetPlatform.android
    I/flutter ( 4832): upgrader: isAndroid: true, isIOS: false, isLinux: false, isMacOS: false, isWindows: false, isFuchsia: false, isWeb: false
    I/flutter ( 4832): upgrader: package info packageName: com.[company].xxx_yyy_zzz
    I/flutter ( 4832): upgrader: package info appName: [app name]
    I/flutter ( 4832): upgrader: package info version: 1.0.12
    I/flutter ( 4832): upgrader: countryCode: US
    I/flutter ( 4832): upgrader: languageCode: en
    I/flutter ( 4832): upgrader: blocked: false
    I/flutter ( 4832): upgrader: debugDisplayAlways: false
    I/flutter ( 4832): upgrader: debugDisplayOnce: false
    I/flutter ( 4832): upgrader: hasAlerted: false
    I/flutter ( 4832): upgrader: appStoreVersion: 1.0.12
    I/flutter ( 4832): upgrader: installedVersion: 1.0.12
    I/flutter ( 4832): upgrader: minAppVersion: null
    I/flutter ( 4832): upgrader: isUpdateAvailable: false
    I/flutter ( 4832): upgrader: shouldDisplayUpgrade: false
    I/flutter ( 4832): upgrader: shouldDisplayReleaseNotes: true
    

    However, on iOS the Upgrader seems to think that the packageName is still supposed to be com.[company].xxx_yyy_zzz and not com.[company].xxxYyyZzz

    Since I have not been able to find a way of ascertaining which bundleId is actually being used during runtime, I can only speculate that the Upgrader is asking for the incorrect bundleId when running on iOS, because of this "dual id" situation.

    These are the debug logs when setting Upgrader.platform to platform: TargetPlatform.iOS:

    I/flutter ( 4832): upgrader: build UpgradeAlert
    I/flutter ( 4832): upgrader: languageCode: en
    I/flutter ( 4832): upgrader: default operatingSystem: android RSR1.201013.001
    I/flutter ( 4832): upgrader: operatingSystem: android
    I/flutter ( 4832): upgrader: platform: TargetPlatform.iOS
    I/flutter ( 4832): upgrader: isAndroid: true, isIOS: false, isLinux: false, isMacOS: false, isWindows: false, isFuchsia: false, isWeb: false
    I/flutter ( 4832): upgrader: package info packageName: com.[company].xxx_yyy_zzz
    I/flutter ( 4832): upgrader: package info appName: [app name]
    I/flutter ( 4832): upgrader: package info version: 1.0.12
    I/flutter ( 4832): upgrader: countryCode: US
    I/flutter ( 4832): upgrader: languageCode: en
    I/flutter ( 4832): upgrader.ITunesResults.version: RangeError (index): Invalid value: Valid value range is empty: 0
    I/flutter ( 4832): upgrader.ITunesResults.trackViewUrl: RangeError (index): Invalid value: Valid value range is empty: 0
    I/flutter ( 4832): upgrader.ITunesResults.releaseNotes: RangeError (index): Invalid value: Valid value range is empty: 0
    I/flutter ( 4832): upgrader.ITunesResults.description: RangeError (index): Invalid value: Valid value range is empty: 0
    I/flutter ( 4832): upgrader: blocked: false
    I/flutter ( 4832): upgrader: debugDisplayAlways: false
    I/flutter ( 4832): upgrader: debugDisplayOnce: false
    I/flutter ( 4832): upgrader: hasAlerted: false
    I/flutter ( 4832): upgrader: appStoreVersion: null
    I/flutter ( 4832): upgrader: installedVersion: 1.0.12
    I/flutter ( 4832): upgrader: minAppVersion: null
    I/flutter ( 4832): upgrader: isUpdateAvailable: false
    I/flutter ( 4832): upgrader: shouldDisplayUpgrade: false
    I/flutter ( 4832): upgrader: shouldDisplayReleaseNotes: false
    

    I have also tried manually querying iTunes using the (correct) bundleId, and this seems to give a good response:

    PS D:\***> dart .\bin\itunes_lookup.dart bundleid=com.[company].xxxYyyZzz
    upgrader: download: https://itunes.apple.com/lookup?bundleId=com.[company].xxxYyyZzz&country=US&_cb=1671798673978320
    upgrader: response statusCode: 200
    itunes_lookup bundleId: com.[company].xxxYyyZzz
    itunes_lookup description: ***
    itunes_lookup minAppVersion: null
    itunes_lookup releaseNotes: ***
    itunes_lookup trackViewUrl: https://apps.apple.com/us/app/xxx-yyy-zzz/id6444800056?uo=4
    itunes_lookup version: 1.0.12
    itunes_lookup all results:
    {resultCount: 1, results: [{screenshotUrls: [https://is4-ssl.mzstatic.com/image/thumb/PurpleSource112/v4/8a/0e/e0/8a0ee00f-7bc6-c054-0604-3e37d2517ed3/a27ea688-ee0d-4b1f-a251-9bc7b7b09dea_Simulator_Screen_Shot_-_iPhone_8_Plus_-_2022-11-30_at_14.03.56.png/392x696bb.png, https://is4-ssl.mzstatic.com/image/thumb/PurpleSource122/v4/41/9d/09/419d095a-41e9-8dcb-562e-1ffffbbc1fe3/029ffcac-6251-46fa-907b-1ebc1a3c76f1_Simulator_Screen_Shot_-_iPhone_8_Plus_-_2022-11-30_at_14.17.13.png/392x696bb.png, https://is1-ssl.mzstatic.com/image/thumb/PurpleSource112/v4/44/c7/c3/44c7c365-514a-0cde-6b8a-0501e3e73a95/2a2a3855-6eeb-4f6f-a9a4-317f1aee3ca4_Simulator_Screen_Shot_-_iPhone_8_Plus_-_2022-11-30_at_14.05.11.png/392x696bb.png], isGameCenterEnabled: false, features: [iosUniversal], advisories: [], supportedDevices: [iPhone5s-iPhone5s, iPadAir-iPadAir, iPadAirCellular-iPadAirCellular, iPadMiniRetina-iPadMiniRetina, iPadMiniRetinaCellular-iPadMiniRetinaCellular, iPhone6-iPhone6, iPhone6Plus-iPhone6Plus, iPadAir2-iPadAir2, iPadAir2Cellular-iPadAir2Cellular, iPadMini3-iPadMini3, iPadMini3Cellular-iPadMini3Cellular, iPodTouchSixthGen-iPodTouchSixthGen, iPhone6s-iPhone6s, iPhone6sPlus-iPhone6sPlus, iPadMini4-iPadMini4, iPadMini4Cellular-iPadMini4Cellular, iPadPro-iPadPro, iPadProCellular-iPadProCellular, iPadPro97-iPadPro97, iPadPro97Cellular-iPadPro97Cellular, iPhoneSE-iPhoneSE, iPhone7-iPhone7, iPhone7Plus-iPhone7Plus, iPad611-iPad611, iPad612-iPad612, iPad71-iPad71, iPad72-iPad72, iPad73-iPad73, iPad74-iPad74, iPhone8-iPhone8, iPhone8Plus-iPhone8Plus, iPhoneX-iPhoneX, iPad75-iPad75, iPad76-iPad76, iPhoneXS-iPhoneXS, iPhoneXSMax-iPhoneXSMax, iPhoneXR-iPhoneXR, iPad812-iPad812, iPad834-iPad834, iPad856-iPad856, iPad878-iPad878, iPadMini5-iPadMini5, iPadMini5Cellular-iPadMini5Cellular, iPadAir3-iPadAir3, iPadAir3Cellular-iPadAir3Cellular, iPodTouchSeventhGen-iPodTouchSeventhGen, iPhone11-iPhone11, iPhone11Pro-iPhone11Pro, iPadSeventhGen-iPadSeventhGen, iPadSeventhGenCellular-iPadSeventhGenCellular, iPhone11ProMax-iPhone11ProMax, iPhoneSESecondGen-iPhoneSESecondGen, iPadProSecondGen-iPadProSecondGen, iPadProSecondGenCellular-iPadProSecondGenCellular, iPadProFourthGen-iPadProFourthGen, iPadProFourthGenCellular-iPadProFourthGenCellular, iPhone12Mini-iPhone12Mini, iPhone12-iPhone12, iPhone12Pro-iPhone12Pro, iPhone12ProMax-iPhone12ProMax, iPadAir4-iPadAir4, iPadAir4Cellular-iPadAir4Cellular, iPadEighthGen-iPadEighthGen, iPadEighthGenCellular-iPadEighthGenCellular, iPadProThirdGen-iPadProThirdGen, iPadProThirdGenCellular-iPadProThirdGenCellular, iPadProFifthGen-iPadProFifthGen, iPadProFifthGenCellular-iPadProFifthGenCellular, iPhone13Pro-iPhone13Pro, iPhone13ProMax-iPhone13ProMax, iPhone13Mini-iPhone13Mini, iPhone13-iPhone13, iPadMiniSixthGen-iPadMiniSixthGen, iPadMiniSixthGenCellular-iPadMiniSixthGenCellular, iPadNinthGen-iPadNinthGen, iPadNinthGenCellular-iPadNinthGenCellular, iPhoneSEThirdGen-iPhoneSEThirdGen, iPadAirFifthGen-iPadAirFifthGen, iPadAirFifthGenCellular-iPadAirFifthGenCellular, iPhone14-iPhone14, iPhone14Plus-iPhone14Plus, iPhone14Pro-iPhone14Pro, iPhone14ProMax-iPhone14ProMax, iPadTenthGen-iPadTenthGen, iPadTenthGenCellular-iPadTenthGenCellular, iPadPro11FourthGen-iPadPro11FourthGen, iPadPro11FourthGenCellular-iPadPro11FourthGenCellular, iPadProSixthGen-iPadProSixthGen, iPadProSixthGenCellular-iPadProSixthGenCellular], kind: software, ipadScreenshotUrls: [https://is2-ssl.mzstatic.com/image/thumb/PurpleSource112/v4/3d/ac/17/3dac173c-7761-2a9e-a2cf-6efd57d8320a/e9f00ead-1bea-43f0-8165-33fbb6bdfa83_Simulator_Screen_Shot_-_iPad_Pro__U002812.9-inch_U0029__U00286th_generation_U0029_-_2022-11-30_at_14.08.24.png/576x768bb.png, 
    https://is3-ssl.mzstatic.com/image/thumb/PurpleSource112/v4/47/c1/ed/47c1ed30-28fc-bde3-b8a1-079e0733cfd3/56e41b2a-b9b1-4b02-b0bd-328eb4c55d04_Simulator_Screen_Shot_-_iPad_Pro__U002812.9-inch_U0029__U00286th_generation_U0029_-_2022-11-30_at_14.08.16.png/576x768bb.png, https://is3-ssl.mzstatic.com/image/thumb/PurpleSource112/v4/c1/0d/22/c10d2202-0091-38ff-0bf9-2d48691fde76/ec1365d5-e3c6-432f-8f1c-c0dab7374c4e_Simulator_Screen_Shot_-_iPad_Pro__U002812.9-inch_U0029__U00286th_generation_U0029_-_2022-11-30_at_14.07.59.png/576x768bb.png], appletvScreenshotUrls: [], artworkUrl60: https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/fa/e1/da/fae1da16-ec5a-58d0-5a33-cfc138767ef7/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/60x60bb.jpg, artworkUrl512: https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/fa/e1/da/fae1da16-ec5a-58d0-5a33-cfc138767ef7/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/512x512bb.jpg, artworkUrl100: https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/fa/e1/da/fae1da16-ec5a-58d0-5a33-cfc138767ef7/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/100x100bb.jpg, artistViewUrl: https://apps.apple.com/us/developer/[company]/id1656936717?uo=4, trackCensoredName: ***, minimumOsVersion: 12.0, languageCodesISO2A: [EN], fileSizeBytes: 32304128, formattedPrice: Free, contentAdvisoryRating: 4+, averageUserRatingForCurrentVersion: 0, userRatingCountForCurrentVersion: 0, averageUserRating: 0, trackViewUrl: https://apps.apple.com/us/app/xxx-yyy-zzz/id6444800056?uo=4, trackContentRating: 4+, currentVersionReleaseDate: 2022-12-22T17:08:52Z, releaseNotes: Added two colour schemes with dark mode support.
    Dark and light modes match global device settings.
    
    Fixed launcher icon appearance on iOS., artistId: 1656936717, artistName: [company], genres: [Business, Utilities], price: 0.0, description: ***, genreIds: [6000, 6002], primaryGenreName: Business, primaryGenreId: 6000, bundleId: com.[company].xxxYyyZzz, sellerName: [company], isVppDeviceBasedLicensingEnabled: true, releaseDate: 2022-12-01T08:00:00Z, trackId: 6444800056, trackName: [app name], version: 1.0.12, wrapperType: software, currency: USD, userRatingCount: 0}]}
    

    Relevant project settings

    Our Upgrader instance is set up with the following values:

    final Upgrader upgrader = Upgrader(
        countryCode: 'US',
        dialogStyle: !kIsWeb && Platform.isIOS
            ? UpgradeDialogStyle.cupertino
            : UpgradeDialogStyle.material,
        durationUntilAlertAgain: const Duration(days: 3),
      );
    

    Our project's upgrader dependency is as follows:

    dependencies:
      flutter:
        sdk: flutter
      ...
      upgrader: ^5.0.0
    

    Am I right in assuming that the incorrect bundleId is being used to query the iTunes store?

    And if so, would an easy fix be to let us explicitly specify which bundleId to ask for inside of the Upgrader constructor?

    Thank you for your time.

    opened by proxy2501 0
  • Google Play description not working

    Google Play description not working

    Currently using upgrader: ^4.11.1. I cannot update it since a package is interfering with another package. I put this in my Google Play description: image

    This is my code:

    home: UpgradeAlert(
        upgrader: Upgrader(
            showLater: true,
            showIgnore: false,
            //debugDisplayAlways: true,
            messages: DutchUpgrader()),
        child: AuthenticationWrapper()),
    

    My app version is currently 0.2.4.

    I'm getting this error: image

    When I continue in the debugger I get to this: image So weirdly enough it is taking the category tag as version.

    Also getting this exception: image

    And this: image

    Can anyone help me solve this?

    opened by Jip1912 0
  • Do critical update if current app version is smaller than latest critical update version

    Do critical update if current app version is smaller than latest critical update version

    This PR fixes an issue when the appcast contains both critical updates and regular updates, and critical update version is lower than the regular update version, Apps lower than critical version fails to act as a critical update. i.e. Suppose critical update version is 0.13.0, regular update version is 0.14.0. If app version is 0.12.0, it offers update to 0.14.0 but the Ignore / Later buttons still show. After this PR, upgrader should offer update to 0.14.0 and do not show the Ignore / Later buttons.

    opened by luiges90 0
  • Version solving failed

    Version solving failed

    On pub get following error is coming:

    Running "flutter pub get" in jaldi_mobile_v2...                 
    
    Because upgrader >=5.0.0-alpha.1 depends on version ^3.0.2 and jaldi_mobile_v2 depends on version ^2.0.0, upgrader >=5.0.0-alpha.1 is forbidden.
    So, because jaldi_mobile_v2 depends on upgrader ^5.0.0, version solving failed.
    pub get failed (1; So, because jaldi_mobile_v2 depends on upgrader ^5.0.0, version solving failed.)
    
    Process finished with exit code 1
    

    In pubspec.yaml

    environment:
      sdk: '>=2.18.0 <3.0.0'
    
    upgrader: ^5.0.0
    

    Flutter 3.3.10

    Would appreciate earliest response!

    opened by rmahmadkhan 0
Owner
Larry Aasen
Lead Software Engineer @ Capital One, Flutter enthusiast.
Larry Aasen
Check if your Flutter app has a newer version.

Flutter NeoVersion Check if a new version of a Flutter app is available on the app stores. The plugin uses the Peek-An-App API to get information abou

József Sallai 3 Oct 6, 2022
[Flutter package] An easy and quick way to check if the local app is updated with the same version in their respective stores (Play Store / Apple Store ).

Retrieve version and url for local app update against store app Android and iOS Features Using as reference packages like in_app_update , version_chec

Kauê Murakami 11 Nov 9, 2022
A lightweight flutter plugin to check if your app is up-to-date on Google Play Store or Apple App Store

App Version Checker this package is used to check if your app has a new version on playstore or apple app store. or you can even check what is the lat

Iheb Briki 6 Dec 14, 2022
Shoes-Store-App-UI-Flutter - Beautiful Shoes Store App UI with support for dark and light mode

Flutter Shoes Store App UI with support for dark and light mode. Flutter 2.8.1 N

Jakub Sobański 4 Nov 23, 2022
Ali Türkay AVCI 1 Jan 20, 2022
Breathe is a mental health blogging app where users can join communities of doctors and other users from around the world and both share their problems as well as lend a ear to and help others

?????????????? ?????????????? In a condensed, suffocating society you can feel closed off, when you can't process your emotions and are going through

Soham Sen 3 May 16, 2022
Github-search - Allows users to search users on github Uses flutter

Github Search Github Search is a cross-platform mobile application powered by Flutter Framework and Github API. The application was built with simplic

Saul 3 Sep 13, 2022
A flutter/dart package that allows developer to develop shiSock client for there application.

A package which allow developers to develop the shiSock client for the there flutter android app. Using flutter-shiSock developers can develop a chat application very easily. It can also be used in app in which we need real time data flow.

shiSock 0 Apr 7, 2022
A cross-platform Flutter home workout app that respects your privacy. THIS IS A GITLAB MIRROR, file issues and contribute there.

Feeel Feeel is an open-source workout app for doing simple at-home exercises. This is a rewrite of the original app in Flutter, to make development ea

null 27 Dec 26, 2022
Dart and Flutter sealed class generator and annotations, with match methods and other utilities. There is also super_enum compatible API.

Dart Sealed Class Generator Generate sealed class hierarchy for Dart and Flutter. Features Generate sealed class with abstract super type and data sub

6thSolution 15 Jan 2, 2023
A sample app of using the image_picker + path_provider and permission_handler package to request permission and store photos on mobile

image_picker_example A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you sta

iang12 4 Apr 19, 2022
A builder for extracting a package version into code

Include the version of your package in our source code. Add build_version to pubspec.yaml. Also make sure there is a version field. name: my_pkg versi

Kevin Moore 39 Dec 7, 2022
Extract pubspec details (such as package version, author and description) into Dart code.

build_pubspec This package helps you convert fields from your pubspec.yaml file into Dart code. Based on the fields in your pubspec, this package will

dartside.dev 9 Jul 15, 2021
Lite version of smart_select package, zero dependencies, an easy way to provide a single or multiple choice chips.

Lite version of smart_select package, zero dependencies, an easy way to provide a single or multiple choice chips. What's New in Version 2.x.x Added p

Irfan Vigma Taufik 97 Dec 15, 2022
A Flutter package that allows Android users to press the back-button twice to close the app.

double_back_to_close_app A Flutter package that allows Android users to press the back-button twice to close the app. Usage Inside a Scaffold that wra

Hugo Passos 57 Oct 10, 2022