was 更新应用程序_更新应用程式

was 更新应用程序

Welcome to this tutorial for adding update app to your flutter application

欢迎使用本教程,向您的flutter应用程序添加更新应用程序

You can connect with me on Instagram:

您可以在Instagram上与我联系:

Enough! Lets start with it.

足够! 让我们开始吧。

让我们从看到最终目标开始- (Let’s start by seeing our end goal-)

For IOS-

对于IOS-

Image for post
Image for post

For Android-

对于Android-

Image for post
Image for post
Image for post

Similar for IOS.

与IOS类似。

分解 (Breaking down)

  • We have two types of update dialogs: Optional update and Required update. Based on your preference you can keep one or both of them.

    我们有两种类型的更新对话框: 可选 更新必需 更新 。 您可以根据自己的喜好保留其中一个或两个。

For both Optional and Required update dialog:

对于“ 可选”和“必需”更新对话框:

  • If user clicks on Update now, we will redirect the user to the PlayStore or AppStore page of our app.

    如果用户点击 更新,现在 ,我们将用户重定向到我们的应用程序的Play商店中或AppStore的页面。

For Optional update dialog:

对于“ 可选更新”对话框:

  • If user clicks on Later, close the dialog and show it next time user opens the app. (Again, you can change it based on preference, maybe change the option to remind me tomorrow)

    如果用户单击“稍后” ,请关闭对话框,并在下次用户打开应用程序时显示该对话框。 (同样,您可以根据喜好进行更改,也可以更改选项以提醒我明天)

  • For Android, If user selects Never ask again then disable Update now. Then if user clicks on Later, do not show the update dialog next time user opens app.

    对于Android,如果用户选择“ 不再询问”, 禁用立即更新 。 然后,如果用户单击“稍后” ,则下次用户打开应用程序时不显示更新对话框。

  • For IOS, If user clicks on Don’t ask me again then close the dialog and do not show the update dialog next time user opens app.

    对于IOS,如果用户单击“ 不要再问我”, 关闭对话框, 下次用户打开应用程序时不显示更新对话框

Key points:

关键点:

  • User can dismiss the optional update dialog by clicking outside the dialog box. In this case do not show again state will not be stored locally.

    用户可以 通过在对话框外部单击 来关闭可选的更新对话框。 在这种情况下,不再显示状态将不会存储在本地。

  • User cannot dismiss the required update dialog by clicking outside the clicking outside the dialog box.

    用户无法通过单击对话框外部的单击来关闭所需的更新对话框。

Let me show you something and you guess the difference.

让我给你看一些东西, 你会猜出区别

Image for post

所以这里- (So here is it-)

  • In the first one, we were logged in successfully and navigated to the main screen. In the second one, we were not logged in and stayed at the login screen.

    在第一个中,我们已成功登录并导航到主屏幕。 在第二个中 我们尚未登录,而是停留在登录屏幕上。

  • What’s interesting in this is that we were able to see the same dialog on both screens. This is not as easy it sounds like and it was a nightmare to get this done.

    有趣的是,我们能够在两个屏幕上看到相同的对话框。 这听起来不那么容易,完成这项工作真是一场噩梦。

But what I wanted exactly?

但是我到底想要什么?

When user opens the app, we check-

当用户打开应用程序时,我们会检查-

  1. Latest app version- retrieved from the server

    最新的应用程序版本-从服务器检索

  2. Current app version

    当前应用版本

  3. Minimum app version- retrieved from the server

    最低应用版本-从服务器检索

If the current app version is less than minimum app version-

如果当前应用版本低于最低应用版本,

We show the required update dialog and force the user to update. Users who have disabled to see update will still see it.

我们显示所需的更新对话框,并强制用户进行更新。 禁用查看更新的用户仍会看到它。

In case the minimum app version is satisfied, but the current version is less than latest app version.

如果满足最低应用程序版本,但当前版本小于最新应用程序版本。

If dialog not disabled, we show the optional update dialog and do not force the user to update. We also give user the option to not see the dialog again.

如果未禁用对话框,我们将显示可选的更新对话框,并且不强制用户进行更新。 我们还为用户提供了一个选项,使其不再显示该对话框。

这是最重要的部分,也是我决定撰写此博客的原因- (Here is the most important part and the reason I decided to write this blog-)

The app version checking and showing the dialog should be done at a single place. We should be able to show the user the update dialog, no matter which screen the user is on.

检查并显示对话框的应用程序版本应在一个地方完成。 无论用户在哪个屏幕上,我们都应该能够向用户显示更新对话框。

In simple words, here is why it is difficult-

