欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

请添加图片描述

前言

在软件开发中,版本号管理是一项基础但严谨的工作。无论是插件依赖管理,还是 App 自身的版本更新检查,都离不开语义化版本(Semantic Versioning)规范。

Dart 官方提供的 pub_semver 库是 Pub 包管理器背后的核心组件,它实现了完整的 SemVer 2.0.0 规范。利用它,我们可以在 OpenHarmony 应用中轻松处理复杂的版本比较、范围约束和解析逻辑。本文将介绍它的用法及在版本更新场景中的实战。

一、核心概念

1.1 语义化版本 (SemVer)

版本格式:主版本号.次版本号.修订号 (MAJOR.MINOR.PATCH),例如 1.2.3

  • MAJOR: 不兼容的 API 修改
  • MINOR: 向下兼容的新功能
  • PATCH: 向下兼容的 bug 修复

1.2 OpenHarmony 适配说明

pub_semver 是纯算法库,不涉及任何系统底层 API。因此,它在 OpenHarmony 上运行时无需任何额外配置,且性能极佳。

符合要求

版本不匹配

版本约束串: ^1.2.0

SemVer 解析器

版本约束条件

App 当前版本: 1.2.3

逻辑匹配校验

服务器最新版本: 2.0.0

允许通过

终止操作

二、基础用法与示例

2.1 添加依赖

dependencies:
  pub_semver: ^2.2.0

2.2 解析与比较

import 'package:pub_semver/pub_semver.dart';

void main() {
  // 1. 解析版本字符串
  final v1 = Version.parse('1.2.3');
  final v2 = Version.parse('1.2.4-dev.1'); // 预发布版本
  
  // 2. 比较大小
  if (v1 < v2) {
    print('$v1 小于 $v2');
  } else {
    print('$v1 大于或等于 $v2'); // 输出: 1.2.3 > 1.2.4-dev.1
  }
}

在这里插入图片描述

2.3 版本约束 (Constraint)

这是 pub_semver 最强大的功能,用于判断某个版本是否符合特定范围。

import 'package:pub_semver/pub_semver.dart';

void checkConstraint() {
  // 定义范围:大于等于 1.0.0 且小于 2.0.0
  final constraint = VersionConstraint.parse('^1.0.0');
  
  final v1 = Version(1, 1, 0);
  final v2 = Version(2, 0, 1);
  
  print(constraint.allows(v1)); // true
  print(constraint.allows(v2)); // false
}

在这里插入图片描述

2.4 版本优先排序

void sortVersions() {
  final versions = [
    Version.parse('1.0.0'),
    Version.parse('0.9.9'),
    Version.parse('1.0.0+build.1'),
  ];
  
  versions.sort(); // 默认升序
  print(versions); // [0.9.9, 1.0.0, 1.0.0+build.1] (注意 build号不影响优先级)
}

在这里插入图片描述

三、完整实战示例:App 版本更新检查器

本示例展示如何在 OpenHarmony 应用启动时,从服务器获取最新版本信息,利用 pub_semver 判断是否需要强制更新或可选更新。

3.1 示例代码

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

// 模拟从服务器获取的版本信息
class UpdateInfo {
  final String latestVersion;
  final String minSupportVersion;
  final String changelog;
  
  UpdateInfo(this.latestVersion, this.minSupportVersion, this.changelog);
}

// 模拟当前 App 版本 (实际上应通过 package_info_plus 获取)
const String currentAppVersion = '1.0.5';

void main() {
  runApp(const MaterialApp(home: UpdateCheckerPage()));
}

class UpdateCheckerPage extends StatefulWidget {
  const UpdateCheckerPage({super.key});

  
  State<UpdateCheckerPage> createState() => _UpdateCheckerPageState();
}

class _UpdateCheckerPageState extends State<UpdateCheckerPage> {
  String _status = '正在检查更新...';
  Color _statusColor = Colors.grey;

  
  void initState() {
    super.initState();
    _checkUpdate();
  }

  Future<void> _checkUpdate() async {
    // 模拟网络延迟
    await Future.delayed(const Duration(seconds: 1));
    
    // 假设这是接口返回的数据
    final serverInfo = UpdateInfo('1.2.0', '1.1.0', '1. 新增深色模式\n2. 修复已知 bug');
    
    try {
      final current = Version.parse(currentAppVersion);
      final latest = Version.parse(serverInfo.latestVersion);
      final minSupport = Version.parse(serverInfo.minSupportVersion);
      
      if (current < minSupport) {
        // 版本过低,强制更新
        setState(() {
          _status = '版本过低 ($current),需强制更新到 $minSupport 以上。\n最新: $latest';
          _statusColor = Colors.red;
        });
        _showUpdateDialog(force: true, info: serverInfo);
      } else if (current < latest) {
        // 有新版本,可选更新
        setState(() {
          _status = '发现新版本: $latest\n当前: $current';
          _statusColor = Colors.orange;
        });
        _showUpdateDialog(force: false, info: serverInfo);
      } else {
        // 已是最新
        setState(() {
          _status = '当前已是最新版本 ($current)';
          _statusColor = Colors.green;
        });
      }
    } catch (e) {
      setState(() => _status = '解析版本号失败: $e');
    }
  }

  void _showUpdateDialog({required bool force, required UpdateInfo info}) {
    showDialog(
      context: context,
      barrierDismissible: !force, // 强制更新时点击背景不关闭
      builder: (context) {
        return AlertDialog(
          title: Text(force ? '重要更新' : '发现新版本'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text('最新版本: ${info.latestVersion}'),
              const SizedBox(height: 10),
              const Text('更新日志:'),
              Text(info.changelog, style: const TextStyle(color: Colors.grey)),
            ],
          ),
          actions: [
            if (!force)
              TextButton(
                onPressed: () => Navigator.pop(context),
                child: const Text('稍后'),
              ),
            ElevatedButton(
              onPressed: () {
                // 实际逻辑:跳转应用市场或下载页
                Navigator.pop(context);
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text('开始下载更新...')),
                );
              },
              child: const Text('立即更新'),
            ),
          ],
        );
      },
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('版本检查 Demo')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.system_update, size: 80, color: Colors.blue),
            const SizedBox(height: 20),
            Text(
              _status,
              style: TextStyle(fontSize: 18, color: _statusColor, fontWeight: FontWeight.bold),
              textAlign: TextAlign.center,
            ),
          ],
        ),
      ),
    );
  }
}

在这里插入图片描述

五、总结

pub_semver 虽然小巧,但在处理版本逻辑时能避免许多手动字符串比较带来的潜在 bug(如 1.10.0 应该大于 1.9.0)。

最佳实践

  1. 服务端规范:确保后端 API 返回的版本号严格遵循 SemVer 格式。
  2. 预发布处理:注意 1.0.0-dev 小于 1.0.0,在处理 Beta 版更新时需留意逻辑。
  3. 强制更新策略:利用版本比较逻辑(current < minSupportVersion)来实施软强制更新策略。
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