Flutter到HarmonyOS Next 的跨越:memory_info库的鸿蒙适配之旅

发布于:2025-05-15 ⋅ 阅读:(10) ⋅ 点赞:(0)

Flutter到鸿蒙的跨越:memory_info库的鸿蒙适配之旅

本项目作者:kirk/坚果

您可以使用这个Flutter插件来更改应用程序图标上的角标

作者仓库:https://github.com/MrOlolo/memory_info/tree/master/memory_info

在数字化浪潮的推动下,跨平台开发框架如 Flutter 凭借其高效、便捷的特性,成为了开发者们的宠儿。而鸿蒙系统的崛起,更是为跨平台开发注入了新的活力。为了助力开发者在鸿蒙生态中快速实现 memory_info可帮助您获取设备内存信息(ram&rom),本文将深入浅出地为大家解析如何适配 memory_info 三方库至鸿蒙平台。

一、适配鸿蒙版 memory_info 三方库

(一)版本选择与仓库简介

我们先去 pub 上查看最新版本,我们选择以 0.0.10版本为基础进行适配。memory_info可帮助您获取设备内存信息(ram&rom),其 GitHub 仓库为https://github.com/MrOlolo/memory_info/tree/master/memory_info ,我们的目标是将这个插件适配到鸿蒙平台。

(二)引入背景与使用场景

在 OpenHarmony 北向生态的发展过程中,许多已经适配了 Flutter 的厂商在接入 OpenHarmony 时,都希望能够继续使用 memory_info 来实现内存查看功能。因此,我们提供了这个适配方案,采用插件化的适配器模式,帮助生态伙伴快速实现产品化。

本方案适用于已经支持 Flutter 框架的设备在移植到 OpenHarmony 系统过程中,作为一个备选方案。

(三)使用文档与插件库使用

适配 OpenHarmony 平台的详细使用指导可以参考:Flutter使用指导文档

在项目中使用该插件库时,只需在 pubspec.yaml 文件的 dependencies 中新增如下配置:

dependencies:
  memory_info:
    git:
      url: "https://gitcode.com/nutpi/memory_info.git"
      path: ""

然后在项目根目录运行 flutter pub get,即可完成依赖添加

接下来是具体的适配过程。

二、适配过程详解

(一)准备工作

确保已经配置好了 Flutter 开发环境,具体可参考 Flutter 配置指南。同时,从 官方插件库 下载待适配的三方插件。本指导书, 以适配 memory_info 为例

image-20250417200546042

(二)插件目录结构

下载并解压插件后,我们会看到以下目录结构:

  • lib :对接 Dart 端代码的入口,由此文件接收到参数后,通过 channel 将数据发送到原生端。
  • android :安卓端代码实现目录。
  • ios :iOS 原生端实现目录。
  • example :一个依赖于该插件的 Flutter 应用程序,用于说明如何使用它。
  • README.md :介绍包的文件。
  • CHANGELOG.md :记录每个版本中的更改。
  • LICENSE :包含软件包许可条款的文件。

(三)创建插件的鸿蒙模块

在插件目录下,打开 Terminal,执行以下命令来创建一个鸿蒙平台的 Flutter 模块:

flutter create . --org com.mrololo.memory_info --template=plugin --platforms=ohos

步骤:

  1. 用vscode/trae打开刚刚下载好的插件。

  2. 打开Terminal,cd到插件目录下。

  3. 执行命令flutter create . --org com.mrololo.memory_info --template=plugin --platforms=ohos 创建一个ohos平台的flutter模块。

第一个问题,修改sdk的版本,适配旧版本。

我们做好修改就好。

(四)在根目录下添加鸿蒙平台配置

在项目根目录的 pubspec.yaml 文件中,添加鸿蒙平台的相关配置:

name: memory_info
description: Flutter package to get device memory info(ram&rom) at android/ios devices
repository: https://com.nutpi.memory_info/
version: 0.0.4

environment:
  sdk: ">=2.12.0 <4.0.0"
  flutter: ">=1.20.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter.
