Flutter 鸿蒙 app_install_date 0.1.5 使用实战:读取应用安装时间

本文用 app_install_date 0.1.5 在 Flutter 鸿蒙应用中读取系统记录的安装时间,展示本地时间和 epoch 毫秒,并说明覆盖安装、时区转换及异常状态的处理边界。

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

本文锁定版本: 3fb5bd5e568784783be69a46adbfc2b7c2185646

完整 Demo: app_install_date/example

一、最终真机效果

图 1:CHZ-AL00 / HarmonyOS 7.0.0.105(SP10) 上展示安装本地时间和 epoch 毫秒。

受测应用两轮、每轮连续读取 5 次,均得到 1788703057807 毫秒,对应本地时间 2026-09-06 21:57:37.807 +08:00。公开 API、宿主直接调用 bundleManager 和外部 bm dump 三方结果一致。

验证点 实测结果
installDate 返回 DateTime
epoch 精度 保留系统毫秒值
重复读取 两轮共 10 次一致
依赖与构建 固定远程 SHA,签名/无签名 HAP 均完成
自动化 25 项 Dart/Widget/ArkTS 功能测试通过

二、安装时间能解决什么问题

它可以辅助新手引导、安装后权益、迁移提示和客服诊断。例如产品只想在安装后的前三天展示一次入口,可以将当前时间与安装时间比较。但这个值不应作为安全身份、设备唯一标识或不可篡改凭证。

OHOS 端读取的是当前宿主的 BundleInfo.installTime,不是目录创建时间,也不是应用第一次启动时自己写入的缓存。卸载后重装通常会形成新的安装记录;覆盖升级是否保持原值则取决于系统安装语义。本文验证期间只做覆盖安装,没有专门完成完整升级矩阵,因此业务若依赖"首次安装且升级永不变化",还要针对发布链路单独测试。

三、环境和依赖

组件 实测版本
Flutter OH 3.41.10-ohos-1.0.1
Dart 3.11.5
DevEco Studio 26.0.0 Release
HarmonyOS SDK API 26,示例兼容 API 18
测试设备 CHZ-AL00 / HarmonyOS 7.0.0.105(SP10C00E105R2P4)
app_install_date 0.1.5 / 上述受测提交

预览版 3.44.9+ohos-0.0.1-canary1 未用于本文回归。当前没有 OHOS 稳定 TAG:

yaml 复制代码
dependencies:
  app_install_date:
    git:
      url: https://atomgit.com/oh-flutter/app_install_date.git
      ref: 3fb5bd5e568784783be69a46adbfc2b7c2185646
shell 复制代码
flutter pub get

pubspec.lock 确认 resolved-ref。读取自身 BundleInfo 不需要新增权限。

图 2:AtomGit 仓库、适配分支和受测提交。

四、核心 API 和时间语义

dart 复制代码
import 'package:app_install_date/app_install_date.dart';

final DateTime installedAt = await AppInstallDate().installDate;
final int epochMilliseconds = installedAt.millisecondsSinceEpoch;
final DateTime localTime = installedAt.toLocal();
final DateTime utcTime = installedAt.toUtc();

epoch 毫秒表示绝对时刻,不带"东八区数值"。Dart 的 toLocal()toUtc() 只改变展示时区,不应在 ArkTS 或 Dart 中手工加减 8 小时。与服务端比较时优先传 epoch 或 ISO 8601 UTC 字符串;本地格式化文本只用于界面。

五、带重试的页面示例

dart 复制代码
import 'package:app_install_date/app_install_date.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

  @override
  State<InstallDatePage> createState() => _InstallDatePageState();
}

class _InstallDatePageState extends State<InstallDatePage> {
  DateTime? _installedAt;
  String? _error;
  bool _loading = false;

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

