Flutter 鸿蒙 HiTrace 请求归因:图片压缩等待时,主线程在做什么

📦 Flutter 三方库 flutter_native_image 是用于本地图片压缩、缩放与裁剪的 package。我在鸿蒙图片处理页面排查等待时,原有鸿蒙实现只能看到调用总耗时而无法定位内部阶段。我在原库基础上增加了按请求开启的 HiTrace 阶段追踪,并补齐了压缩与 EXIF 阶段的资源释放。
完整代码已提交 PR 至官方仓库 CPF-Flutter/flutter_native_image,有问题可以到仓库提 Issue,也可以来 鸿蒙系统Flutter开源库社区 交流。

前言

我做了一个鸿蒙图片处理页面,先在 Mate X7 模拟器上连续压缩同一张图片,后来又接到 华为畅享 100 Pro Max 真机(型号 YEW-AL80)上复测。页面能显示完成次数和总耗时,但首轮为什么更慢、不同设备慢在哪个环节,光看秒表找不到原因。

于是,我沿着插件里的解码、缩放、编码和清理调用加上 HiTrace 标记,再对照系统线程调度记录。模拟器六次请求中,五次最长的独立阶段是解码,另一次出现了 34.254 ms 的像素对象释放等待;而到了畅享 100 Pro Max 真机上,像素对象释放仅需 0.773—1.070 ms,主要耗时集中在解码与编码两个工作线程阶段。

🔍 有了这些分段,我不用盲猜,就能直接看清当前设备该查解码、编码还是释放。这次补齐的是诊断入口;具体等待原因,还需要沿着长区间继续查。

一、使用场景与归因问题

1.1 在模拟器上复现一次可重复的图片处理

诊断页面在沙箱生成图片,依次调用三次 FlutterNativeImage.compressImage,记录等待时长和输出大小,并显示阶段与完成次数。它没有接入相册或上传服务,观察范围限于本地处理。

折叠屏图片处理页面与图片准备、插件调用、系统处理和追踪分析流程

图1 压缩流程

Example 用一个简单的路径插件返回应用缓存目录,通道名为 pgc/native_image_paths。这个通道只服务于示例工程,不属于图片插件对外接口,既省去额外引入路径库,也减少无关通道消息进入采样时间窗。

拿到目录后,Flutter 用画布生成 1280×960 彩色网格 PNG,输入为 8411 字节。

应用等待 3 秒供外部脚本准备,再以 percentage: 70、quality: 70 连续压缩三次相同字节。准备等待不计入压缩秒表。

输出 JPEG 均为 66754 字节,比紧凑编码的合成 PNG 大。这份样本只用于重复执行处理管线,不证明压缩率或上传速度改善;实际图片需另测。

1.2 先核对已有库,再确定扩展位置

我检查了 CPF-Flutter 与 oh-Flutter 的相关仓库。flutter_native_image 已通过 @ohos.multimedia.image 实现鸿蒙压缩,可以直接复用;缺少阶段埋点属于可补能力,不是原包 Bug。

CPF-Flutter 的 flutter_native_image 仓库文件列表与鸿蒙实现目录

图2 社区仓库

UME 通道观察器、通道监控工具包、flutter_logs 开发分支及 sentry_flutter 鸿蒙实现覆盖消息、日志或事件观察,却未暴露图片插件内部阶段。消息往返时间无法拆出解码、编码和像素对象释放各自的等待。

因此,我在原有 compressImage 上增加默认关闭的 enableOhosTrace。未显式开启时,通道消息不增加字段,原生侧也不向追踪缓冲区写入标记;传入 true 后才输出本次调用的阶段区间。它不自行启动整机采集,也不上传数据,采样时仍需配合设备上的 hitrace 命令同时抓取业务标记与调度切片。

1.3 先理顺处理顺序,再加入追踪

我以社区公开标签 0.0.6_1-ohos-1.0.0 为实验起点,包内版本是 0.0.6+1。我也检查了社区 master、dev 和上游 btastic/flutter_native_image 的 master,用来确认已有修正的来源;核查时,社区两个分支的核心原生文件一致。

🧩 在这个版本上,我按下面的顺序处理:

  1. 先等图片处理完成。 原标签使用回调式 fs.write,没有等待 copyExif,属性循环又用了 forEach(async ...),可能在操作结束前就返回路径。我回迁社区已有的顺序修正,改为同步写盘并等待属性复制结束,保留标签原有的 16 项 EXIF 属性。
  2. 再释放用完的资源。 沿用已有清理方案,在收尾阶段关闭文件,释放图像打包器、像素对象和三个图像源。第一步先把执行顺序理清,才能避免释放仍在使用的对象。
  3. 最后加上阶段追踪。 这是本文重点增加的能力:给 Dart 调用提供可选开关,在解码、缩放、编码和释放前后记录标记,让一次总等待能拆成具体阶段。

后面出现的“基线版”和“清理版”都包含顺序修正与追踪,区别是有没有第二步的主动释放。基线版只供对照,并非未经修改的原标签;默认使用的 patched 清理版包含上述全部改动。

关闭追踪时,新增开关不会改变原有通道参数。但顺序修正和资源清理仍会执行,它们已经调整了返回路径的时机,不能把整份清理版理解成与原标签行为完全相同。

二、实测结果与诊断效果

2.1 先看诊断入口,再看两组运行材料

我在同一 Mate X7 模拟器上测试 patched 的诊断开关。两次构建的插件、Example、宿主配置及五项核心文件 SHA-256 一致,只切换编译参数 PGC_TRACE_ENABLED,分别关闭和开启追踪。

Example 把它传给 enableOhosTrace,并显示、记录开关状态。示例编译参数默认开启,插件公开 API 默认关闭。

两轮均用展开屏 2416×2210、API 26、镜像 7.0.0.107、debug 无签名构建、app+sched 和 32768 KB 缓冲区,按相同输入和参数顺序执行三次。期间还有其他任务使用模拟器,所以只核对本进程回执、标记和文件结果,不评估性能开销。

同一清理版的诊断选项完成调用自定义配对区间目标进程调度行三次输出大小
关闭,PID 25602302257均为 66754 字节
开启,PID 27221390 🟢↑2160均为 66754 字节

表1 开关对照