flutter:
  plugin:
    platforms:
      android:
        package: com.mrololo.memory_info
        pluginClass: MemoryInfoPlugin
      ios:
        pluginClass: MemoryInfoPlugin
      ohos:
        package: com.mrololo.memory_info
        pluginClass: MemoryInfoPlugin

(五)编写鸿蒙插件的原生 ArkTS模块

1. 创建鸿蒙插件模块

使用 DevEco Studio 打开鸿蒙项目。

2. 修改相关配置文件

ohos 目录内的 oh-package.json5 文件中添加 libs/flutter.har 依赖,并创建 .gitignore 文件,添加以下内容以忽略 libs 目录:

/node_modules
/oh_modules
/local.properties
/.preview
/.idea
/build
/libs
*.har
/.cxx
/.test
/BuildProfile.ets
/oh-package-lock.json5

oh-package.json5 文件内容如下:

{
  "name": "memory_info",
  "version": "1.0.0",
  "description": "Flutter package to get device memory info(ram&rom) at Android/ios/OpenHarmony devices",
  "main": "index.ets",
  "author": "nutpi",
  "license": "Apache-2.0",
  "dependencies": {
    "@ohos/flutter_ohos": "file:./har/flutter.har"
  }
}

ohos 目录下创建 index.ets 文件,导出配置:



import MemoryInfoPlugin from './src/main/ets/components/plugin/MemoryInfoPlugin';
export default MemoryInfoPlugin;
3. 编写 ETS 代码

ohos的api可以参考:https://gitcode.com/openharmony/docs

以下是 MemoryInfoPlugin 文件的代码示例:

import {
  FlutterPlugin,
  FlutterPluginBinding,
  MethodCall,
  MethodCallHandler,
  MethodChannel,
  MethodResult,
} from '@ohos/flutter_ohos';
import { storageStatistics,statfs } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hidebug } from '@kit.PerformanceAnalysisKit';
import appManager from '@ohos.application.appManager';

/** MemoryInfoPlugin **/
export default class MemoryInfoPlugin implements FlutterPlugin, MethodCallHandler {
  private channel: MethodChannel | null = null;

  constructor() {
  }

  getUniqueClassName(): string {
    return "MemoryInfoPlugin"
  }

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    this.channel = new MethodChannel(binding.getBinaryMessenger(), "com.nutpi.memory_info");
    this.channel.setMethodCallHandler(this)


  }

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    if (this.channel != null) {
      this.channel.setMethodCallHandler(null)
    }
  }

   onMethodCall(call: MethodCall, result: MethodResult)  {
    if (call.method == "getPlatformVersion") {
      result.success("OpenHarmony ^ ^ ")
    } else if (call.method == "getDiskSpace") {
      try {
        const Info = new Map<string, number>();
        storageStatistics.getTotalSize()
        // 获取内置存储的总空间大小(单位为Byte),同步返回
        let diskTotalSpaceBytes =  storageStatistics.getFreeSizeSync();
        // 获取内置存储的可用空间大小(单位为Byte),同步返回
        let diskFreeSpaceBytes =  storageStatistics.getTotalSizeSync();
         // 转换为 MB
         const mbFactor = 1024 * 1024;
         let diskTotalSpaceMB = diskTotalSpaceBytes / mbFactor;
         let diskFreeSpaceMB = diskFreeSpaceBytes / mbFactor;

         Info.set("diskTotalSpace", diskTotalSpaceMB);
         Info.set("diskFreeSpace", diskFreeSpaceMB);

         console.info(`getDiskSpace success: total=${diskTotalSpaceMB}MB, free=${diskFreeSpaceMB}MB`);
         result.success(Info);
      } catch (err) {
        console.error("getDiskSpace failed with error:" + JSON.stringify(err));
        // 在 Flutter 端,通常期望一个 Map 或者 null/error
        // 这里返回一个空的 Map 或者可以考虑 result.error
        result.error("DISK_SPACE_ERROR", "Failed to get disk space", JSON.stringify(err));
      }
    } else if (call.method == "getMemoryInfo") {

      const Info = new Map<string, number>();
      // 转换为 MB
      const mbFactor = 1024 * 1024;

      let systemMemInfo: hidebug.SystemMemInfo = hidebug.getSystemMemInfo();

      // Convert bigint to number before division
      Info.set("total", Number(systemMemInfo.totalMem)/mbFactor);
      Info.set("free", Number(systemMemInfo.freeMem)/mbFactor);
      Info.set("usedByApp", Number(systemMemInfo.availableMem)/mbFactor);
      console.info(`totalMem: ${systemMemInfo.totalMem}, freeMem: ${systemMemInfo.freeMem}, ` +
        `availableMem: ${systemMemInfo.availableMem}`);
      //获取当前应用的存储空间大小。
      storageStatistics.getCurrentBundleStats((err: BusinessError, bundleStats: storageStatistics.BundleStats) => {
        if (err) {
          console.error(`Invoke getCurrentBundleStats failed, code is ${err.code}, message is ${err.message}`);
        } else {
          console.info(`Invoke getCurrentBundleStats succeeded, appsize is ${bundleStats.appSize}`);
          Info.set("appSize", Number(bundleStats.appSize)/mbFactor);
        }
        result.success(Info);
      });
    } else {
      result.notImplemented()
    }
   }
}