简单来说,这就是为什么很难-

  1. To show a dialog, we need the context of the active screen.

    要显示对话框,我们需要活动屏幕的上下文。
  2. As we navigate the current active context keeps on changing.

    在导航时,当前活动上下文不断变化。
  3. Therefore we will need to add it at many places and increase complexity.

    因此,我们将需要在许多地方添加它并增加复杂性。

But we need to keep it simple.

但是我们需要保持简单。

让我们解决这个问题 (Lets solve this)

I have made it simple for you so you just have to copy and paste most of the code.

我为您简化了操作,因此您只需复制并粘贴大部分代码。

import 'dart:io';


import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:package_info/package_info.dart';
import 'package:parse_server_sdk/parse_server_sdk.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:talkfootball/constants.dart';
import 'package:talkfootball/dialogs/do_not_ask_again_dialog.dart';
import 'package:talkfootball/models/app_version.dart';


class UpdateApp extends StatefulWidget {
  final Widget child;


  UpdateApp({this.child});


  @override
  _UpdateAppState createState() => _UpdateAppState();
}


class _UpdateAppState extends State<UpdateApp> {
  @override
  void initState() {
    super.initState();


    checkLatestVersion(context);
  }


  checkLatestVersion(context) async {
    await Future.delayed(Duration(seconds: 5));
    
    //Add query here to get the minimum and latest app version
    
    //Change
    //Here is a sample query to ParseServer(open-source NodeJs server with MongoDB database)
    var queryBuilder = QueryBuilder<AppVersion>(AppVersion())
      ..orderByDescending("publishDate")
      ..setLimit(1);


    var response = await queryBuilder.query();


    if (response.success) {
      //Change
      //Parse the result here to get the info
      AppVersion appVersion = response.results[0] as AppVersion;
      Version minAppVersion = Version.parse(appVersion.minAppVersion);
      Version latestAppVersion = Version.parse(appVersion.version);
      
      PackageInfo packageInfo = await PackageInfo.fromPlatform();
      Version currentVersion = Version.parse(packageInfo.version);


      if (minAppVersion > currentVersion) {
        _showCompulsoryUpdateDialog(
          context,
          "Please update the app to continue\n${appVersion.about ?? ""}",
        );
      } else if (latestAppVersion > currentVersion) {
        SharedPreferences sharedPreferences =
            await SharedPreferences.getInstance();


        bool showUpdates = false;
        showUpdates = sharedPreferences.getBool(kUpdateDialogKeyName);
        if (showUpdates != null && showUpdates == false) {
          return;
        }


        _showOptionalUpdateDialog(
          context,
          "A newer version of the app is available\n${appVersion.about ?? ""}",
        );
        print('Update available');
      } else {
        print('App is up to date');
      }
    }
  }


  _showOptionalUpdateDialog(context, String message) async {
    await showDialog<String>(
      context: context,
      barrierDismissible: true,
      builder: (BuildContext context) {
        String title = "App Update Available";
        String btnLabel = "Update Now";
        String btnLabelCancel = "Later";
        String btnLabelDontAskAgain = "Don't ask me again";
        return DoNotAskAgainDialog(
          kUpdateDialogKeyName,
          title,
          message,
          btnLabel,
          btnLabelCancel,
          _onUpdateNowClicked,
          doNotAskAgainText:
              Platform.isIOS ? btnLabelDontAskAgain : 'Never ask again',
        );
      },
    );
  }


  _onUpdateNowClicked() {
    print('On update app clicked');
  }


  _showCompulsoryUpdateDialog(context, String message) async {
    await showDialog<String>(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        String title = "App Update Available";
        String btnLabel = "Update Now";
        return Platform.isIOS
            ? new CupertinoAlertDialog(
                title: Text(title),
                content: Text(message),
                actions: <Widget>[
                  CupertinoDialogAction(
                    child: Text(
                      btnLabel,
                    ),
                    isDefaultAction: true,
                    onPressed: _onUpdateNowClicked,
                  ),
                ],
              )
            : new AlertDialog(
                title: Text(
                  title,
                  style: TextStyle(fontSize: 22),
                ),
                content: Text(message),
                actions: <Widget>[
                  FlatButton(
                    child: Text(btnLabel),
                    onPressed: _onUpdateNowClicked,
                  ),
                ],
              );
      },
    );
  }


  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}
import 'dart:io';


import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:talkfootball/constants.dart';


class DoNotAskAgainDialog extends StatefulWidget {
  final String title, subTitle, positiveButtonText, negativeButtonText;
  final Function onPositiveButtonClicked;
  final String doNotAskAgainText;
  final String dialogKeyName;


  DoNotAskAgainDialog(
    this.dialogKeyName,
    this.title,
    this.subTitle,
    this.positiveButtonText,
    this.negativeButtonText,
    this.onPositiveButtonClicked, {
    this.doNotAskAgainText = 'Never ask again',
  });


