Flutter之自动更新(自带源码 包看包会)

2023-11-06

Flutter做的App怎么自动更新呢 首先要用到两个依赖一个叫update_app
另外一个叫package_info
还有一个叫Dio
一个是用来下载App的 一个是用来获取当前App的版本信息的 一个是用来网络链接的

flutter pub add update_app
flutter pub add package_info
flutter pub add dio

然后上代码

import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:update_app/bean/download_process.dart';

import 'package:update_app/update_app.dart';

void main() => runApp(MyApp());
//为什么我要先用StatelessWidget  再用StatefulWidget 的呢  因为如果不这样 会报错误 找不到父类的祖宗Context

class MyApp extends StatelessWidget {
  @override
  _MyAppState createState() => _MyAppState();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(), // here pass parameter
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<HomePage> {
  //定时更新进度
  Timer? timer;

  //下载进度
  double downloadProcess = 0;

  //下载状态
  String downloadStatus = "";

  @override
  void initState() {
    super.initState();
       SchedulerBinding.instance!.addPostFrameCallback((_) => {ifUpdate(context)});
  }

  Future<void> ifUpdate(BuildContext buildContext) async {
    var s = "http://你的后端链接获取你设置App的版本号";
    var dio = Dio();
    final response = await dio.get(s);
    print(response.data);
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    //如果你设置的版本号 于你本机上的App的版本号 不一致 弹出下载框
    if (response.data != packageInfo.version) {
      print(packageInfo.version);
      updatedialog.showUpdateDialog(buildContext, '有新版本发布\n2.请更新', false);
    }
  }

  @override
  Widget build(BuildContext? context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Update app'),
        ),
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Container(
                padding: EdgeInsets.all(16),
                width: 200,
                height: 200,
                child: CircularProgressIndicator(
                  value: downloadProcess,
                  strokeWidth: 10,
                ),
              ),
              Text("Download status: $downloadStatus"),
              Text("Please replace the download url with your own address"),
            ],
          ),
        ),
        bottomNavigationBar: Container(
            padding: EdgeInsets.all(20),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  '点击右下角的下载按钮下载!',
                  style: TextStyle(color: Theme.of(context!).primaryColor),
                ),
              ],
            )),
        floatingActionButton: FloatingActionButton(
          onPressed: download,
          child: Icon(Icons.file_download),
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
      ),
    );
  }

  @override
  void dispose() {
    timer?.cancel();
    super.dispose();
  }

  void download() async {
    var downloadId = await UpdateApp.updateApp(
        url:
            "https://你app的下载地址",
        );

    //本地已有一样的apk, 下载成功
    if (downloadId == 0) {
      setState(() {
        downloadProcess = 1;
        downloadStatus = ProcessState.STATUS_SUCCESSFUL.toString();
      });
      return;
    }

    //出现了错误, 下载失败
    if (downloadId == -1) {
      setState(() {
        downloadProcess = 1;
        downloadStatus = ProcessState.STATUS_FAILED.toString();
      });
      return;
    }

    //正在下载文件
    timer = Timer.periodic(Duration(milliseconds: 100), (timer) async {
      var process = await UpdateApp.downloadProcess(downloadId: downloadId);
      //更新界面状态
      setState(() {
        downloadProcess = process.current / process.count;
        downloadStatus = process.status.toString();
      });

      if (process.status == ProcessState.STATUS_SUCCESSFUL ||
          process.status == ProcessState.STATUS_FAILED) {
        //如果已经下载成功, 取消计时
        timer.cancel();
      }
    });
  }
}

下面是弹窗widgt 你们可以自己修改 或者自己写一个

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:translateapp/CommonUtils/toast_helper.dart';
import 'package:translateapp/main.dart';

///update by zah
///on 2023/1/7
///description:版本更新提示弹窗
class updatedialog extends Dialog {
  final String upDateContent = "";
  final bool isForce = false;

