3分钟实现git托管软件安装包,并实现版本检测和更新功能

3分钟实现git托管软件安装包,并实现版本检测和更新功能

  • 最近写了一个开源的壁纸软件,一直想找一个免费好用的安装包托管平台,很遗憾,并未找到,好多平台要么收费、要么不好用。
  • git就不多介绍了,git能够托管代码自然能托管安装包。
  • 问题在于如何通过接口检测更新?只要解决这个问题,其它就都不是问题。

1、git 托管如何通过接口检测更新?

  • 众所周知,json文件是能通过get方式直接获取到的,这个没问题吧,不了解的可以查一下资料。
  • 那么 git 里面的json文件能直接读取吗?我以 gitee 为例测试了一下,发现并没有问题,用户能直接通过链接访问到git托管的json的文件内容。gitee没问题,github等其它代码托管平台应该也没问题,我是懒得测其它平台,有兴趣的可以自己一下。
  • 测试地址: gitee.com/zsnoin-can/...

gitee 获取托管的json文件的连接

  • 初始化git仓库这种基础操作就不说了,直接看结构,只有一个 json(版本信息文件)和 apk 安装包文件。
  • 注意点:仓库需要开源,不然别人无法访问。
  1. 点击json文件,查看json文件内容
  2. 点击右侧原始数据按钮,跳转新页面
  3. copy新页面的地址,通过get请求就能直接获取到json文件的内容了。
  4. json文件内容,你就可以完全自定义了,有新版本时更新版本号和更新日志即可。
  5. 刚开始,我不是通过这种方式获取到地址的,忘了一开始是咋获取到的,应该还有其它方法也可以获取到json地址。

有了版本信息接口和软件地址,只需要对比本地软件版本和git托管的版本是否一致,即可实现软件更新功能。

2、版本检测(flutter为例)

因为壁纸软件是用flutter写的,就以flutter举例,其它像 uniapp、electron 等等都大差不差。

  • package_info_plus 软件包信息管理插件,可以简单快速获取到当前版本号
  • url_launcher 跳转浏览器插件,gitee托管并不能直接下载,需跳转浏览器让用户自行下载。

下载函数,我这用的是自己封装过的Dio发起的网络请求,你可以直接用Dio或者http。

csharp 复制代码
Future<Response> updateApp() => DioInstance.instance().get(
      path:
          'https://gitee.com/zsnoin-can/new-wall-paper-apk/raw/master/version.json',
      param: {
        'random': Random().nextDouble(),
      },
    );

封装更新工具 /tools/update_apk.dart,添加 displayTips 控制没有检测到新版本时是否提示用户。

dart 复制代码
import 'package:bot_toast/bot_toast.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:wallpaper/api/foot.dart';
import 'package:wallpaper/components/button/normal_button.dart';
import 'package:wallpaper/generated/l10n.dart';

class UpdateApk {
  String updateUrl =
      'https://gitee.com/zsnoin-can/new-wall-paper-apk/blob/master/wallpaper.apk';

  Future updateApk(BuildContext context, {bool displayTips = false}) async {
    Response res = await updateApp();
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    String version = packageInfo.version; // 获取版本号
    if (version != res.data['version']) {
      showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: Row(
                crossAxisAlignment: CrossAxisAlignment.end,
                spacing: 5,
                children: [
                  Icon(Icons.update, color: Colors.deepOrangeAccent),
                  Text(
                    S.of(context).s15,
                    style: TextStyle(
                      fontSize: 18,
                    ),
                  ),
                  Text(
                    '${res.data['version']}',
                    style: TextStyle(
                      color: Theme.of(context).colorScheme.primary,
                      fontSize: 16,
                    ),
                  ),
                ],
              ),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(5)),
              ),
              content: SizedBox(
                height: 100,
                child: Padding(
                  padding: const EdgeInsets.only(left: 10, right: 10),
                  child: ListView.builder(
                      itemCount: res.data['update'].length,
                      itemBuilder: (context, index) {
                        return Text(
                            "${index + 1}、${res.data['update'][index]}");
                      }),
                ),
              ),
              actions: [
                NormalButton(
                    radius: 5,
                    width: 100,
                    height: 30,
                    fontSize: 16,
                    title: S.of(context).b7,
                    bgColor: const Color.fromARGB(131, 158, 158, 158),
                    onPressed: () {
                      Navigator.pop(context);
                    }),
                NormalButton(
                    radius: 5,
                    width: 100,
                    height: 30,
                    fontSize: 16,
                    title: S.of(context).s16,
                    onPressed: () async {
                      // 打开浏览器更新
                      if (await canLaunchUrl(Uri.parse(updateUrl))) {
                        await launchUrl(Uri.parse(updateUrl));
                      } else {
                        // 如果无法打开链接,显示错误提示
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(content: Text('url error: $updateUrl')),
                        );
                      }
                      Navigator.pop(context);
                    }),
              ],
            );
          });
    }
    if (version == res.data['version'] && displayTips) {
      BotToast.showText(text: S.of(context).s17);
    }
  }
}

用法:

  • 未检测到新版本时不需要提示 UpdateApk().updateApk(context);,例如,用户进入软件时自动检测更新,未检测到时无需提醒。
  • 未检测到新版本时需要提示 UpdateApk().updateApk(context, displayTips: true);,例如,用户在设置中手动点击了检测更新按钮,未检测到新版本时需要给用户正反馈。

效果图:

3、优缺点

  • 优点:非常简单,基本不需要任何操作就能对软件进行更新功能实装,增加软件的健全性。
  • 缺点:软件没有办法直接下载,安装包属于大文件范畴了,gitee需要用户登录后才能下载。

4、链接

相关推荐
C.er2 小时前
Git回顾
git
怀君10 小时前
Flutter——数据库Drift开发详细教程(四)
数据库·flutter
极小狐11 小时前
如何使用极狐GitLab 软件包仓库功能托管 ruby?
开发语言·数据库·人工智能·git·机器学习·gitlab·ruby
靡不有初11112 小时前
git命令常见用法【持续更新中……】
git
桃林春风一杯酒15 小时前
Cannot Run Git: Cannot identify version of Git executable: no response
git
~菜鸟笔记~16 小时前
Git笔记
笔记·git
10000hours17 小时前
【Git】【commit】查看未推送的提交&查看指定commit的修改内容&合并不连续的commit
git
江畔独步17 小时前
Git 基础操作系列2: 本地项目上传至git仓库(gitee / gitlab / github)
git·gitee·gitlab
hay_lee1 天前
git 多个提交记录合并为一个
git
刃神太酷啦1 天前
C++入门(下)--《Hello C++ World!》(2)(C/C++)
java·c语言·c++·git·算法·github