关闭时没有新增的 pgc14.compress.* 区间;开启时每次 30 个,全部配对,时基核对通过,三个请求总区间内,主线程状态的未知时长均为 0。两组输入和留存的第三次 JPEG 哈希相同,证明本样本输出一致。

两份 HAP 哈希、原始 trace、回执和输出均已留存。关闭后的零区间是预期结果,不是零耗时,也无法用于业务窗口求交。

图 3、图 4 在各自测量轮次结束采集后从模拟器窗口捕获,保留 Mate X7 设备外框,用于核对完成回执与开关标识,不用于判断动画帧率。

关闭诊断采样轮次的完成画面

图3 关闭结果

开启诊断采样轮次的完成画面

图4 开启结果

图 5 使用同一份开启诊断的冻结 HAP 从桌面单独拉起录制,展示生成输入图片、等待采样窗口及三次顺序压缩进入 complete 的运行过程。该演示轮次不开启系统 hitrace,连续窗口截屏不混入耗时样本。

开启诊断冻结包从桌面启动到完成三次压缩的运行过程

图5 运行过程

后面的耗时表来自另一组资源清理对照,采样标识为 baseline-02、patched-02a。两组分别以 com.example.pgc14tagbaseline、com.example.pgc14tagpatched 安装在同一 Mate X7,各运行一轮三次请求。

页面、输入、参数和构建模式一致,区别是资源清理层,两组均已开启追踪。六次输出均为 66754 字节;这些数据展示诊断用途,不是 HiTrace 接入前后的对照。

Example 检查输出长度后删除临时文件,只留第三次的 sample-output.jpg。生成图片、查长度和删文件均在秒表范围之外。

页面 complete 表示调用完成。下表的等待、跨度和运行时间分别取自回执、原始追踪文件及交集分析。

2.2 将接口等待与主线程运行时间分开

Dart 秒表包围 await compressImage,pgc14.compress.total 标记原生处理区间,sched 则记录窗口内的线程运行。宿主主线程按 tid = pid 识别,两组为 21473、26795,不同于 Flutter UI 或 Raster 线程。

组别与请求序号Dart 外层等待 ms原生 total 跨度 ms主线程 Running ms主线程 Sleeping(S) ms
基线组 #1 (任务号 1)39.73537.3276.84128.304
基线组 #2 (任务号 26)35.30334.4113.84827.519
基线组 #3 (任务号 51)40.73339.5796.49232.600
清理组 #1 (任务号 1)118.204108.71819.89585.884
清理组 #2 (任务号 31)55.34253.6388.10044.958
清理组 #3 (任务号 61)50.99149.9958.81440.661

表2 等待与运行

清理组首轮除表中的 Running、Sleeping 外,还有 2.939 ms 处于 Runnable、等待调度。较长的休眠窗口说明主线程并未全程持续占用 CPU。

但 Sleeping 也可能是在等锁或同步结果,不代表事件循环能立即响应。本次没有交互、Flutter 帧耗时或事件循环延迟测量,不能据此认定没有阻塞或卡顿。

图 6 对齐了 patched-02a 的阶段标记和线程状态。

实采阶段区间与宿主主线程状态的对齐视图

图6 调度泳道

三次请求位于系统单调时间 8219.9799—8220.2453 s,首轮释放长尾较明显。OS_FFRT_3_0(线程号 27633)在 decode、packing 窗口分别运行 31.330 ms、9.018 ms;OS_FFRT_3_1(线程号 27744)在 scale 窗口运行 8.954 ms。

图内 31.282 ms 是一根连续调度切片,31.330 ms 则是整个解码窗口内多根重叠切片的总和。

这些后台运行与异步图像处理相符,但脚本只有时间交集,没有关联 FFRT 任务编号或调用栈。不能把窗口内运行全算成该次图像任务的 CPU;进一步归因需要补采任务关联。

属性复制的 11.838 ms 窗口内,主线程 Running 为 8.036 ms,短切片较密集。逐项等待属性操作、返回 ArkTS 推进循环的控制流可以解释这类活动,但不能确定每段切片的具体工作。

Dart 等待比原生跨度多约 0.9—9.5 ms。这可能包含任务投递、结果回传和异步恢复,这里未分别计时,不能全归为 MethodChannel 序列化。

2.3 找到主要等待阶段与首轮释放长尾

表 3 列出调用边界间的墙钟跨度,包含运行和等待。

组别与请求序号decode 解码 msscale 缩放 mspacking 编码 mscopy_exif ms释放合计 ms
基线组 #121.8843.1693.2495.116未执行该清理
基线组 #224.5873.0572.6402.829未执行该清理
基线组 #323.4523.6983.9177.466未执行该清理
清理组 #132.3049.43310.07311.83838.384
清理组 #229.4626.2818.3816.2221.537
清理组 #327.7254.4125.1949.1942.200

表3 阶段跨度

“释放合计”包含图像打包器、像素对象、输入图像源,以及目标和来源两个 EXIF 图像源的释放。后两项已计入属性复制阶段,不能与全部阶段重复相加;基线没有执行清理,也不是零耗时释放。

六次请求中,五次最长的独立阶段是图像解码,对应 createPixelMap 调用。解码跨度 21.884—32.304 ms,宿主主线程只运行 0.166—0.529 ms,排查范围因而收窄到解码调用边界。

清理组首轮的像素对象释放耗时为 34.254 ms,超过解码的 32.304 ms,后两次却降至 0.616 ms、0.907 ms。分段记录使我看到:首轮较慢,还应检查资源释放。

这段释放窗口中,Running、Runnable、Sleeping 分别为 2.144 ms、1.807 ms、30.303 ms,状态覆盖无缺口。这说明首轮长等待落在 bmp.release() 调用边界内,且宿主主线程并未持续做 CPU 忙等;至于底层在等待图形缓冲区回收、跨线程同步还是系统服务响应,仍需结合后续调用栈确认。

2.4 华为畅享 100 Pro Max 真机复测与双环境核验

只在模拟器上看调度切片还不够,我又把相同的三份构建参数包通过本地调试签名装到 华为畅享 100 Pro Max 实体真机(型号 YEW-AL80,固件 7.0.0.100,系统回读 OpenHarmony-7.0.0.105)上,同样使用 hitrace --trace_begin -b 32768 app sched 采集真机阶段与内核线程状态。

