Flutter for OpenHarmony 实战:三方库 large_file_handler 的鸿蒙化适配指南
环境搭建指引:https://atomgit.com/CPF-Flutter/flutter_samples/blob/master/docs/ohos/getting-started/flutter-oh-env-setup.md
large_file_handler 解决的是一个很具体的问题:把大文件(Flutter 资源或远程 URL)复制到应用的本地目录,并且边复制边报进度。它的 0.5.2 版支持 Android、iOS、macOS(原生实现)和 Windows、Linux(纯 Dart 实现),没有 OpenHarmony。
这个库的接口少得可爱——五个方法、一条事件通道——但它在鸿蒙上踩到的那个坑很值得写下来:分块读写时偏移量算错,文件大小会分毫不差、内容却整段整段地错。这种错误用"文件存在、大小对"是查不出来的,本篇因此专门做了一套逐字节比对,并且真的靠它抓到了一个 bug。
适配对象:上游 large_file_handler 0.5.2(MIT,对应 main 7987f70);适配产物 TAG 0.5.2-ohos-1.0.0-beta.1。
一、这个库要解决什么
1.1 上游 API
final handler = LargeFileHandler();
// 资源 -> 本地
await handler.copyAssetToLocalStorage(assetName: 'x.bin', targetPath: 'x.bin');
Stream<int> p1 = handler.copyAssetToLocalStorageWithProgress(assetName: 'x.bin', targetPath: 'x.bin');
// URL -> 本地
await handler.copyNetworkAssetToLocalStorage(assetUrl: url, targetPath: 'y.bin');
Stream<int> p2 = handler.copyNetworkAssetToLocalStorageWithProgress(assetUrl: url, targetPath: 'y.bin');
// 是否存在
bool exists = await handler.fileExists(targetPath: 'x.bin');
三个细节决定了适配的形状:
targetPath是相对的,由插件自己用path_provider的getApplicationDocumentsDirectory()拼成绝对路径再交给原生;- 带进度与不带进度是四个独立的方法(不是"传个回调"),它们共用同一条事件通道
file_download_progress; - 进度值就是 0-100 的整数,复制结束时原生侧还会
endOfStream()收尾。
1.2 契约
final methodChannel = const MethodChannel('large_file_handler');
final progressChannel = const EventChannel('file_download_progress');
// 五个方法,参数都是 {assetName, targetPath} 或 {url, targetPath} 或 {targetPath}
// copyAssetToLocal / copyAssetToLocalWithProgress
// copyUrlToLocal / copyUrlToLocalWithProgress
// fileExists -> bool
pubspec 里的平台声明是这样的:
android: { pluginClass: LargeFileHandlerPlugin }
ios: { pluginClass: LargeFileHandlerPlugin }
macos: { pluginClass: LargeFileHandlerPlugin }
windows: { dartPluginClass: LargeFileHandlerDesktop } # 纯 Dart
linux: { dartPluginClass: LargeFileHandlerDesktop } # 纯 Dart
web: { pluginClass: LargeFileHandlerWeb }
而且 lib/src/default_instance_io.dart 里写得很清楚:
LargeFileHandlerPlatform? buildDefaultInstance() => MethodChannelLargeFileHandler();
没有平台门、没有 defaultTargetPlatform 分支——鸿蒙上平台接口的默认实现就是这条方法通道的实现,原生侧把通道接住即可。
1.3 一个不能忘的前置依赖
插件 Dart 侧用 path_provider 把相对路径解析成绝对路径,而 path_provider 自己没有为 ohos 声明 default_package:
# path_provider 2.1.6 的 pubspec
plugin:
platforms:
android: { default_package: path_provider_android }
ios: { default_package: path_provider_foundation }
linux: { default_package: path_provider_linux }
macos: { default_package: path_provider_foundation }
windows: { default_package: path_provider_windows }
也就是说:pub get 不会自动带上鸿蒙实现。鸿蒙宿主必须自己加一行:
dependencies:
path_provider_ohos: ^2.2.1
少了它,插件里第一个方法调用就是 MissingPluginException。示例工程加上之后,getApplicationDocumentsDirectory() 在鸿蒙上返回 <应用 filesDir>/flutter:
应用文档目录
/data/storage/el2/base/files/flutter
二、选库:四道筛 + 在线查重
2.1 四筛
| 筛 | 结果 |
|---|---|
① pub.dev 平台列表有没有 ohos | android, ios, macos, windows, linux, web —— 没有,通过 |
② 上游根目录 / pub.dev 有没有 *_ohos 兄弟包 | 根目录无;large_file_handler_ohos 返回 404,通过 |
| ③ Dart 入口有没有平台门 | 只有 MethodChannel / EventChannel,没有 Platform.is*、defaultTargetPlatform、UnsupportedError,通过 |
| ④ 依赖体检 | node .agents/tools/dep-ohos-check.mjs large_file_handler → 依赖只有 path_provider(有 path_provider_ohos)与纯 Dart 包,通过 |
第四道筛是上一轮新增的:一个插件能不能在鸿蒙上跑,还取决于它依赖的原生插件有没有鸿蒙实现。这一条对 large_file_handler 的结论不是"通过就完事",而是直接产出了 1.3 节的宿主要求——依赖有实现,但必须显式引入。
2.2 在线查重
$ node .agents/tools/live-dedup.mjs large_file_handler
pub.dev : v0.5.2 platforms=[android,ios,macos,windows,linux,web]
atomgit : 四个组织(oh-flutter / CPF-Flutter / hxa-flutter / oh-tpc)均无同名仓库
顺带确认没有撞同主题的库:oh-flutter/flutter_downloader_ohos、CPF-Flutter/fluttertpc_flutter_downloader、fluttertpc_flutter_file_downloader 都是另一个库(flutter_downloader / flutter_file_downloader,偏"下载任务管理"),而 large_file_handler 的定位是"把一份数据可靠地写到指定路径并报进度",接口只有五个方法。
2.3 基线
上游仓库没有发布任何 tag,所以基线取 main 的 7987f70,并逐文件核对它与 pub.dev 上 0.5.2 的归档一致:
identical after EOL normalisation: 8 / 8
still different: []
(上一轮踩过"git tag 落后于已发布版本"的坑,这一步现在每篇都做。)
三、六步适配流程
第一步:把上游同步到 AtomGit
node .agents\tools\atomgit.mjs create oh-flutter large_file_handler "<中文描述>"
node .agents\tools\atomgit.mjs verify oh-flutter large_file_handler # 回读校验中文没被 ASCII 毁掉
第二步:本地克隆(并用发布版核对基线)
git clone https://gh-proxy.com/https://github.com/DenisovAV/large_file_handler.git lfh_work
cd lfh_work
git log --oneline -1 # 7987f70 Merge pull request #12 ...
git tag # (空:上游没有 tag)
第三步:建分支并用框架命令补出鸿蒙化目录
git checkout -b feat/ohos_large_file_handler_0.5.2
flutter create -t plugin --platforms ohos --org com.example .
这一次 .metadata 里本来就是 project_type: plugin,省掉了上一轮那两个报错(-t plugin 与 project_type 不匹配、--org 必填)。但模板垃圾依旧,见第六节。
第四步:适配过程(新增了什么、为什么)
| 文件 | 作用 |
|---|---|
ohos/index.ets | HAR 出口 |
ohos/src/main/ets/components/plugin/LargeFileHandlerPlugin.ets | 插件本体:五个方法 + 事件通道 |
pubspec.yaml | 新增 ohos: pluginClass: LargeFileHandlerPlugin |
第五步:补全额外文件
两份 README(中英)+ CHANGELOG,并在根 README.md 的 Supported Platforms 表里加一行 OpenHarmony。
第六步:推送并打 TAG
git add -A && git commit -F commit-msg.txt
git remote add atomgit https://atomgit.com/oh-flutter/large_file_handler.git
git push atomgit HEAD:main
git push atomgit feat/ohos_large_file_handler_0.5.2
git tag -a 0.5.2-ohos-1.0.0-beta.1 -m "large_file_handler OpenHarmony 适配 0.5.2-ohos-1.0.0-beta.1"
git push atomgit 0.5.2-ohos-1.0.0-beta.1
推完的仓库首页:

