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
- 適配倉庫地址