在真机开关对照中,关闭诊断(PID 38685)完成三次压缩且自定义 pgc14.* 区间数为 0,目标进程调度记录 5667 行;开启诊断(PID 39891)产出 90 个完整配对区间(基线组 PID 39255 为 75 个),时基核对全部通过,六个 total 区间的宿主主线程未知状态时长均为 0,三次输出 JPEG 均为 65831 字节。表 4 列出畅享 100 Pro Max 真机清理组与基线组的阶段跨度对照。

真机组别与请求Dart 等待 mstotal 跨度 msdecode mspacking ms释放合计 ms
真机基线 #145.06542.93812.71213.668未执行该清理
真机基线 #226.10025.0336.6078.494未执行该清理
真机基线 #326.42625.3768.2967.615未执行该清理
真机清理 #182.08476.35125.65420.4371.988
真机清理 #230.02428.9189.2347.4311.232
真机清理 #332.65031.6329.9157.7391.382

表4 真机阶段

真机和模拟器的对比很有意思:模拟器清理组首轮出现了 34.254 ms 的 release_pixelMap 长尾等待,而在畅享 100 Pro Max 真机上,三次 release_pixelMap 分别只用了 1.070 ms、0.773 ms 和 0.911 ms,五项释放合计均不超过 2 ms。真机清理组首轮 76.351 ms 的原生跨度里,宿主主线程 Running 为 18.767 ms、Sleeping 为 57.081 ms,主要耗时落在 decode(25.654 ms)与 packing(20.437 ms)两个由 OS_FFRT 线程池异步处理的阶段。图 7 是畅享 100 Pro Max 真机经 DevEco Studio 投屏(顶栏设备序列号已做不可逆像素马赛克脱敏)完成三次顺序压缩后的画面。同一套分段标记在不同硬件上呈现不同的慢阶段分布,正好体现了先做阶段归因再针对性优化的意义。

华为畅享 100 Pro Max 真机运行开启诊断组完成三次压缩

图7 真机实测

2.5 固定双环境配置并检查采样完整性

模拟器与真机双环境的配置汇总在表 5。

环境与工具项归因案例实际配置
Flutter / Dart3.41.9+ohos-1.0.2 / 3.11.5
DevEco Studio26.0.0.865
HarmonyOS SDK26.0.0.105 Release(API 26)
模拟器环境Mate X7,arm64,4 核 CPU、4 GB 内存,镜像 7.0.0.107 / 系统 OpenHarmony-7.0.0.105
实体真机环境华为畅享 100 Pro Max(型号 YEW-AL80),固件 7.0.0.100 / 系统 OpenHarmony-7.0.0.105,arm64-v8a,USB 直连
构建模式debug(模拟器无签名调试 HAP;真机配本地调试签名)
系统追踪参数app、sched,缓冲区 32768 KB
离线工具trace_streamer 4.3.7、analyze_trace.py
原版公开标签0.0.6_1-ohos-1.0.0(包内版本 0.0.6+1)
补丁与诊断示例feat/ohos-hitrace-attribution 分支(核心补丁见 feat/ohos-hitrace-minimal)

表5 实测环境

资源清理对照采样时,未并行执行其他构建和性能实验。两组均开启追踪与 PGC14Trace 日志,这些操作有开销,debug 数字也不代表 release 性能。

根据实采日志和分析结果整理的数据面板

图8 日志与汇总

图 8 汇集设备日志与两组区间统计,日志中的任务号用于对应具体请求。

基线共 75 个区间,每次 25 个;清理组每次多五个释放阶段,共 90 个。原件中全部配对,六个请求总区间的状态覆盖完整,未知时长为 0;解析器另有两条告警,见 4.3。

三、原理与核心代码

3.1 从公开 Dart 入口传入诊断选项

图 9 展示处理链路:Example 发起公开调用,插件添加阶段标记,设备采集 app+sched,主机解析求交。图片能力仍在插件中,Example 只负责输入和验收。

公开调用到系统追踪分析的处理流程

图9 归因流程

下面是 package/lib/flutter_native_image.dart 中加入可选参数后的完整方法。

  static Future<File> compressImage(String fileName,
      {int percentage = 70,
      int quality = 70,
      int targetWidth = 0,
      int targetHeight = 0,
      bool enableOhosTrace = false}) async {
    var file = await _channel.invokeMethod("compressImage", {
      'file': fileName,
      'quality': quality,
      'percentage': percentage,
      'targetWidth': targetWidth,
      'targetHeight': targetHeight,
      // 显式诊断才发点,默认调用不新增通道参数。
      if (enableOhosTrace) 'ohosTrace': true,
    });

    return new File(file);
  }

关闭时不发送 ohosTrace 键,开启才传 true。Dart 未增加异常拦截,PlatformException 仍交给调用方;Android、iOS 原生实现未改,也未作运行回归。

插件诊断入口与宿主关键配置

图10 插件配置

图 10 根据源码整理入口与配置。插件仍为 har,诊断不新增敏感权限;沙箱示例无需相册权限,真实相册授权由应用处理。

宿主 compatibleSdkVersion、targetSdkVersion 均为 26.0.0。

3.2 配对异步区间,并收尾未结束的标记

阶段里有异步等待,我用 startAsyncTrace、finishAsyncTrace 标记起止位置,两端的名称和任务号要一致。同名任务同时执行时,编号必须不同,避免把两个请求的记录混在一起;串行执行则可以复用编号。

开始方法负责分配编号、写入标记,并保存编号与名称的对应关系。每次压缩各用一份记录,互不影响。这里递增分配编号,到上限再从头计数;这六次请求没有触及回绕,也没有重复编号。

下面只摘录追踪辅助类中负责结束和收尾的两个完整方法。代码中的 active 保存尚未结束的标记,LEVEL 指定输出级别;追踪和日志接口均来自 PerformanceAnalysisKit。

其余实现见公开复现工程中的 ohos/src/main/ets/components/plugin/CompressionTrace.ets。

end(id: number): void {
  const name = this.active.get(id);
  // 没有开始记录,或已经结束,就不用再处理。
  if (name === undefined) return;
  try {
    // 用开始时的名称和编号,告诉系统这一段结束了。
    hiTraceMeter.finishAsyncTrace(LEVEL, name, id);
  } catch (_error) {
    // 打点失败只记告警,别盖掉图片处理本身的结果。
    hilog.warn(0, 'PGC14Trace', 'trace_end_unavailable');
  } finally {
    // 清掉本地记录,避免下次收尾时重复结束。
    this.active.delete(id);
  }
}

