Flutter到HarmonyOS Next 的跨越:memory_info库的鸿蒙适配之旅
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 为例
(二)插件目录结构
下载并解压插件后,我们会看到以下目录结构:
- 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
步骤:
用vscode/trae打开刚刚下载好的插件。
打开Terminal,cd到插件目录下。
执行命令
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();// 转换为 MBconst 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.errorresult.error("DISK_SPACE_ERROR", "Failed to get disk space", JSON.stringify(err));}} else if (call.method == "getMemoryInfo") {const Info = new Map<string, number>();// 转换为 MBconst mbFactor = 1024 * 1024;let systemMemInfo: hidebug.SystemMemInfo = hidebug.getSystemMemInfo();// Convert bigint to number before divisionInfo.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 getflutter build hap --debug
如果应用正常启动,说明插件适配成功。如果没有,欢迎大家联系坚果派一起支持。
五、总结
通过以上步骤,我们成功地将 memory_info 三方库适配到了鸿蒙平台。这个过程涉及到了解插件的基本信息、配置开发环境、创建鸿蒙模块、编写原生代码以及测试验证等多个环节。希望这篇博客能够帮助到需要进行 memory_info可帮助您获取设备内存信息(ram&rom) 鸿蒙适配的开发者们,让大家在鸿蒙生态的开发中更加得心应手。
六、参考
- [如何使用Flutter与OpenHarmony通信 FlutterChannel](https://gitcode.com/openharmony-sig/flutter_samples/blob/master/ohos/docs/04_development/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8Flutter%E4%B8%8EOpenHarmony%E9%80%9A%E4%BF%A1 FlutterChannel.md)
- [开发module](https://gitcode.com/openharmony-sig/flutter_samples/blob/master/ohos/docs/04_development/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E6%B7%B7%E5%90%88%E5%BC%80%E5%8F%91 module.md)
- 开发package
- 开发plugin
- [开发FFI plugin](https://gitcode.com/openharmony-sig/flutter_samples/blob/master/ohos/docs/04_development/%E5%BC%80%E5%8F%91FFI plugin.md)
- developing-packages
- 适配仓库地址