本文用 app_version_details 1.0.3 在 Flutter 鸿蒙应用的关于页和问题反馈页读取完整版本、版本名、构建号与 bundle name,并说明为什么必须以设备上的已安装元数据为准。

三方库仓库: https://atomgit.com/oh-flutter/app_version_details

本文锁定版本: f161b93e3c484aecf8a8910b22a64827dff71bf3

完整 Demo: app_version_details/example

一、最终真机效果

在这里插入图片描述

图 1:CHZ-AL00 / HarmonyOS 7.0.0.105 上显示完整版本、版本名、构建号和 bundle name。

受测宿主返回完整版本 1.0.0+1、版本名 1.0.0、构建号 1、包名 com.example.flutter_oh_demo,两轮重复读取均与 bm dump 中的已安装 bundle 元数据一致。

API本次结果常见用途
getVersion()1.0.0+1日志、反馈信息
getVersionName()1.0.0关于页展示
getBuildNumber()1灰度和诊断
getPackageName()com.example.flutter_oh_demo应用标识和支持信息
自动化与构建23 项功能测试及 HAP 通过回归依据

二、不要读取插件自己的版本

插件装入哪个宿主,就应返回哪个已安装应用的版本和 bundle name,而不是 app_version_details 自己的 1.0.3。Flutter 构建还可能根据宿主 pubspec.yaml 覆盖 AppScope 中的静态版本,因此源文件里的某个数字不一定是设备最终安装值。

关于页、客服工单和崩溃日志都应基于运行时读取。升级比较仍建议让服务端使用结构化版本策略,不要仅按字符串字典序比较 1.10.01.9.0

三、环境与依赖

组件实测版本
Flutter OH3.41.10-ohos-1.0.1
Dart3.11.5
DevEco Studio26.0.0 Release
HarmonyOS SDKAPI 26,示例兼容 API 18
测试设备CHZ-AL00 / HarmonyOS 7.0.0.105
app_version_details1.0.3 / 上述受测提交

更大版本号的 3.44.9+ohos-0.0.1-canary1 是预览版,未用于本文回归。OHOS 适配尚无稳定 TAG:

dependencies:
  app_version_details:
    git:
      url: https://atomgit.com/oh-flutter/app_version_details.git
      ref: f161b93e3c484aecf8a8910b22a64827dff71bf3
flutter pub get

检查 pubspec.lockresolved-ref。读取自身 bundle 元数据不需要新增权限。

在这里插入图片描述

图 2:AtomGit 适配分支、仓库来源和当前 HEAD。

四、一次读取四项信息

import 'package:app_version_details/app_version_details.dart';

class AppBuildInfo {
  const AppBuildInfo({
    required this.version,
    required this.versionName,
    required this.buildNumber,
    required this.packageName,
  });

  final String? version;
  final String? versionName;
  final String? buildNumber;
  final String? packageName;
}

Future<AppBuildInfo> loadBuildInfo() async {
  final plugin = AppVersionDetails();
  final values = await Future.wait<String?>([
    plugin.getVersion(),
    plugin.getVersionName(),
    plugin.getBuildNumber(),
    plugin.getPackageName(),
  ]);
  return AppBuildInfo(
    version: values[0],
    versionName: values[1],
    buildNumber: values[2],
    packageName: values[3],
  );
}

getVersionName()getBuildNumber() 会在 Dart 层从完整版本拆分,它们不是四次不同的系统元数据定义。若只做关于页,读取 getVersion()getPackageName() 后自行展示通常已经足够;上面同时调用四项是为了演示全部公开 API。

五、关于页完整示例

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

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

  
  State<AboutBuildPage> createState() => _AboutBuildPageState();
}

class _AboutBuildPageState extends State<AboutBuildPage> {
  final _plugin = AppVersionDetails();
  List<String?>? _values;
  Object? _error;
  bool _loading = false;

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

  Future<void> _refresh() async {
    if (_loading) return;
    setState(() {
      _loading = true;
      _error = null;
    });
    try {
      final values = await Future.wait<String?>([
        _plugin.getVersion(),
        _plugin.getPackageName(),
        _plugin.getVersionName(),
        _plugin.getBuildNumber(),
      ]);
      if (mounted) setState(() => _values = values);
    } catch (error) {
      if (mounted) setState(() => _error = error);
    } finally {
      if (mounted) setState(() => _loading = false);
    }
  }

  
  Widget build(BuildContext context) {
    const labels = ['完整版本', 'Bundle name', '版本名', '构建号'];
    return Scaffold(
      appBar: AppBar(
        title: const Text('关于应用'),
        actions: [
          IconButton(
            tooltip: '刷新',
            onPressed: _loading ? null : _refresh,
            icon: const Icon(Icons.refresh),
          ),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          for (var i = 0; i < labels.length; i++)
            ListTile(
              title: Text(labels[i]),
              subtitle: SelectableText(_values?[i] ?? '不可用'),
            ),
          if (_loading) const LinearProgressIndicator(),
          if (_error != null) Text('读取失败:$_error'),
        ],
      ),
    );
  }
}

客服反馈页面可以把这四项加入诊断信息,但应让用户看见将要提交的内容。包名和版本通常不是秘密,仍不应顺带上传设备标识、账号或其他无关数据。

在这里插入图片描述

图 3:OHOS 端从当前宿主 BundleInfo 读取并组装版本。

六、测试、构建与系统对照

flutter analyze
flutter test
node --test ohos/test/app_version_details.test.cjs
cd example
flutter test
flutter build hap --debug --no-codesign

在这里插入图片描述

图 4:23 项 Dart、Widget 和 ArkTS 功能测试通过。

在这里插入图片描述

图 5:HAP 构建和真机宿主受测 SHA。

在这里插入图片描述

图 6:两轮四项 API 结果与 bm dump 已安装元数据一致。

真机预验收曾按 AppScope 静态值期待构建号 1000000,实际安装值为 1bm dump 证明插件返回正确,最终修正的是错误断言。这也是使用时最值得保留的经验:以安装后的系统元数据为事实来源。

应用内重复读取

在这里插入图片描述

图 7:app_version_details 1.0.3 首次读取完整版本和 Bundle Name。

在这里插入图片描述

图 8:手动刷新到第 2 次读取后,读取时间变化,版本拆分与一致性检查仍通过。

七、常见问题

Q1:为什么插件版本是 1.0.3,页面却显示 1.0.0

前者是三方库版本,后者是宿主应用版本。两者不是同一个字段。

Q2:为什么 AppScope 和真机结果不一致

Flutter 构建可能从宿主 pubspec.yaml 写入最终版本。请用已安装应用的系统元数据核对。

Q3:读取失败时能否继续展示默认版本

可以展示“未知”,但不要把代码里的默认字符串当成真机事实或用于强制升级判断。

八、总结

app_version_details 可以为 Flutter 鸿蒙关于页、日志和反馈流程提供真实宿主版本与 bundle name。项目应固定受测 SHA、处理空值和平台异常,并以已安装元数据而非构建前静态文件作为验收基线。本文四个公开 API 已完成两轮真机和 bm dump 对照。

九、参考链接

欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter

Logo

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

更多推荐