  updatedialog({Key? key, required String upDateContent, required bool isForce})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              color: Colors.blue,
              /*         decoration: BoxDecoration(
                color: backgroundColor,
                border: Border.all(color: Colors.white60),
                shape: BoxShape.circle,
              ),*/
              width: MediaQuery.of(context).size.width -
                  (MediaQuery.of(context).size.width / 4),
              /* height: ,*/
              child: Stack(
                children: <Widget>[
/*                Image.asset(
                    AssetsUtil.getImagePath(
                        imageName: 'bg_update', suffix: 'png'),
                    fit: BoxFit.cover,
                  ),*/
                  Container(
                    width: double.infinity,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Container(
                          margin: const EdgeInsets.only(top: 10),
                          child: const Text('发现新版本',
                              style: TextStyle(
                                  fontSize: 14,
                                  color: Colors.white,
                                  decoration: TextDecoration.none)),
                        ),
                        Text(upDateContent,
                            style: TextStyle(
                                fontSize: 14,
                                color: Colors.black54,
                                decoration: TextDecoration.none)),
                        Container(
                          width: 100,
                          height: 100,
                          margin: EdgeInsets.only(bottom: 10),
                          child: RaisedButton(
                              color: Colors.red,
                              shape: StadiumBorder(),
                              child: Text(
                                '立即更新',
                                style: TextStyle(
                                    fontSize: 14, color: Colors.white),
                              ),
                              onPressed: () {
                                HomePage home = new HomePage();
                                home.createState().download();
                                Navigator.pop(context);
                              }),
                        )
                      ],
                    ),
                  ),
                ],
              ),
            ),
            GestureDetector(
              onTap: () {
                exit(0);
              },
              child: Offstage(
                offstage: isForce,
                child: Container(
                  margin: EdgeInsets.only(top: 10),
                  child: Icon(
                    Icons.cancel,
                    size: 54,
                    color: Colors.white,
                  ),
                  /*    Image.asset(
                      AssetsUtil.getImagePath(
                          imageName: 'ic_update_close', suffix: 'png'),
                      width:100 ,
                      height: ,100
                    )*/
                ),
              ),
            )
          ],
        ),
      ),
    );
  }

  static showUpdateDialog(
      BuildContext context, String mUpdateContent, bool mIsForce) {
    return showDialog(
        barrierDismissible: false,
        context: context,
        builder: (BuildContext context) {
          return WillPopScope(
              child: updatedialog(
                  upDateContent: mUpdateContent, isForce: mIsForce),
              onWillPop: _onWillPop);
        });
  }

  static Future<bool> _onWillPop() async {
    return false;
  }
}

效果如下
在这里插入图片描述
对了 最后 还有一点 下载的文件 如果它不安装 直接把它下载的文件删掉 由于依赖没有这个方法 我自己加了下去 就一句代码而已
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter之自动更新(自带源码 包看包会) 的相关文章