  @override
  _DoNotAskAgainDialogState createState() => _DoNotAskAgainDialogState();
}


class _DoNotAskAgainDialogState extends State<DoNotAskAgainDialog> {
  bool doNotAskAgain = false;


  _updateDoNotShowAgain() async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    await sharedPreferences.setBool(kUpdateDialogKeyName, false);
  }


  @override
  Widget build(BuildContext context) {
    if (Platform.isIOS) {
      return CupertinoAlertDialog(
        title: Text(widget.title),
        content: Text(widget.subTitle),
        actions: <Widget>[
          CupertinoDialogAction(
            child: Text(
              widget.positiveButtonText,
            ),
            onPressed: widget.onPositiveButtonClicked,
          ),
          CupertinoDialogAction(
            child: Text(
              widget.doNotAskAgainText,
            ),
            onPressed: () {
              Navigator.pop(context);
              _updateDoNotShowAgain();
            },
          ),
          CupertinoDialogAction(
            child: Text(
              widget.negativeButtonText,
            ),
            onPressed: () => Navigator.pop(context),
          ),
        ],
      );
    }
    return AlertDialog(
      title: Text(
        widget.title,
        style: TextStyle(fontSize: 24),
      ),
      content: FittedBox(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(widget.subTitle),
            Row(
              mainAxisAlignment: MainAxisAlignment.start,
              children: <Widget>[
                SizedBox(
                  width: 24,
                  height: 24,
                  child: Checkbox(
                    value: doNotAskAgain,
                    onChanged: (val) {
                      setState(() {
                        doNotAskAgain = val;
                      });
                    },
                  ),
                ),
                SizedBox(width: 8),
                GestureDetector(
                  onTap: () {
                    setState(() {
                      doNotAskAgain = doNotAskAgain == false;
                    });
                  },
                  child: Text(
                    widget.doNotAskAgainText,
                    style: TextStyle(color: kDarkGray),
                  ),
                ),
              ],
            )
          ],
        ),
      ),
      actions: <Widget>[
        FlatButton(
          child: Text(widget.positiveButtonText),
          onPressed: doNotAskAgain ? null : widget.onPositiveButtonClicked,
        ),
        FlatButton(
          child: Text(
            widget.negativeButtonText,
            style: TextStyle(color: Colors.red),
          ),
          onPressed: () async {
            Navigator.pop(context);
            if (doNotAskAgain) {
              _updateDoNotShowAgain();
            }
          },
        ),
      ],
    );
  }
}

Here is how the data is structured-

数据的结构如下-

Image for post

What you have to do?

你要做什么

  1. Add some libraries to pubspec.yaml

    将一些库添加到pubspec.yaml

Use: Locally store do not show info.

使用:在本地存储不显示信息。

Use: To parse version string from server and compare them easily.

使用:从服务器解析版本字符串并轻松比较它们。

Use: To get current app version

用途:获取当前应用程序版本

UPDATE: Use can also use another package for in-app upgrade in Android.

更新:使用还可以使用另一个软件包在Android中进行应用内升级。

2. Copy and paste both the above code files to your project.

2.将以上两个代码文件复制并粘贴到您的项目中。

3. Make changes to the first code file

3.更改第一个代码文件

You need to make two changes, based the server you are using.

您需要根据所使用的服务器进行两项更改。

  1. Change the query to get the latest and minimum app version.

    更改查询以获取最新和最低应用程序版本。
  2. Get the response and parse it to Version type for easy comparison.

    获取响应并将其解析为“ 版本”类型以便于比较。

After making the above changes, add this to MaterialApp.

完成上述更改后,将其添加到MaterialApp。

child: MaterialApp(
builder: (context, widget) => Navigator(
onGenerateRoute: (settings) => MaterialPageRoute(
builder: (context) => UpdateApp(
child: widget,
),
),
),

Read more about the builder property here-

在这里阅读更多有关builder属性的信息-

让我们现在检查输出- (Let’s check the output now-)

Image for post

让我们更改最低应用版本 (Lets change the minimum app version)

Image for post

现在的输出- (The output now-)

Image for post

As you can see, now the user is forced to update the app and can no use the app.

如您所见,现在用户被迫更新应用程序,并且无法使用该应用程序。

To open Play store or App store page on update click. Use url_launcher.

要在更新时打开Play商店或App商店页面,请单击。 使用url_launcher。

Its done :)

完成 :)

Thank you for staying

谢谢你留下来

更多颤振微博 (More flutter spinner blogs)

I will be posting more about flutter, so stay tuned :)

我将发布更多有关颤振的信息,敬请期待:)

翻译自: https://medium.com/swlh/update-app-flutter-402c528235e4

was 更新应用程序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值