Flutter中App升级实现

Flutter Upgrader 插件集成指南

概述

本文档详细介绍了 Peekababy 项目中使用的 upgrader 插件的集成方式和使用方法,帮助团队成员快速理解和使用该功能。

插件信息

  • 插件名称 : upgrader
  • 版本 : ^11.4.0
  • 功能: 自动检查应用更新并提示用户升级
  • 支持平台: iOS、Android

依赖配置

pubspec.yaml 配置

yaml 复制代码
dependencies:
  upgrader: ^11.4.0
  dio: ^5.4.0# 用于网络请求xml: ^6.5.0# 用于解析 XML 响应version: ^3.0.2# 用于版本比较

核心实现

1. 自定义认证 Store

dart 复制代码
// 带认证的自定义 Appcast Storeclass AuthenticatedAppcastStore extends UpgraderAppcastStore {
  final Map<String, String> headers;

  AuthenticatedAppcastStore({required super.appcastURL, required this.headers});

  @override
  Future<UpgraderVersionInfo> getVersionInfo({
    required UpgraderState state,
    required Version installedVersion,
    required String? country,
    required String? language,
  }) async {
// 创建带认证的 Appcastfinal localAppcast = Appcast(
      client: state.client,
      clientHeaders: headers,// 设置认证头
      upgraderDevice: state.upgraderDevice,
      upgraderOS: state.upgraderOS,
    );

    return UpgraderAppcastStore(
      appcastURL: appcastURL,
      appcast: localAppcast,
    ).getVersionInfo(
      state: state,
      installedVersion: installedVersion,
      country: country,
      language: language,
    );
  }
}

2. 升级服务类

ini 复制代码
class UpgraderService {
  static Future<Upgrader> getUpgrader(BuildContext context) async {
    final languageCode = AppLocalizations.of(context)!.localeName.split('_').first;
    final platform = Theme.of(context).platform;
    final platformString = platform == TargetPlatform.android ? 'android' : 'ios';

// 构建 API URLfinal appcastURL = '<http://pkb.xinzhiaigc.com/functions/v1/check-update?platform=$platformString>';

// 检查是否为关键更新String? minAppVersion;
    try {
      final dio = Dio();
      dio.options.headers = {
        'User-Agent': 'Flutter App Updater',
        'Accept': 'application/xml, text/xml',
        'Authorization': 'Bearer <your-token>',
        'apikey': '<your-api-key>',
      };

      final response = await dio.get(appcastURL);
      if (response.statusCode == 200) {
        final document = XmlDocument.parse(response.data);
        final enclosure = document.findAllElements('enclosure').firstOrNull;
        if (enclosure != null) {
          final isCritical = enclosure.getAttribute('sparkle:criticalUpdate') == 'true';
          if (isCritical) {
            minAppVersion = '999.0.0';// 强制更新
          }
        }
      }
    } catch (e) {
// 静默处理错误
    }

    return Upgrader(
      minAppVersion: minAppVersion,
      storeController: UpgraderStoreController(
        onAndroid: () => AuthenticatedAppcastStore(
          appcastURL: appcastURL,
          headers: authHeaders,
        ),
        oniOS: () => AuthenticatedAppcastStore(
          appcastURL: appcastURL,
          headers: authHeaders,
        ),
      ),
      messages: UpgraderMessages(code: languageCode),
    );
  }
}

3. UI 集成

scala 复制代码
class _HomeScreenState extends State<HomeScreen> {
  Upgrader? _upgrader;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (_upgrader == null) {
      _initUpgrader();
    }
  }

  void _initUpgrader() async {
    try {
      final upgrader = await UpgraderService.getUpgrader(context);
      if (mounted) {
        setState(() {
          _upgrader = upgrader;
        });
      }
    } catch (e) {
// 静默处理错误
    }
  }

  @override
  Widget build(BuildContext context) {
    Widget homeContent = Scaffold(/* 你的页面内容 */);

// 条件性包装升级检查if (_upgrader != null) {
      return UpgradeAlert(
        upgrader: _upgrader!,
        showReleaseNotes: false,
        dialogStyle: Theme.of(context).platform == TargetPlatform.iOS
            ? UpgradeDialogStyle.cupertino
            : UpgradeDialogStyle.material,
        child: homeContent,
      );
    }

    return homeContent;
  }
}

后端 API 规范

请求格式

sql 复制代码
GET /functions/v1/check-update?platform={android|ios}
Headers:
  Authorization: Bearer <token>
  apikey: <api-key>
  User-Agent: Flutter App Updater
  Accept: application/xml, text/xml