close(): void {
  const ids = Array.from(this.active.keys());
  // 后开始的先结束,让内层阶段先于外层 total 收尾。
  for (let index = ids.length - 1; index >= 0; index--) {
    this.end(ids[index]);
  }
}

正常走完一个阶段就调用 end();图片处理途中抛错时,外层收尾逻辑会调用 close(),把剩下的标记逐个收尾。系统结束接口失败时,本地记录虽然已清掉,追踪文件里仍可能缺少结束事件,所以采集后还要检查起止是否配对。

追踪名称仅含固定前缀、阶段名,附加参数留空;日志只有阶段和任务号,不记录图片路径、内容或摄影位置。

3.3 在真实调用边界添加阶段标记

插件收到开启追踪的选项后,先记录本次请求的总区间,再依次给打开文件、创建图像源、读取尺寸、解码、缩放、JPEG 编码、写盘和属性复制这八个阶段打点。

标记紧贴每次原生调用的起止位置,不往处理流程里插入额外等待。这样既能看到整次请求花了多久,也能继续查看其中某一步。

清理版另记录五个对象释放,成功时清理完再返回路径。失败区间可能包含错误处理与清理,不能视为 API 的纯成功耗时。

属性复制阶段再为十六项 EXIF 属性分别记录子区间。程序逐项读取、写入,无论成功或失败都会结束当前标记,全部处理完后释放两个 EXIF 图像源。

输入 PNG 没有摄影 EXIF,读取缺失属性时会进入异常分支,再继续处理下一项。因此,这些子区间主要反映查询及失败返回,不代表十六项都复制成功;父区间还包含两个 EXIF 对象的释放。

资源释放和文件关闭函数遇到异常时会记日志,并继续清理其他资源;单次底层释放仍可能失败。

3.4 对齐时基,再计算调度交集

app 记录业务标记,sched 提供调度依据。两者写入同一 .ftrace,由 trace_streamer 4.3.7 导出 SQLite,再交给只读 analyze_trace.py。

脚本先独立解析原文起止事件,与数据库核对。完整时间转换和配对函数如下。

EVENT = re.compile(r'\s(?P<time>\d+\.\d+):\s+tracing_mark_write:\s+(?P<kind>[SF])\|(?P<pid>\d+)\|(?P<name>[^|]+)\|(?P<cookie>\d+)')


def nanoseconds(value: str) -> int:
    whole, fraction = value.split('.', 1)
    return int(whole) * 1_000_000_000 + int(fraction.ljust(9, '0')[:9])


def read_spans(path: Path, pid: int, prefix: str) -> tuple[list[dict], list[str]]:
    pending: dict[tuple[str, int], int] = {}
    spans: list[dict] = []
    warnings: list[str] = []
    for number, line in enumerate(path.read_text().splitlines(), 1):
        event = EVENT.search(line)
        if event is None or int(event['pid']) != pid:
            continue
        name = event['name'].removeprefix('H:')
        if not name.startswith(prefix):
            continue
        key = (name, int(event['cookie']))
        timestamp = nanoseconds(event['time'])
        if event['kind'] == 'S':
            if key in pending:
                warnings.append(f'重复开始,原开始被保留:line={number}, key={key}')
            else:
                pending[key] = timestamp
        elif key not in pending:
            warnings.append(f'缺少开始:line={number}, key={key}')
        else:
            start = pending.pop(key)
            if timestamp < start:
                warnings.append(f'结束早于开始:line={number}, key={key}')
                continue
            spans.append({'name': name, 'task_id': key[1], 'start_ns': start,
                          'end_ns': timestamp, 'wall_ns': timestamp - start})
    for key in pending:
        warnings.append(f'缺少结束:key={key}')
    return sorted(spans, key=lambda item: item['start_ns']), warnings

原件时间戳有六位小数,即 1 μs 分辨率。数据库的部分端点与原始文本换算值相差 1 ns。若文本出现重复开始、缺少开始、结束早于开始或尾部未闭合区间,解析函数会逐条记录告警,避免残缺记录直接混入后续统计。

分析脚本按原件实际精度核对两边的起止时间,同时保留开始、结束时间的纳秒偏差,避免把舍入尾差当成时钟域错位,也不为了对齐而改写调度数据。

只有全部业务区间在原件精度下对齐,且存在目标进程的调度记录,脚本才计算 CPU 交集。如果缺少这些条件,结果为 null 并附告警;没有数据不能写成 0 ms。

业务窗口为 [ s t a r t , e n d ] [start,end] [start,end],调度切片起点、长度为 t i t_i ti​、 d i d_i di​,交集为:

Overlap = ∑ max ⁡ ( 0 , min ⁡ ( end , t i + d i ) − max ⁡ ( start , t i ) ) \text{Overlap}=\sum\max\bigl(0,\min(\text{end},t_i+d_i)-\max(\text{start},t_i)\bigr) Overlap=∑max(0,min(end,ti​+di​)−max(start,ti​))

这个求交会截断跨过业务边界的调度切片。某个线程在阶段开始前已经运行,或在阶段结束后继续执行其他任务,都只计入窗口内的部分。不过,时间重叠只建立了时间关系,并没有建立任务因果关系;同一进程中的其他工作落在窗口内,也会被统计。

对主线程状态,脚本先求区间并集得到覆盖长度,再用墙钟跨度减去覆盖长度,单列为未知时长(unknown)。状态重叠也单独报告。

这样,缺失切片不会被当成休眠,重复区间也不会被当成额外运行。

进程总 CPU 还可能大于墙钟跨度。例如清理组第 2 次缩放跨度为 6.281 ms,该窗口内 FFRT 线程与主线程的运行交集合计达到 6.590 ms。多核允许它们同时运行,这不矛盾;但这些运行时间只能称为窗口内进程线程的累计值,不能全部归给缩放函数,更不能当作单核利用率。

四、踩坑与解释边界

4.1 保留方向不一致的历史数据

开发分支 master 的三组、每组三十次历史测量中,清理版中位数第一组较长,后两组较短,不能稳定归因为清理影响。