四、代码写在哪个文件
large_file_handler/
├── ohos/
│ ├── index.ets # HAR 出口(flutter create 生成)
│ ├── oh-package.json5 # 包名/版本/协议(生成后手改)
│ └── src/main/ets/components/plugin/
│ └── LargeFileHandlerPlugin.ets # ★ 插件本体
├── example/
│ ├── assets/sample_1mb.bin # ★ 1MiB 随机资源,用来验证"逐字节一致"
│ ├── lib/main.dart # ★ 鸿蒙演示页(本次重写)
│ └── ohos/ # 应用工程(flutter create 生成)
└── pubspec.yaml # ★ 新增 ohos: pluginClass
4.1 资源复制:getRawFd() + 分块读写
Flutter 资源在 HAP 里的落点是固定的,这一点可以直接从构建产物里确认:
$ tar -tf entry-default-signed.hap | findstr sample_1mb
resources/rawfile/flutter_assets/assets/sample_1mb.bin
所以 rawfile 路径 = flutter_assets/ + Dart 传来的 assets/<名字>。拿到 fd 之后分块处理:
const raw = await context.resourceManager.getRawFd(rawPath); // { fd, offset, length }
const dest = fs.openSync(targetPath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE | fs.OpenMode.TRUNC);
const buffer = new ArrayBuffer(CHUNK_SIZE);
let read = 0;
for (;;) {
const want = Math.min(CHUNK_SIZE, raw.length - read);
if (want <= 0) break;
// 关键:每次都要给绝对偏移
const length = fs.readSync(raw.fd, buffer, { offset: raw.offset + read, length: want });
if (length <= 0) break;
fs.writeSync(dest.fd, buffer, { length: length });
read += length;
if (withProgress) this.reportBytes(read, raw.length);
}
4.2 URL 下载:http.requestInStream() 流式写盘
const request = http.createHttp();
request.on('dataReceiveProgress', (info) => { total = info.totalSize; });
request.on('dataReceive', (chunk) => {
fs.writeSync(dest.fd, chunk, { length: chunk.byteLength });
written += chunk.byteLength;
if (withProgress && total > 0) this.reportBytes(written, total);
});
const code = await request.requestInStream(url, {
method: http.RequestMethod.GET,
connectTimeout: 30000,
readTimeout: 0, // 大文件不设读超时
expectDataType: http.HttpDataType.ARRAY_BUFFER,
});
if (code !== 200 && code !== 206) throw new Error(`Failed to download file: ${code}`);
为什么不用 @ohos.request(系统下载代理):它把任务交给系统服务、产物落进系统下载目录、还附带系统通知,与本库"写到你给的 targetPath、进度由这条通道上报"的契约不一致;另外模拟器上根本没有对应的系统能力(hidumper -ls 列出的 98 个服务里没有 request/download 相关项)。用进程内的流式 HTTP,一来契约完全吻合,二来几十 MB 的响应体也不会整块进内存。
4.3 进度:0-100 整数 + 收尾 endOfStream
上游 Android 每读 1KB 报一次、结束补 100 并 endOfStream(),Dart 侧靠 onDone 收尾。鸿蒙侧沿用同样的可观测语义,只做两处工程化处理:
- 块大小取 64KB(1KB 对几十 MB 的文件会产生几万条事件);
- 只在百分比变化时上报(同一百分比不重复发)。
失败时把错误推进进度流:sink.error('ERROR', message, null)。上游 0.5.1 专门修过这一点——否则调用方会看到"进度流正常结束",以为文件复制成功了。
五、一个只有逐字节比对才能抓住的坑
第一版的资源复制是这样写的:“第一块按 raw.offset 读,之后的块交给文件指针自己前进”:
// ❌ 第一版
const length = first
? fs.readSync(raw.fd, buffer, { offset: raw.offset, length: want })
: fs.readSync(raw.fd, buffer, { length: want });
结果是:第二次起每次都从头读,写出来的文件是"第一块 64KB 重复 16 遍"。而它的表现是:
| 检查项 | 结果 |
|---|---|
| 文件是否存在 | ✅ 存在 |
| 文件大小 | ✅ 1048576 字节(与资源一模一样) |
| 进度事件 | ✅ 16 个(6, 12, 18, 25, 31, 37 … 100) |
| 内容 | ❌ 全错——每块都是第一块 |
一开始我用 SHA-256 看出了差异,但直到在演示页里加了一个"与 asset 逐字节比对"的按钮,才把问题定位到具体字节:
资源复制结果逐字节比对
第 65536 字节起不同:asset=0xd6,文件=0x50
65536 正好是块大小,指向"从第二块开始读错"。改成每次都传绝对偏移(offset: raw.offset + read)之后:
资源复制结果逐字节比对
逐字节一致(1048576 字节)
这条经验值得单独记一笔:验证"文件复制"时,"大小对不对"几乎等于没验证。分块读写里的偏移、缓冲区复用、最后一块的边界,任何一个出错都不会改变文件大小。要么对哈希,要么逐字节比。
六、编译与构建踩坑
6.1 integration_test 会让鸿蒙构建直接失败
上游示例的 dev_dependencies 里有 integration_test: { sdk: flutter },鸿蒙构建时:
> hvigor ERROR: AdaptorError 00303231 Configuration Error
Error Message: The srcPath is not a relative path: D:/flutter/flutter_flutter/packages/integration_test/ohos
工具会把每个"dev 依赖里的插件"都登记给 OHOS,而 integration_test 这个 SDK 包没有 ohos 模块,于是 hvigor 拿到一个绝对路径就报错。处理办法是从示例里移除该依赖,并说明上游那两个集成测试为什么没有保留——这属于示例侧的取舍,插件本身不受影响。
6.2 ArkTS 不允许抛"联合类型"
copyUrl 里我原本把写盘失败先存成 let writeError: Error | null,请求结束后再 throw writeError,ArkTS 编译器不认:
Error Message: "throw" statements cannot accept values of arbitrary types
(arkts-limited-throw)
改成存字符串消息、需要时 throw new Error(...) 即可:
let writeErrorMessage: string = '';
// ...
if (writeErrorMessage !== '') throw new Error(writeErrorMessage);
6.3 模板垃圾这次进了 lib/、test/,还多出 linux/、windows/
flutter create -t plugin --platforms ohos . 之后,git ls-files --others --exclude-standard 列出了 23 项不该存在的东西:
| 类别 | 例子 | 处理 |
|---|---|---|
| 平台模板 | android/*.gradle.kts、linux/、windows/ | 删(本插件的 Linux/Windows 是纯 Dart 实现,本来就没有原生目录) |
| Dart 模板 | lib/large_file_handler_method_channel.dart、test/large_file_handler_test.dart | 删(会污染包的公开 API) |
| 示例模板 | example/android/*.kts、example/ios/.../SceneDelegate.swift、example/test/ | 删 |
| 隐私清单 | ios/.../PrivacyInfo.xcprivacy、macos/.../PrivacyInfo.xcprivacy | 删 |
清理姿势(与上一轮一致,重点是只删未跟踪的文件):
$untracked = git ls-files --others --exclude-standard
$junk = $untracked | Where-Object { $_ -notmatch '(^|/)ohos/' }
foreach ($f in $junk) { Remove-Item -LiteralPath $f -Force }
6.4 其它
flutter pub get会把别的平台生成的注册文件按 CRLF 重写,git status里出现一堆"已修改"。用git diff --ignore-cr-at-eol --quiet判断:只是换行符差异就git checkout --掉,别把噪音带进提交。- release 构建下
Log.i不输出(引擎Log类默认级别 WARN),验证一律flutter build hap --debug --target-platform ohos-x64。 - ABI /
PUB_CACHE/ 唤醒设备 / 签名:--target-platform ohos-x64、$env:PUB_CACHE="E:\pub-cache"、hdc shell power-shell wakeup、先在example/ohos跑devecocli signature generate,提交前清空signingConfigs。
七、真机(模拟器)验证
7.1 验证环境与数据源
| 项 | 值 |
|---|---|
| Flutter for OpenHarmony SDK | 3.44.9+ohos-0.0.1-canary1(Dart 3.12.2) |
| DevEco Studio | 26.0.0.621(OpenHarmony SDK API 26) |
| 设备 | Pura X View 模拟器,HarmonyOS 7.0.0(26.0.0) Beta2,ohos-x64 |
| 下载源 | 宿主机器上的 HTTP 服务(模拟器经 QEMU NAT 访问 10.0.2.2),40MiB 随机数据 |
下载源刻意放在宿主机器上而不是公网:http-test-server.mjs 支持限速,本次设成 2.5MB/s,40MiB 需要约 17 秒,足够让进度条在截图里停在中间、也足够让进度事件跑满 101 个点。
node .agents/tools/http-test-server.mjs httpd --port 8899 --throttle 2500000
# httpd/test_40mb.bin: 41943040 字节,sha256 = 6be2cf5ea35faaaf388faecc8d55b4935be4e00488d6cc3f0e387165178a76aa
7.2 实测数据
| 操作 | 文件 | 大小 | 应用内 SHA-256(前 16 位) | 期望值(宿主侧) |
|---|---|---|---|---|
| 复制资源(带进度) | sample_1mb.bin | 1048576 | 86a786ac32eb8523… | 86a786ac32eb8523…(HAP 内资源) |
| 下载 URL(带进度) | download_40mb.bin | 41943040 | 6be2cf5ea35faaaf… | 6be2cf5ea35faaaf…(宿主文件) |
配合界面上的进度统计:
| 操作 | 进度点数量 | 序列 |
|---|---|---|
| 复制资源(带进度) | 16 | 6, 12, 18, 25, 31, 37 … 100(1MiB ÷ 64KB = 16 块) |
| 下载 URL(带进度) | 101 | 0, 1, 2, 3, 4, 5 … 100(每个百分比一个点) |
| 复制资源(不带进度) | 0 | 事件通道没有被订阅(日志里没有 progress stream listened) |
| 下载 URL(不带进度) | 0 | 同上 |
原生日志(节选):
LargeFileHandlerPlugin --> large_file_handler channels registered
LargeFileHandlerPlugin --> progress stream listened
LargeFileHandlerPlugin --> copied asset assets/sample_1mb.bin -> /data/storage/el2/base/files/flutter/sample_1mb.bin (1048576 bytes)
LargeFileHandlerPlugin --> progress stream cancelled
LargeFileHandlerPlugin --> downloaded http://10.0.2.2:8899/test_40mb.bin -> /data/storage/el2/base/files/flutter/download_40mb.bin (41943040 bytes, http 200)
启动后的样子(两个目标文件都还不存在):

复制完成后:进度点 16 个、SHA-256 与 HAP 内资源一致、逐字节比对通过。

下载进行到 33% 时的界面(进度流已记录 34 个点,说明是连续上报而不是只在结束时给一个 100):

下载完成后的最终状态:

八、已知限制
- 资源复制依赖
getRawFd():资源必须随 HAP 打包(Flutter 资源的默认落点就是resources/rawfile/flutter_assets/)。 - URL 下载在应用进程内完成:不申请后台任务权限,也不做断点续传(本库的 Dart 接口没有这两个语义);应用退到后台后能否继续下载取决于系统策略。
- 进度事件数量与上游不同:块大小 1KB → 64KB、相同百分比去重,可观测的序列一致但事件更少。
- 示例移除了
integration_test:见 6.1,这是示例侧取舍。 - 示例里多了
crypto依赖:只用于演示页在设备上算 SHA-256(纯 Dart)。 - 示例资源是 1MiB 随机数据:为了让"逐字节比对"和"进度 16 个点"可复现;仓库因此多了 1MiB 二进制文件。
九、常见问题
Q1:为什么鸿蒙宿主还要额外加 path_provider_ohos?
因为本插件 Dart 侧调用 path_provider 的 getApplicationDocumentsDirectory() 来解析相对路径,而 path_provider 只为 android/ios/linux/macos/windows 声明了 default_package,没有为 ohos 背书,pub get 不会自动把 path_provider_ohos 拉进来。这是鸿蒙生态里用官方插件的一个通例:主包给你 API,<包名>_ohos 给你实现,缺一不可。加上之后实测返回 /data/storage/el2/base/files/flutter。
Q2:为什么不直接用 @ohos.request 的下载代理?它不是更"系统"吗?
它确实是系统能力,但语义与本库不匹配:任务交给系统服务、文件落到系统下载目录、还弹系统通知,而本库要求"写到我给的 targetPath、进度走我这条事件通道"。另外模拟器上没有该项系统能力(hidumper -ls 的 98 个服务里没有 request/download 相关项),走它会让演示完全无法验证。用 http.requestInStream() 既符合契约,又不需要任何系统服务。
Q3:分块读为什么非要每次给绝对偏移?
resourceManager.getRawFd() 返回的 fd 指向整个 HAP 文件,raw.offset 才是资源在里面的起点,fs.readSync(fd, buffer, { offset }) 的 offset 是相对这个 fd 的绝对位置。第一版只给第一块传偏移、指望文件指针自动前进,实际是每次从头读——文件大小依旧正确,内容全错。这个坑在第五节有完整的证据截图。
Q4:怎么证明"复制真的写对了"?
两条:①应用内用 crypto 算 SHA-256,与源文件(HAP 内资源 / 宿主上的原文件)比对;②再加一个"与 asset 逐字节比对"按钮,报出第一个不同字节的位置。只看"文件存在 + 大小相等"是不够的——本节的 bug 就是这样漏掉的。为了让比对有意义,示例资源用的是 1MiB 随机数据(不是可压缩的文本)。
Q5:进度为什么不是 1KB 报一次?会不会和上游行为不一致?
值域与收尾语义完全一致(0-100 整数、结束补 100 并 endOfStream()),只是把块从 1KB 放大到 64KB 并对重复百分比去重。对调用方来说,Stream<int> 的可观测内容一样(都是从低到高、以 100 结束),只是事件更少。40MiB 的下载实测是 101 个点(每个百分比一个)。
Q6:下载失败会怎样?
原生侧先把错误写进进度流(sink.error('ERROR', message, null)),再让方法调用以 PlatformException('DOWNLOAD_FAILED', ...) 失败——与上游 0.5.1 之后的约定一致。Dart 侧 _progressStream 会把事件通道的错误导入调用方正在监听的那条流,所以调用方不会看到"流正常结束"这种假成功。非 2xx 响应会被当作失败并带上 HTTP 状态码。
Q7:不带进度的两个方法会不会也订阅事件通道?
不会。实测日志里只有带进度的两次调用出现过 progress stream listened / cancelled,不带进度的两次调用一条都没有——这也是"四个方法"而不是"一个方法加回调"的价值所在:不需要进度时不会白建一条事件通道。
Q8:示例为什么要删掉 integration_test?
因为它在场时鸿蒙构建会直接失败(AdaptorError 00303231: The srcPath is not a relative path: .../packages/integration_test/ohos):工具会把 dev 依赖里的插件都登记给 OHOS,而 integration_test 这个 SDK 包没有 ohos 模块。移除它只影响示例自身的集成测试,插件的功能验证改由演示页 + 宿主 HTTP 服务完成。
十、本篇用到的库
| 项 | 值 |
|---|---|
| 适配仓库 | https://atomgit.com/oh-flutter/large_file_handler |
| 上游仓库 | https://github.com/DenisovAV/large_file_handler |
| 上游版本 | 0.5.2(MIT,对应 main 7987f70;上游未发布 tag) |
| 适配 TAG | 0.5.2-ohos-1.0.0-beta.1 |
| 适配分支 | feat/ohos_large_file_handler_0.5.2 |
| 平台目录 | ohos/(插件 HAR)、example/ohos/(示例工程) |
| 通道 | 方法通道 large_file_handler、事件通道 file_download_progress |
依赖写法(写死 TAG,不跟分支):
dependencies:
large_file_handler:
git:
url: https://atomgit.com/oh-flutter/large_file_handler.git
ref: 0.5.2-ohos-1.0.0-beta.1
# 鸿蒙宿主必须显式引入,否则插件里的 getApplicationDocumentsDirectory() 会抛
# MissingPluginException
path_provider_ohos: ^2.2.1
验证环境
| 项 | 值 |
|---|---|
| Flutter for OpenHarmony SDK | 3.44.9+ohos-0.0.1-canary1 |
| Dart | 3.12.2 |
| DevEco Studio | 26.0.0.621(OpenHarmony SDK API 26) |
| 设备 | Pura X View 模拟器,HarmonyOS 7.0.0(26.0.0) Beta2,ohos-x64 |
| 构建产物 | example/build/ohos/hap/entry-default-signed.hap |
复现命令
# 1. 在宿主机器上起一个限速 HTTP 服务(40MiB 随机文件,约 2.5MB/s)
node .agents/tools/http-test-server.mjs httpd --port 8899 --throttle 2500000
# 2. 构建(PUB_CACHE 必须与工程同盘;模拟器是 ohos-x64)
$env:PUB_CACHE = "E:\pub-cache"
cd example
flutter pub get
flutter build hap --debug --target-platform ohos-x64
# 3. 安装并启动
hdc shell power-shell wakeup
hdc install -r build/ohos/hap/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.example.large_file_handler_example
# 4. 依次点击:复制资源(带进度)→ 与 asset 逐字节比对
# → 下载 URL(带进度)→ 重新检查文件状态
hdc shell snapshot_display -f /data/local/tmp/lfh.jpeg
hdc file recv /data/local/tmp/lfh.jpeg .
# 5. 取原生日志
hdc shell hilog -x | Select-String "LargeFileHandlerPlugin"
欢迎加入 CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter
更多推荐



所有评论(0)