响应格式 (Appcast XML)

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="<http://www.andymatuschak.org/xml-namespaces/sparkle>">
  <channel>
    <title>App Updates</title>
    <item>
      <title>Version 1.2.3</title>
      <description>Bug fixes and improvements</description>
      <pubDate>Mon, 01 Jan 2024 12:00:00 +0000</pubDate>
      <enclosure
        url="<https://apps.apple.com/app/your-app/id123456789>"
        sparkle:version="1.2.3"
        sparkle:shortVersionString="1.2.3"
        sparkle:criticalUpdate="false"
        type="application/octet-stream" />
    </item>
  </channel>
</rss>

关键特性

1. 强制更新支持

  • 通过 sparkle:criticalUpdate="true" 标记关键更新
  • 设置 minAppVersion = "999.0.0" 强制用户更新

2. 多语言支持

  • 自动根据应用语言设置显示对应的升级提示
  • 支持的语言由 UpgraderMessages(code: languageCode) 控制

3. 平台适配

  • iOS: 使用 Cupertino 风格对话框
  • Android: 使用 Material 风格对话框

4. 认证支持

  • 自定义 AuthenticatedAppcastStore 支持 API 认证
  • 通过 headers 传递认证信息

最佳实践

1. 初始化时机

scss 复制代码
// ✅ 正确:在 didChangeDependencies 中初始化@override
void didChangeDependencies() {
  super.didChangeDependencies();
  if (_upgrader == null) {
    _initUpgrader();
  }
}

// ❌ 错误:在 initState 中初始化(context 依赖可能未就绪)

2. 错误处理

scss 复制代码
void _initUpgrader() async {
  try {
    final upgrader = await UpgraderService.getUpgrader(context);
    if (mounted) {// 检查 widget 是否仍然挂载
      setState(() {
        _upgrader = upgrader;
      });
    }
  } catch (e) {
// 静默处理错误,不影响应用正常使用
  }
}

3. 性能优化

  • 升级检查异步进行,不阻塞 UI 渲染
  • 使用条件渲染,只在升级器准备好后才包装 UI
  • 防重复初始化:if (_upgrader == null)

注意事项

1. 网络依赖

  • 升级检查需要网络连接
  • 网络异常时应用仍能正常使用
  • 建议设置合理的超时时间

2. 权限要求

  • iOS: 需要网络访问权限
  • Android: 需要网络访问权限

3. 应用商店政策

  • 确保升级链接指向官方应用商店
  • 遵守各平台的更新政策

4. 测试建议

  • 测试网络异常情况
  • 测试强制更新流程
  • 测试不同语言环境
  • 测试不同平台的 UI 样式

故障排除

常见问题

  1. 升级检查不工作

    • 检查网络连接
    • 验证 API 认证信息
    • 确认后端 API 返回正确的 XML 格式
  2. 对话框样式异常

    • 确认平台检测正确
    • 检查主题配置
  3. 语言显示错误

    • 验证 AppLocalizations 配置
    • 确认支持的语言列表

调试技巧

scss 复制代码
// 启用调试日志
Upgrader.clearSavedSettings();// 清除缓存设置
debugPrint('Platform: $platformString');
debugPrint('AppcastURL: $appcastURL');

总结

upgrader 插件为应用提供了完整的版本更新解决方案,通过合理的配置和集成,可以实现:

  • 自动版本检查
  • 优雅的用户提示
  • 强制更新支持
  • 多平台适配
  • 国际化支持

正确使用该插件可以显著提升用户体验和应用的维护效率。

相关推荐
Mintopia8 小时前
⚛️ React 17 vs React 18:Lanes 是同一个模型,但跑法不一样
前端·react.js·架构
李子烨8 小时前
吃饱了撑的突发奇想:TypeScript 类型能不能作为跑业务逻辑的依据?(纯娱乐)
前端·typescript
AAA简单玩转程序设计8 小时前
救命!Java小知识点,基础党吃透直接起飞
java·前端
叫我詹躲躲8 小时前
Vue 3 动态组件详解
前端·vue.js
叫我詹躲躲8 小时前
基于 Three.js 的 3D 地图可视化:核心原理与实现步骤
前端·three.js
TimelessHaze8 小时前
算法复杂度分析与优化:从理论到实战
前端·javascript·算法
旧梦星轨9 小时前
掌握 Vite 环境配置:从 .env 文件到运行模式的完整实践
前端·前端框架·node.js·vue·react
PieroPC9 小时前
NiceGui 3.4.0 的 ui.pagination 分页实现 例子
前端·后端
晚霞的不甘9 小时前
实战前瞻:构建高可用、强实时的 Flutter + OpenHarmony 智慧医疗健康平台
前端·javascript·flutter