这些样本与公开标签的六次请求分别保存,表 2、表 3 只用后者,不跨版本合并。一次释放长尾也不足以推出普遍规律。

4.2 将工具失败与插件失败分开

采集中遇到的工具错误如下。

现象核查原因处理方式
页面完成,脚本仍等到超时hdc shell 参数中的日志正则含未转义的竖线,被远端 shell 解释为管道按 PID 取回日志,在主机 Python 中过滤
安装返回 9568288模拟器存储空间不足清理两个已归档的旧自建实验应用,另开 patched-02a 采样
解析器报告两条 invalid_data原件末尾的时钟同步标记不被该分支识别用独立副本验证,正式分析保留原件
构建报 00306003当前使用的 Hvigor 不接受中文工程路径排除缓存后复制到 ASCII 路径构建

表6 工具排障

未转义的 TRACE_BATCH|PGC14Trace 导致首轮漏读实际完成回执;安装失败的 patched-02 则没有测量样本。两者均不计入正式结果,也不算插件失败。

修复后另开 patched-02a,保留失败记录。复现时也应使用新运行标识,避免覆盖原件。

4.3 核实解析告警,不修改正式原件

两份原件的写入/留存计数为 49481/49481、50245/50245,未见缓冲覆写;数据库却各报两条 tracing_mark_write invalid_data。

核查发现文件末尾有 trace_event_clock_sync,如下。

hitrace-27773   (  27773) [002] ....  8220.948103: tracing_mark_write: trace_event_clock_sync: realtime_ts=1794259562118
hitrace-27773   (  27773) [002] ....  8220.948110: tracing_mark_write: trace_event_clock_sync: parent_ts=8220.948242

这两行不符合常规 B|pid|...、S|pid|... 格式。我仅在诊断副本删除它们重跑,错误归零,本篇业务区间的名称、任务号、起点和时长均不变。

五、结论与可直接复用的建议

5.1 这次扩展解决了什么

回到图片处理页面,我原先只能知道一次压缩多久返回,现在能把等待定位到解码、编码、属性复制或资源释放。六次请求里,五次最长的独立阶段是解码,另一次出现了 34.254 ms 的像素对象释放等待,后续排查因此有了具体方向。

这项能力适合已经能完成图片处理、却不知道耗时落在哪里的 Flutter 鸿蒙项目。插件负责提供阶段标记,系统调度记录帮助判断窗口内线程的运行情况;这些结果不直接证明页面流畅,也不代表压缩速度已经提高。

5.2 在项目里直接使用

💡 需要这项能力时,可以直接依赖已经写好的 flutter_native_image 扩展版,继续使用原有图片压缩入口。下面固定为本文使用的实现,在项目的 pubspec.yaml 中加入依赖即可,无需自己编写鸿蒙阶段标记。

dependencies:
  flutter_native_image:
    git:
      url: https://atomgit.com/abaoge/flutter_native_image.git
      ref: 4c876b9ce0fe29354e88bc95ee5ff0f93168d2cc

这个提交来自公开的 feat/ohos-hitrace-attribution 分支,仓库根目录就是插件。已有同名依赖时替换原来的配置,再运行 flutter pub get,用鸿蒙 Flutter 工具链重新构建应用,让原生实现一起更新。

下面是业务侧调用的一个完整函数。传入应用能够读取的本地图片路径,等待返回后即可取得输出文件,交给自己的预览、保存或上传流程。

import 'dart:io';
import 'package:flutter_native_image/flutter_native_image.dart';

Future<File> compressPhoto(String imagePath) {
  return FlutterNativeImage.compressImage(
    imagePath,
    percentage: 70,
    quality: 70,
    // 平时保持关闭;需要排查这次压缩的等待时,再改为 true。
    enableOhosTrace: false,
  );
}

缩放比例和编码质量是两项不同的参数,示例都取 70。业务中按图片用途选择参数,并实际比较输入、输出大小;本文的网格 PNG 转为 JPEG 后反而变大,不能把“调用压缩接口”理解成文件一定缩小。

页面自行处理加载提示、重复点击和失败状态。插件返回文件后,后续预览或上传仍由应用负责;如果读取相册图片,也需要应用完成相应授权和路径准备。

5.3 按需使用诊断能力

日常压缩保持默认关闭。需要排查某次等待时,将调用中的 enableOhosTrace 改为 true,插件便会为这次请求记录阶段起止。开启诊断不会自动启动整机采集,也不会上传图片或追踪记录。

已有 HiTrace 采集流程的项目可以直接查看这些阶段。需要用到配套分析工具时,仓库使用说明提供了完整命令和同款 Example。

如果编译时提示没有诊断参数,先检查是否仍依赖原版包。更新依赖后要重新构建、安装应用,单独刷新 Flutter 页面不会替换 HAP 中的原生插件。关闭追踪也只停止新增打点,顺序修正和资源清理仍然执行。

这里提供的是本文运行过的标签派生版本,保留 16 项 EXIF 属性。面向社区仓库 CPF-Flutter/flutter_native_image 主分支整理的核心改动保留了该分支的 20 项属性与裁剪修改,两份代码应分开辨认;依赖先固定提交,升级时再查看相应变更说明。

我在表 5 所列的 Mate X7 模拟器与华为畅享 100 Pro Max 真机双环境运行过这份实现。Android、iOS 原有代码保留,但这次没有做其他平台的运行回归;业务中的大照片、复杂 EXIF 和异常输入仍需按实际场景处理。

小结

需要排查图片处理等待时,可以直接在现有压缩调用上开启诊断选项,沿着具体阶段继续查。无论是在模拟器揪出首轮像素对象释放长尾,还是在畅享 100 Pro Max 真机确认耗时主要落在解码与编码阶段,接入仍是熟悉的 Flutter 图片接口,阶段记录都由鸿蒙插件按需完成 🎉。

参考资料

相关推荐

RN 鸿蒙安全三方库落地:react-native-digital-shield,密钥不出 TEE,AES-GCM/RSA-JWT 跨端身份打通