  Future<void> _refresh() async {
    if (_loading) return;
    setState(() {
      _loading = true;
      _error = null;
    });
    try {
      final value = await AppInstallDate().installDate;
      if (mounted) setState(() => _installedAt = value);
    } on PlatformException catch (error) {
      if (mounted) {
        setState(() => _error = '${error.code}: ${error.message ?? '读取失败'}');
      }
    } catch (error) {
      if (mounted) setState(() => _error = '$error');
    } finally {
      if (mounted) setState(() => _loading = false);
    }
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: const Text('安装时间'),
          actions: [
            IconButton(
              tooltip: '刷新',
              onPressed: _loading ? null : _refresh,
              icon: const Icon(Icons.refresh),
            ),
          ],
        ),
        body: ListView(
          padding: const EdgeInsets.all(24),
          children: [
            SelectableText(
              _installedAt?.toLocal().toString() ?? '暂不可用',
            ),
            const SizedBox(height: 8),
            Text(
              'Epoch milliseconds: '
              '${_installedAt?.millisecondsSinceEpoch ?? '-'}',
            ),
            if (_loading) const LinearProgressIndicator(),
            if (_error != null) Text('读取失败:$_error'),
          ],
        ),
      );
}

这个值通常不需要高频刷新。页面初始化读取一次即可,诊断页可以提供手动刷新。平台返回异常时保留错误状态,不要退回当前时间;把"现在"当作安装时间会让新手权益和统计悄悄出错。

图 3:OHOS 端读取并校验 BundleInfo.installTime 的毫秒值。

六、业务中的时间差判断

dart 复制代码
bool installedWithin(DateTime installedAt, Duration window) {
  final elapsed = DateTime.now().difference(installedAt);
  return !elapsed.isNegative && elapsed <= window;
}

系统时钟可能被用户调整,极端情况下 elapsed 会变成负数。示例明确拒绝负时间差;涉及奖励或风控时,应由服务端时间和账号状态决定,不能只信任客户端时钟与安装元数据。

七、测试、构建与真机对照

shell 复制代码
flutter analyze --no-fatal-infos
flutter test
node --test ohos/test/app_install_date.test.cjs
cd example
flutter test
flutter build hap --debug --no-codesign

图 4:25 项功能测试通过;保留上游 1 条 analyze info。

图 5:HAP 构建结果和远程依赖 resolved-ref。

图 6:公开 API、独立 bundleManager 与 bm dump 的 epoch 毫秒一致。

应用内重复读取

图 7:首次读取完整展示本地时间、ISO 8601、epoch 毫秒和时区偏移。

图 8:刷新到第 2 次读取后,安装 epoch 保持一致,本次读取时间更新。

八、常见问题

Q1:显示时间为什么和 epoch 转换工具差八小时

通常是工具按 UTC 展示,而页面按本地时区展示。比较两边的 epoch 毫秒,且不要手工加减时区。

Q2:为什么不用应用目录创建时间

目录可能被迁移、恢复或重新创建,语义不稳定。OHOS 受测实现直接读取系统 bundle 安装元数据。

Q3:覆盖升级后值一定不变吗

本文没有覆盖所有升级方式和系统版本。业务依赖这个性质时,必须使用真实发布包完成升级矩阵。

九、总结

app_install_date 为 Flutter 鸿蒙应用提供了直接的 DateTime 安装时间。可靠使用要锁定受测提交、按 epoch 绝对时刻处理时区、失败时不伪造当前时间,并把它限制在引导和诊断等辅助场景。本文已完成两轮重复读取及三方系统对照。

十、参考链接

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

相关推荐
Dream-Y.ocean1 小时前
鸿蒙平台 Apache Tomcat 管理控制台适配实战:基于 Electron 壳方案的真实 HTTP 服务器实现
tomcat·apache·harmonyos
●VON3 小时前
Flutter 鸿蒙插件适配实战:flutter_screenshot_detect 0.1.7 截图事件监听
flutter·华为·harmonyos·鸿蒙
GLAB-Mary5 小时前
90%的网络工程师,根本没必要考HCIE!
网络·华为·华为认证·hcie·hcia·hcip
HwJack2011 小时前
HarmonyOS批量数据与性能优化实战:万条数据入库与不卡 UI 的查询
ui·性能优化·harmonyos
FrameNotWork13 小时前
HarmonyOS应用《左右相册》 隐私防窥实战:用 dlpAntiPeep 让相册“感知“正在被偷瞄
华为·harmonyos
昇腾知识体系13 小时前
昇腾 950 RegBase 性能优化:从 msprof 采数到优化手法
人工智能·华为·性能优化·知识图谱
马剑威(威哥爱编程)16 小时前
HarmonyOS 应用上架审核避坑:驳回五类地图与提交前自检清单
华为·harmonyos
OH_TPC19 小时前
【鸿蒙优选三方库】@react-native-ohos/react-native-screens:原生屏幕导航管理
华为·harmonyos·鸿蒙