这里我主要参考的是

三、应用及文件系统空间统计

1.storageStatistics.getCurrentBundleStats

getCurrentBundleStats(): Promise

应用异步获取当前应用存储空间大小(单位为Byte),以Promise方式返回。

系统能力:SystemCapability.FileManagement.StorageService.SpatialStatistics

返回值:

类型 说明
Promise<Bundlestats> Promise对象,返回指定卷上的应用存储空间大小(单位为Byte)。

错误码:

以下错误码的详细介绍请参见文件管理错误码

错误码ID 错误信息
401 The input parameter is invalid. Possible causes: Mandatory parameters are left unspecified.
13600001 IPC error.
13900042 Unknown error.

示例:

import { BusinessError } from '@kit.BasicServicesKit';storageStatistics.getCurrentBundleStats().then((BundleStats: storageStatistics.BundleStats) => {  console.info("getCurrentBundleStats successfully:" + JSON.stringify(BundleStats));}).catch((err: BusinessError) => {  console.error("getCurrentBundleStats failed with error:"+ JSON.stringify(err));});

https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-storage-statistics#storagestatisticsgetfreesize15

2.应用及文件系统空间统计

在系统中,可能出现系统空间不够或者cacheDir等目录受系统配额限制等情况,需要应用开发者关注系统剩余空间,同时控制应用自身占用的空间大小。

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/app-fs-space-statistics

表1 文件系统空间和应用空间统计

模块 接口名 功能
@ohos.file.storageStatistics getCurrentBundleStats 获取当前应用的存储空间大小(单位为Byte)。
@ohos.file.storageStatistics getFreeSize 异步获取内置存储的总空间大小(单位为Byte)。
@ohos.file.storageStatistics getTotalSize 异步获取内置存储的可用空间大小(单位为Byte)。

表2 应用空间统计

BundleStats属性 含义 统计路径
appSize 应用安装文件大小(单位为Byte) 应用安装文件保存在以下目录:/data/storage/el1/bundle
cacheSize 应用缓存文件大小(单位为Byte) 应用的缓存文件保存在以下目录:/data/storage/el1/base/cache/data/storage/el1/base/haps/entry/cache/data/storage/el2/base/cache/data/storage/el2/base/haps/entry/cache
dataSize 应用文件存储大小(除应用安装文件和缓存文件)(单位为Byte) 应用文件由本地文件、分布式文件以及数据库文件组成。本地文件保存在以下目录(注意缓存文件目录为以下目录的子目录):/data/storage/el1/base/data/storage/el2/base分布式文件保存在以下目录:/data/storage/el2/distributedfiles数据库文件保存在以下目录:/data/storage/el1/database/data/storage/el2/database

https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-hidebug#hidebuggetsystemmeminfo12

3.使用 HiDebug 模块

HiDebug 提供了一系列接口,可以获取系统的内存信息,进而间接获取 RAM size 。具体步骤如下:

  • 导入 HiDebug 模块 :在代码中导入 HiDebug 模块,import { hidebug } from '@ohos.hidebug';

4.SystemMemInfo

描述系统内存信息。

系统能力:SystemCapability.HiviewDFX.HiProfiler.HiDebug