本文基于 RNOH 0.84 与 HarmonyOS API 26,自研数字盾库 react-native-digital-shield,把 ArkTS 专属的 HUKS、asset 能力经TurboModule 桥接给 JS:提供 AES-256-GCM 加解密与密钥托管、敏感资产存储、RSA-2048 签发校验 RS256 JWT,并以 JWK 公钥和 HS256 共享密钥实现跨端身份互认,密钥明文始终不出 TEE。文中还复盘 TurboModule 双侧注册、GCM 需拆分 16 字节

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 8

Flutter 修复鸿蒙 WebView Cookie 同名键丢失:离线回读与开发助手复核实录

修复了 Flutter 三方库 webview_cookie_manager 鸿蒙端因同名键误判导致的 Cookie 名称丢失问题,确保业务键如 path、domain 等在回读时正确保留。修复后,模拟器与真机测试均实现四组数据完整恢复,值中多等号也保持不变。补丁已提交至 CPF-Flutter 官方仓库,提升插件在鸿蒙平台的可靠性。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 10

Flutter 鸿蒙启动图撤销后编译失败:用 DevEco Code 复核三方库修复

本文针对 Flutter 鸿蒙启动图撤销时导致编译失败的问题,修复了 flutter_native_splash_ohos 库在移除启动图时误删仍被引用资源的缺陷。通过保留1×1透明图片并透传自定义模块路径,确保资源引用完整性,使工程可正常构建。修复已提交至官方仓库,支持幂等操作与多场景验证,提升开发体验。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 17

Flutter 接入鸿蒙 ArkWeb 预初始化:帮助页首开时机与主线程成本实测

为解决Flutter鸿蒙版webview_flutter无法在无视图状态下提前初始化引擎的问题,我在其原生实现中新增可选静态入口initializeWebEngine()。实测表明,在2秒预热窗口下,页面首屏渲染(FCP)耗时从中位数1791ms降至1019ms,显著提升首次打开体验;而在零延迟场景下,总路径耗时略有上升,需权衡预热时机与用户等待成本。该补丁已提交至CPF-Flutter官方仓库,支持社区协作优化。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 11

Flutter 优化鸿蒙 printing_ohos 多页 PDF 光栅化:原生资源释放与缓冲复用

针对鸿蒙端 printing_ohos 插件存在的页码映射错误与高内存占用问题,本文提出并实现三项优化:修正页码索引映射、引入原生资源分层释放机制、复用像素缓冲区。修复后,第三页显示正确,内存增长显著降低——在模拟器上PSS增量中位数下降65.8%,真机测试下降64.4%。完整补丁已提交至官方仓库,支持社区协作与问题反馈。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 8

React Native 鸿蒙权限审计实战:让每一项权限都有人认领

本文介绍一款纯 JS 编写的 React Native 鸿蒙权限审计工具,解决权限声明与使用对账难、最小权限集计算矛盾、审核必填字段缺失三大痛点。通过 module.json5 声明、使用台账与源码扫描三路输入对账,自动识别未使用权限、补全 reason/usedScene、生成可粘贴的最小清单,并支持 CI 卡控与风险分评估。工具内核独立,离线运行,兼顾准确性与安全性,助力应用高效通过审核。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 8

Cordova 鸿蒙 WebView 安全实战:能改的运行时拦,改不了的构建期审

本文通过 cordova-plugin-harmony-webguard 插件,解决 Cordova/HarmonyOS 应用中导航安全、引擎不可修改配置、JS 门面静默降级三大难题。基于运行时策略闸门(onPageStart + JS 预检)与构建期审计 CLI(扫描 MainPage.ets、config.xml 等),实现协议拦截、白名单校验、高危配置阻断,支持 CI 失败退出,将安全基线可视化、可测化,真正落地“能改的运行时拦,改不了的构建期审”。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 11

Flutter 鸿蒙供应链审计实战:让高危依赖卡在 CI 门口

本文介绍了一个基于纯 Dart CLI 与 Flutter Dashboard 的依赖审计工具,解决鸿蒙工程中三套锁文件(pubspec.lock、oh-package-lock.json5、package-lock.json)统一读取、离线快照与 OSV 在线情报选择、以及高危依赖通过退出码卡在 CI 的问题。工具以锁文件为事实依据,支持离线快照(4 条真实 GHSA)与在线查询,输出 SBOM(CycloneDX 1.5)、Markdown/JSON 报告,并通过退出码实现 CI 阻断,性能秒级

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 59

React Native 鸿蒙端侧 OCR 实战:TurboModule 与纯 TS 引擎的逐字契约

本文以鸿蒙真机上的 React Native 0.84 工程为例,详解三大难题:通过 TurboModule 接入 HarmonyOS Core Vision Kit 实现端侧离线 OCR;规避 Metro 预置头导致的 require 不存在问题;实现 npm 包与 HAR 双形态交付。项目采用 codegen 生成 ArkTS 接口,结合纯 TS 回退引擎,确保跨引擎逐字符一致,并通过 autolinking 支持无缝集成。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 30

Flutter 鸿蒙端侧 OCR 实战:让文字识别留在设备上

本文通过一个运行在鸿蒙真机上的 Flutter 插件工程,系统解决了三大核心问题:如何统一内存、文件、相册三类输入的识别链路;如何实现与 KMP 版本的 JSON 契约逐字节对齐;以及在系统不提供置信度时如何诚实处理。基于 HarmonyOS Core Vision Kit,插件实现端侧离线 OCR,全程无网络、无权限、无密钥,支持真实小票与截图识别,性能稳定(312~507ms),并通过 35 项单元测试与真机集成验证。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 49

跨端 RN 鸿蒙碰一碰分享库实战:基于 Share Kit 封装 react-native-ohos-knock-share,实现卡片、文件一碰传

本文介绍基于React Native的鸿蒙碰一碰分享库,解决RN开发者在鸿蒙生态中无法便捷使用Share Kit碰一碰功能的痛点。通过封装NFC/星闪触碰、3秒发送窗口、沙箱文件URI转换等核心逻辑,实现跨设备快速传递链接、文件、图片等内容。支持手机、平板、PC多端适配,提供回环演示与真机实测验证,显著降低接入门槛,提升跨端协作效率。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 37

React Native 鸿蒙实战:给应用接入小艺语音指令,跑通 Skill 声明到操作闭环