随机推荐

  • 列存储与行存储的区别

    写入 行存储的写入是一次完成 数据的完整性因此可以确定 列存储需要把一行记录拆分成单列保存 写入次数明显比行存储多 行存储在写入上占有很大的优势 数据修改 行存储是在指定位置写入一次 列存储是将磁盘定位到多个列上分别写入 行存储在数据修改也
  • 从Java到Go:实现多语言翻译服务的高性能解决方案

    本文将深入探讨如何使用Go语言 Golang 开发多语言翻译服务 我们将重点介绍从Java到Go的过渡 并提供详细的代码示例以帮助您快速上手 目录 1 为什么选择Go 2 Go语言基础 2 1 语法结构 2 2 变量 常量和类型
  • java 类增强机制

    前言 对类的增强有多少种方式 我们首先想一下一个类的生命周期 从编码到程序运行结束 对类的增强 目的是为了在使用的时候能够在类原有的行为上进行增强 所以编码一直到使用中的几乎每个环节都可以对类进行增强 主要有以下几种方式 静态代理 编译期织
  • 遇到文件误删情况,使用EasyRecovery快速恢复

    当我们不小心将文件误删了 还有办法恢复吗 可能很多朋友认为这是不可能的 一个连在电脑中都无法找到痕迹的文件 我们要怎么找到它呢 其实也不是不可能 借助专业的数据恢复软件EasyRecovery就可以帮你恢复彻底删除的文件 下面就一起来学习具
  • 【Netty】NIO基础(三大组件、文件编程)

    文章目录 三大组件 Channel Buffer Selector ByteBuffer ByteBuffer 正确使用姿势 ByteBuffer 内部结构 ByteBuffer 常见方法 分配空间 向 buffer 写入数据 从 buff
  • k-近邻算法的Python实现

    k 近邻算法的Python实现 一 概述 k 近邻算法 k Nearest Neighbour algorithm 又称为KNN算法 是数据挖掘技术中原理最简单的算法 KNN的工作原理 给定一个已知标签类别的训练数据集 输入没有标签的新数据
  • Netty网络编程框架

    一 简介 Netty是由JBOSS提供的一个java开源框架 Netty提供异步的 事件驱动的网络应用程序框架和工具 用以快速开发高性能 高可靠性的网络服务器和客户端程序 也就是说 Netty 是一个基于NIO的客户 服务器端编程框架 使用
  • B3:多个if(c++)

    做纸箱最少需要多少面积的硬纸板 题目描述 请问做一个尺寸为a b c 单位 厘米 的开口的立方体纸箱 只有一个面是不需要封的 其余5个面都需要封起来 这样算开口的 最少需要多少平方厘米的纸 6 1 6 输入 三个整数 abc 输出 制作该纸
  • Javascript中的every()与some()的区别和应用

    every 定义和用法 every 方法用于检测数组所有元素是否都符合指定条件 通过函数提供 every 方法使用指定函数检测数组中的所有元素 如果数组中检测到有一个元素不满足 则整个表达式返回 false 且剩余的元素不会再进行检测 如果
  • 遗传的效应,美貌与智慧奇妙的遗传

    身高是母亲的遗传大 在营养状况下的前提下 父母的遗传是决定孩子身高的主要因素 其中妈妈的身高尤其关键 妈妈长得高 孩子也大多长得比较高 智力是母亲的遗传大 智力有一定的遗传性 同时受到环境 营养 教育等后天因素的影响 据科学家评估 遗传对智
  • 南大通用&河北工业大学人工智能与数据科学学院党支部共建暨研究生培养基地合作签约仪式顺利举办

    2022年2月18日下午 天津南大通用数据技术股份有限公司 河北工业大学人工智能与数据科学学院党支部共建签约仪式暨研究生培养基地签约仪式在普天创新产业园23层会议室举行 南大通用董事长丁明峰 高级副总裁赵伟 总工办主任杨伟伟 人力资源部总监
  • python中有哪些去除重复项的操作

    Python中去除重复项的操作 常用的有以下几种方式 1 使用set 将列表转化为集合 再转化为列表 即可去重 list a 1 2 3 2 1 4 5 4 6 7 7 new list a list set list a print ne
  • JMeter----安装与介绍以及简单页面录制和移动端录制

    1 什么是JMeter 2 JMeter的安装 3 JMeter基本使用 4 JMeter运行原理 5 JMeter录制脚本 1 什么是JMeter JMeter简介 JMeter是Apache公司使用Java平台开发的一套测试工具 JMe
  • flowable实战(三):关于流程图编辑

    发现很多人讲到flowable 就是大概讲一下整合里面一些名词之类 实操偏少 或者用一个小demo演示一下 就完了 但是一涉及到具体的业务 你会发现涉及到工作流要有多麻烦 考虑很多情况进去会涉及到条件设置 逻辑判断甚至官方提供的那么多方法你
  • C++实现人机对战围棋(使用Leela Zero权重)-界面

    1 在 leela zero next 包中有一个 从人类游戏训练的 较弱的 网络的权重文件 https sjeng org zero best v1 txt zip 6残差块 128通道 2 并在 easyx吧 百度贴吧下了一个双人对战的
  • C语言-函数指针-快速排序算法

    概述 使用C语言 实现结构体多元素 排序算法 冒泡排序 这里使用示例 蓝牙信号强度排序解说 编码环境 Visual Studio 2022 1 code include
  • Python int()的有趣用法

    Python中的int 函数相信大家都不陌生 总的来说 就是int 函数用于将字符串或数字转换为整型 那么今天要说的有趣用法是什么呢 先看一行代码 并猜一下它有什么作用 int 1 200 2 初看这行代码想半天也没搞懂 于是help in
  • 2014年12月4日星期四(DEMO10-2地形生成函数)

    转眼间 2014年快过去了 数了数代码 封装后的代码也有17000行了 但是 还有很多工作量 继续进行最为敬畏的地形生成 这个DEMO的意思是说 加载256色位图 以位图颜色索引乘以一个缩放因子为高程 将每个单元格分割为三角形 并插入到物体
  • 西瓜书《机器学习》课后答案——chapter5_5.5

    网络结构 这里采用简单的单隐层神经网络 输入层有2个神经元 隐层有4个神经元 输出层有2个神经元 隐层采用sigmoid激活函数 输出层采用softmax激活函数 z1 W1x b1 boldsymbol z 1 W 1 boldsymbo
  • Flutter之自动更新(自带源码 包看包会)

    Flutter做的App怎么自动更新呢 首先要用到两个依赖一个叫update app 另外一个叫package info 还有一个叫Dio 一个是用来下载App的 一个是用来获取当前App的版本信息的 一个是用来网络链接的 flutter