名称 类型 必填 说明
totalMem bigint 系统总的内存,以KB为单位,计算方式:/proc/meminfo: MemTotal。
freeMem bigint 系统空闲的内存,以KB为单位,计算方式:/proc/meminfo: MemFree。
availableMem bigint 系统可用的内存,以KB为单位,计算方式:/proc/meminfo: MemAvailable
  • usedByApp: 表示当前应用程序占用的内存大小(单位:MB)。这是通过 Runtime 类计算得到的应用已分配内存减去其中的空闲内存。
  • total: 表示设备的总内存(RAM)大小(单位:MB)。这是通过 ActivityManager.MemoryInfo 获取的系统总内存。
  • free: 表示设备当前可用的内存大小(单位:MB)。这是通过 ActivityManager.MemoryInfo 获取的系统可用内存,指系统在开始强制关闭后台进程之前可用的内存。
  • lowMemory: 一个布尔值,表示系统当前是否处于低内存状态。如果为 true,则表示系统内存不足。

5.appManager.isRamConstrainedDevice7+

isRamConstrainedDevice(): Promise

查询是否为ram受限设备。使用Promise异步回调。

系统能力:SystemCapability.Ability.AbilityRuntime.Core

返回值:

类型 说明
Promise Promise对象。返回true表示是ram受限设备;返回false表示不是ram受限设备。

示例:

import appManager from '@ohos.application.appManager';import { BusinessError } from '@ohos.base';
appManager.isRamConstrainedDevice().then((data) => {    console.log(`The result of isRamConstrainedDevice is: ${JSON.stringify(data)}`);}).catch((error: BusinessError) => {    console.error(`error: ${JSON.stringify(error)}`);});

https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-application-appmanager

6.appManager.isRamConstrainedDevice7+

isRamConstrainedDevice(callback: AsyncCallback): void

查询是否为ram受限设备。使用callback异步回调。

系统能力:SystemCapability.Ability.AbilityRuntime.Core

参数:

参数名 类型 必填 说明
callback AsyncCallback 回调函数。返回true表示当前是ram受限设备;返回false表示当前不是ram受限设备。

示例:

import appManager from '@ohos.application.appManager';
appManager.isRamConstrainedDevice((error, data) => {    if (error && error.code !== 0) {        console.error(`isRamConstrainedDevice fail, error: ${JSON.stringify(error)}`);    } else {        console.log(`The result of isRamConstrainedDevice is: ${JSON.stringify(data)}`);    }});

7.使用 HiDebug 模块

HiDebug 提供了一系列接口,可以获取系统的内存信息,进而间接获取 RAM size 。具体步骤如下:

  • 导入 HiDebug 模块 :在代码中导入 HiDebug 模块,import { hidebug } from '@ohos.hidebug';
  • 调用接口获取内存信息 :调用 hidebug.getSystemMemInfo() 接口获取系统内存信息,该方法返回一个对象,其中包含了系统的总内存、可用内存等信息。

https://github.com/SebghatYusuf/system_info_plus

四、编写 Example

1. 创建 Example 应用

在插件根目录下创建一个名为 example 的文件夹,用于存放示例应用。在 example 文件夹中,创建一个鸿蒙平台的 Flutter 应用,用于验证插件功能。

2. 签名与运行

使用 Deveco Studio 打开 example > ohos 目录,单击 File > Project Structure > Project > Signing Configs,勾选 Automatically generate signature,等待自动签名完成。然后运行以下命令:

flutter pub get

 flutter build hap --debug

如果应用正常启动,说明插件适配成功。如果没有,欢迎大家联系坚果派一起支持。

五、总结

通过以上步骤,我们成功地将 memory_info 三方库适配到了鸿蒙平台。这个过程涉及到了解插件的基本信息、配置开发环境、创建鸿蒙模块、编写原生代码以及测试验证等多个环节。希望这篇博客能够帮助到需要进行 memory_info可帮助您获取设备内存信息(ram&rom) 鸿蒙适配的开发者们,让大家在鸿蒙生态的开发中更加得心应手。

六、参考


网站公告

今日签到

点亮在社区的每一天
去签到