本文介绍如何在 React Native 鸿蒙(RNOH)工程中实现小艺技能闭环,通过开源库 react-native-ohos-ai-agent 封装技能声明、语音指令接收、端侧执行与结果回传全流程。针对三方应用权限限制,精准定位可操作边界,实现“被唤起→执行→反馈”链路贯通。结合五张真机截图验证:技能注册、指令匹配、意图上报、智能体调起及对话层弹出等关键节点均成功,完整打通语音交互闭环,助力应用无需入口即可被用户“叫”到。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 44

Flutter 鸿蒙实现精准碰一碰分享:tap_share_ohos 三方库打通真机传文件与传卡片

本文针对Flutter在鸿蒙系统上“碰一碰”分享功能缺失的痛点,基于DevEco Studio 26.0、HarmonyOS 7.0 API 26与Flutter 3.41.9实测环境,提出并实现开源库tap_share_ohos。该库封装NFC、Share Kit、权限管理及分布式能力,通过Dart门面层统一接口,利用MethodChannel与BasicMessageChannel对接原生ArkTS逻辑,实现文件与卡片的碰一碰分享。真机测试显示,可无缝调起系统分享面板,支持华为分享接力

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 126

Flutter 鸿蒙实战:用三方库接入小艺语音指令与智能体,跑通 Skill 声明到操作闭环

本文基于 flutter_ohos_ai_agent 三方库,实现 Flutter 应用一键调起鸿蒙小艺智能体。针对跨端框架对接鸿蒙 AI 能力的碎片化、环境差异等痛点,通过插件封装系统 Kit 能力,提供统一 Dart API。实测显示,模拟器与真机均支持文本/语音指令闭环,真机可完整调起小艺面板并回传事件。核心原理为:利用 ArkUI 承载页桥接 FunctionComponent,通过 MethodChannel 与 EventChannel 实现 Flutter 与原生能力双向通信,完成从语音识别到

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 44

RNOH 原生内存泄漏定位与治理:借助 LeakyGuard 实现图片解码降采样、LRU 字节缓存、资源生命周期管控,长列表图片页面峰值内存优化

本文面向 RNOH 0.84 长列表图片场景,剖析滑动数分钟后进程被系统杀掉的根因:原图解码尺寸失控、缓存按条数限流、PixelMap未显式 release。基于自研LeakyGuar,TurboModule 库,给出 desiredSize 真降采样、字节预算 LRU 缓存(逐出必 release)、资源登记与快照 diff、卸载即释放 Hook 的闭环方案,实测单图内存降 98.6%,24 图峰值由 1098.6MB 降至15.8MB。并总结双侧注册、ArkTS 语法差异、vp 转像

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 105

Flutter 鸿蒙空间音频实战:让音乐播放器的声音“长出方位感“

本文通过一个真实运行的 Flutter 工程,系统解析了在鸿蒙系统上实现空间音频的三大核心问题:基于双耳时间差(ITD)、声级差(ILD)和频谱整形的方位感算法;耳机切换与音频焦点管理;以及播放器与音效的集成。项目使用自研插件 spatial_audio,结合原生 HarmonyOS 接口,实现了跨设备的空间音频体验,支持普通耳机,无需硬件依赖,并提供实时参数反馈与系统状态监听。附带完整代码仓库与实测效果展示,为 Flutter on HarmonyOS 的音频开发提供了可复用的技术方案。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 273

Flutter 适配鸿蒙折叠屏铰链角度按需订阅:支架调节页用完即停与重入实测

本文介绍对 Flutter 三方库 dual_screen 的优化:针对支架调节页等短时观察场景,保留原有缓存入口的同时,新增按需订阅机制。通过按需启停监听,实现页面退出后停止原生回调,避免无效数据更新。实测显示,无消费者时原生回调从3条降至0条,重进页面则等待新事件,更符合临时工具页的使用逻辑。完整代码已开源,支持鸿蒙折叠屏角度动态感知,适用于需精准控制生命周期的折叠屏应用开发。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 1万+

Flutter 适配鸿蒙手表屏幕形状:让计时卡片按圆屏和方屏布局

本文基于 wear_plus 1.2.4 版本,为鸿蒙系统补全屏幕形状查询功能,使 WatchShape 能正确返回 round 等形状信息。通过在原 Dart 接口不变的前提下,新增鸿蒙平台处理器,实现与 Android 一致的异步查询逻辑。对照实验验证:适配后页面可从“查询未接入”变为“圆屏已确认”,日志成功接收系统回执,布局行为保持一致。完整代码开源至 oh-flutter/wear_plus,支持 Flutter 鸿蒙穿戴设备开发。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 1万+

Flutter 优化鸿蒙剪贴板大图复制卡顿:从主线程同步阻塞到异步文件描述符直解

针对鸿蒙系统下 flutter_image_clipboard 插件复制高清图片时阻塞主线程的问题,本文提出三项优化:异步文件描述符直解、异步剪贴板写入及原生资源逆序释放。实测显示,模拟器事件循环最大间隔从300.32ms降至54.36ms(降幅81.9%),真机上更从133.20ms降至11.20ms(降幅91.59%),显著提升页面响应性。完整代码已开源,支持直接使用与社区交流。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 1万+

Flutter 三方库 petalmaps_ohos 的 OpenHarmony 适配实战(0 → 1 全记录)

本文详细记录了从零构建 Flutter 三方库 petalmaps_ohos 并适配 OpenHarmony/HarmonyOS 平台的全过程,涵盖项目初始化、原生实现(基于 ArkTS 和 MethodCallHandler)、插件注册、功能验证及升级至 HarmonyOS SDK 26 的关键步骤。重点解析了为何需实现 AbilityAware 获取 UIAbilityContext 以确保地图调起成功,并通过分层架构、枚举封装与兼容性设计,实现功能完整、易用且低维护成本的“调起系”地图插件,

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 52

Flutter 三方库 holding 的 OpenHarmony 适配实战:从 0 到 1 开发一个鸿蒙感知插件

本文详述了从零实现开源 Flutter 插件 holding 并适配 OpenHarmony/HarmonyOS 的全过程。基于鸿蒙专属 MultimodalAwarenessKit,实现握持手与操作手状态感知,覆盖事件流订阅、状态查询及 API 26 新增接口,确保功能一致、性能高效、接口稳定。通过 Dart 层封装、ArkTS 原生桥接、真机验证与单元测试,完成插件工程化落地,并发布至 pub.dev,为同类系统能力插件的鸿蒙化提供可复用的技术路径。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 25

