tiny_upgrader 1.0.4 copy "tiny_upgrader: ^1.0.4" to clipboard
tiny_upgrader: ^1.0.4 copied to clipboard

A Flutter app upgrade plugin. You can use it to upgrade your app. Supports custom upgrade dialogs or pages. Provides multiple upgrade methods.

TinyUpgreade #

这是一个 Flutter 项目,APP 升级插件,支持使用 Flutter 组件作为更新弹窗。

与其他插件最大的不同是这里尽最大可能只使用 Dart 一个语言处理逻辑,例如 APP 安装等系统接口调用以外的部分都会用 Dart&Flutter 完成。

特色功能 #

  • 支持使用 Flutter Widget 自定义更新弹窗样式
  • 支持使用事件回调无 UI 更新,当你需要自定义一个 APP 更新**”页面“**而非弹窗时,它会非常有用。
  • 至少 2 年的维护支持

开始使用 #

使用门槛很低,在你的 APP 启动时或者任何在需要更新前,调用初始化接口,例如

TinyUpgrader.init(
  // 是否为开发调试模式,能看到更多日志
  isDebug: true,

  // APP路径前缀
  baseUrl: 'https://example.cn:8080/',

  // 错误回调函数,为了避免影响您的业务,只在这里进行回调提示,而不去throw错误
  errorHandler: (error) {
    debugPrint('出现错误: $error');
  },

  /// 自定义解析器,这里你可以将回调函数返回的json数据解析成VersionInfo对象,也可以对其进行加工处理
  parser: (response) async {
    /// response 就是 dio 的 response data 没有做任何处理,我的响应结构是 { success: boolean, data: dynamic }
    var res = VersionInfo.fromMap((response as Map<String, dynamic>)['data']);

    // 例如我这里就对它进行token校验
    res.downloadUrl = '${res.downloadUrl}?token=123123';
    return res;
  },
);

而在检查更新时,只需要简单一行代码即可完成

await _upgrader.check(context, url: 'api/apk-manager-v1/latest');

后端代码示例 #

package main

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
)

var fileData *fileInfo

const (
	version      = "1.2.0"
	buildVersion = 1
)

func main() {
	r := gin.Default()

	{
		base := r.Group("/api/apk-manager-v1")
		base.POST("/upload", func(c *gin.Context) {
			// 解析表单数据
			file, err := c.FormFile("apk")
			if err != nil {
				fmt.Println(err)
				return
			}

			fileData, err = processFile(c, file, version, buildVersion)
			if err != nil {
				fmt.Println(err)
				return
			}
		})

		base.GET("/download/:version", func(c *gin.Context) {
			c.Header("Content-Type", "application/octet-stream")
			c.File(fileData.Path)
		})

		base.GET("/latest", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{
				"update_status":  2,
				"version":        version,
				"build_version":  buildVersion,
				"modify_content": "修复了一些bug",
				"download_url":   "/api/apk-manager-v1/download/" + version,
				"apk_size":       fileData.Size,
				"apk_hash_code":  fileData.MD5,
				"file_path":      fileData.Path,
			})
		})
	}
}

// 辅助结构体
type uploadParams struct {
	UpdateStatus  int
	Version       string
	BuildVersion  int
	ModifyContent string
}

type fileInfo struct {
	Size int64
	MD5  string
	Path string
}

// 解析上传参数
func parseUploadParams(c *gin.Context) (*uploadParams, error) {
	updateStatus, err := strconv.Atoi(c.PostForm("update_status"))
	if err != nil || updateStatus < 0 || updateStatus > 2 {
		return nil, fmt.Errorf("invalid update_status")
	}

	version := c.PostForm("version")
	if version == "" {
		return nil, fmt.Errorf("必须填写版本号")
	}

	buildVersion, err := strconv.ParseInt(c.PostForm("build_version"), 10, 32)
	if err != nil || buildVersion < 0 {
		return nil, fmt.Errorf("构建号必须是大于0的整数")
	}

	return &uploadParams{
		UpdateStatus:  updateStatus,
		Version:       version,
		BuildVersion:  int(buildVersion),
		ModifyContent: c.PostForm("modify_content"),
	}, nil
}

// 处理文件保存 只是一个参考,也可以自行处理
func processFile(c *gin.Context, file *multipart.FileHeader, bigVersion string, buildVersion int) (*fileInfo, error) {
	// 打开文件
	src, err := file.Open()
	if err != nil {
		return nil, fmt.Errorf("failed to open file")
	}
	defer src.Close()

	// 创建一个 MD5 哈希器
	hash := md5.New()
	// 将文件内容拷贝到哈希器中
	if _, err := io.Copy(hash, src); err != nil {
		fmt.Println("无法读取文件:", err)
		return nil, err
	}
	// 计算 MD5 哈希值
	hashInBytes := hash.Sum(nil)[:16]
	// 将哈希值转换为十六进制字符串
	hashString := strings.ToUpper(hex.EncodeToString(hashInBytes))

	_, err = src.Seek(0, io.SeekStart)
	if err != nil {
		return nil, err
	}

	// 创建保存路径
	ext := path.Ext(file.Filename)
	newFilename := fmt.Sprintf("app-v%s-%d%s", bigVersion, buildVersion, ext)
	filePath := path.Join("./", newFilename)

	// 保存文件到磁盘
	dst, err := os.Create(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to create file")
	}
	defer dst.Close()

	if _, err := io.Copy(dst, src); err != nil {
		return nil, fmt.Errorf("failed to save file")
	}

	return &fileInfo{
		Size: file.Size,
		MD5:  hashString,
		Path: filePath,
	}, nil
}
1
likes
0
points
51
downloads

Publisher

verified publishericeres.cn

Weekly Downloads

A Flutter app upgrade plugin. You can use it to upgrade your app. Supports custom upgrade dialogs or pages. Provides multiple upgrade methods.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

crypto, dio, flutter, http, package_info_plus, path_provider, plugin_platform_interface

More

Packages that depend on tiny_upgrader

Packages that implement tiny_upgrader