Flutter 三方库 gesturesshare 从 0 到 1:鸿蒙隔空传送分享插件的开发、升级与发布实战

本文详述了 Flutter for OpenHarmony 三方库 gesturesshare 从零开发到发布全过程:基于 HarmonyOS 隔空传送能力,实现跨设备图片与 App Linking 一键分享。涵盖双端代码设计、API 26 升级、真机验证及 Pub 发布流程,提供 Dart/ArkTS 对照与踩坑复盘。项目填补 Flutter 生态空白,推动鸿蒙多设备交互能力普及,助力开发者快速接入系统级功能。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 26

Qt 鸿蒙沉浸光感实战:让玻璃的每个像素自己发光

本文通过一个 QML 模块与 Qt for OpenHarmony 构建实践,完整解答了三个核心问题:如何用 81 行 GLSL 实现无图片依赖的动态玻璃材质(含光核漂移、视差、SDF 圆角与颗粒);如何在 Qt Quick 中通过 C++ 控制器实现弹层锚定与翻转;以及如何将 Qt 应用交叉编译并以 HAR 形式部署至鸿蒙系统。项目基于 Qt 5.12.12,利用 ShaderEffect 实现纯渲染级视觉效果,兼顾性能与跨平台兼容性,提供可复用的开源方案。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 21

开源鸿蒙平台 KMP_CMP 三方库「端侧语音转文字」适配全流程

本项目实现KMP/CMP在OpenHarmony鸿蒙平台的语音转文字(TTS)完整链路适配,通过Kotlin/Native共享模型、C ABI/N-API桥接与ArkTS交互,解决权限、音频格式、生命周期及跨平台契约等难题。支持中文、英文、日文多语言识别,提供统一结果模型与JSON序列化,实测于华为Mate 80 Pro Max模拟器,验证了JVM测试、Native动态库、HAP签名部署及真机识别全流程。项目结构清晰,分六阶段推进,确保代码复用与平台无关性,为KMP在鸿蒙生态落地提供可复用的技术范式。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 30

开源鸿蒙平台 KMP_CMP 三方库「端侧OCR」新特性适配

本项目实现Kotlin Multiplatform(KMP)在OpenHarmony平台的端侧OCR适配,基于HarmonyOS 7.0 SDK与Compose Multiplatform 1.9.2,成功打通JVM、Kotlin/Native与ArkTS间的数据交互。通过C ABI/N-API桥接层,实现KMP模型与Core Vision Kit识别结果的跨语言共享,支持中、英、日、韩四语识别。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 11

开源鸿蒙平台 KMP/CMP 三方库「智感握姿」新特性

本项目实现鸿蒙KMP/CMP平台下智感握姿能力的跨端适配,基于Kotlin Multiplatform构建共享状态模型,通过C ABI与ArkTS桥接,支持左手、右手、双手等五种握持状态的稳定传递。项目打通ohosArm64目标、Native动态库构建与DevEco Studio集成链路,提供统一API与真机验证示例,确保状态模型、事件序列与生命周期在多端一致。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 16

Electron 鸿蒙沉浸光感实战:把玻璃交给操作系统去发光

本文通过一个 Electron 库与 HarmonyOS 三方库,系统解决三大核心问题:跨平台材质路径对齐(macOS vibrancy、Windows acrylic、鸿蒙 backgroundBlurStyle)、菜单子窗口精准定位(坐标转换与工作区适配)、以及无脚本菜单文档的安全事件回传(自定义 URL scheme 与焦点管理)。基于 CPF-Electron 鸿蒙化分支,实现桌面级玻璃效果——材质由操作系统合成器采样,网页仅渲染薄色层与光斑,确保视觉一致性与性能优化。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 21

Flutter 修复 flutter_secure_storage 鸿蒙入口路由与前缀隔离:让多账号登录凭证在手机上独立读写与清理

本文针对 flutter_secure_storage 在鸿蒙平台的适配问题,修复了主包缺失 TargetPlatform.ohos 路由导致的 unsupported_platform 错误,并统一鸿蒙子包多账号前缀的读写与清理范围,解决键值覆盖、前缀错用及批量操作匹配过宽等问题。修复后,业务层可继续使用统一接口实现跨账号安全存储,保障数据隔离性。完整代码已开源至 abaoge/flutter_secure_storage。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 1万+

Cordova 鸿蒙沉浸光感实战:让弹层玻璃“喝到“背景的光

本文通过一个 HarmonyOS 模拟器上的 Cordova 项目,详解了在 WebView 中实现“玻璃拟态”效果的三大核心问题:利用 backdrop-filter 实现背景实时模糊与提亮,构建四层结构(采样、渐变底、光场、噪点)模拟真实玻璃质感;通过锚点定位与动态布局实现弹层贴边生长;并集成焦点管理、系统返回键及 inert 属性,确保交互礼仪完整。插件为纯 JS 无原生依赖,基于 ArkWeb 内核,兼顾性能与真实背景采样,适用于菜单、浮层等场景。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 26

CMP 鸿蒙透明玻璃实战:让悬浮导航栏真正透出光场

本文通过一个KMP/CMP工程,详解如何在鸿蒙上用Kotlin实现沉浸光感玻璃材质的逐像素渲染。核心解决三大问题:透明感源于环境光场与带alpha的柔光混合、玻璃“透光”依赖alpha保留的屏幕混合算法、跨平台一致性通过软件光栅器与原生桥接实现。项目以纯代码生成全屏光场与悬浮玻璃组件,无图片资源,支持动态切换调色板,实测模拟器下亚秒级重绘,完整复现官方“沉浸光感”视觉效果。仓库地址:https://atomgit.com/lqjmac/spatial-glass-cmp。

白天写代码,晚上追AI大模型,偶尔搞点八卦 开源动态|技术干货|实习机会|生态活动 我负责分享,你负责变强 20
上一篇: Flutter 适配鸿蒙折叠屏铰链角度按需订阅:支架调节页用完即停与重入实测
下一篇: Flutter 鸿蒙空间音频实战:让音乐播放器的声音“长出方位感“
AtomGit 代码君
AtomGit 代码君 企业官方账号 企业官方账号
博客等级 码龄6年 2万+粉丝 856原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值