HarmonyOS 7 InsightBoard 多形态适配实录 06:ArkUI × 多设备回归:布局抖动、监听释放与全形态验收【鸿蒙心迹】

InsightBoard 到第五篇已经完成了一条比较完整的多形态链路:

COMPACT 手机
→ MEDIUM 折叠屏展开
→ HOVER 半折叠
→ EXPANDED 平板 / PC
→ 自由窗口
→ WindowStage 销毁与恢复

最后一篇我没有再加任何组件。

因为多形态适配最危险的阶段,往往不是“第一遍切过去”,而是用户连续切 10 次、20 次以后。

我以前做响应式页面时就见过这种情况:第一次完全正常,来回拖窗口十几轮以后,日志一口气打出 3 个 windowSizeChange;折叠屏开合几次,selectedItem 偶尔回到第一条;HoverMode 退出后 Timer 没清掉,下一次进入还会收到旧回调。

这些都不是视觉稿能发现的问题。

所以 06 只做一件事:把 InsightBoard 当成一个已经准备发版的应用,用固定矩阵做 25 轮全形态回归。

本轮固定数据:

taskId: adapt_accept_20261002_06

deviceCases:
5 / 5

cycles:
25

layoutTransitions:
80

duplicateLayoutApply:
0

stateLoss:
0

listenerLeak:
0

avgLayoutApply:
14.8ms

p95LayoutApply:
22.6ms

maxLayoutApply:
31.0ms

baselineMemory:
128.4MB

after25Cycles:
129.1MB

memoryDelta:
+0.7MB

activeWindowListeners:
1

activeFoldListeners:
1

activeTimers:
0

releaseListenersAfterDestroy:
0

status:
PASS

这些数据是 InsightBoard 当前测试工程的回归基线,不是 HarmonyOS 的系统指标。

一、最终验收不是“设备都能打开”

如果只看功能,五个场景都已经能用了。

但我把最终验收拆成六组:

Layout
State
Event
Lifecycle
Performance
Memory

每一组都有失败条件。

例如:

布局看起来对
但 layoutApply 一次窗口变化触发两遍
→ FAIL

页面没有闪退
但 selectedItem 被重置
→ FAIL

25 轮以后内存持续阶梯上涨
→ FAIL

这样 PASS 才不是“肉眼没发现问题”。

二、回归矩阵固定五种场景,不再随机点

这一轮的 5 个 case 固定为:

1. Phone COMPACT

412vp
Bottom / Stack

验证单栏、底部导航、详情 push 和 selectedItem 保持。

2. Foldable MEDIUM

824vp
Split

验证 foldStatus + windowSize 最终只 Apply 一次,insight_042 继续显示。

3. Foldable HOVER

392vp + 36vp + 487vp

验证折痕安全区、Primary / Secondary,以及退出 Hover 后 Timer 清理。

4. Tablet EXPANDED

1024vp
三栏

验证大屏信息密度和导航结构。

5. PC / Free Window

1180vp
→ 780vp
→ 520vp
→ close
→ reopen

验证 RAIL / SPLIT / STACK,以及 WindowStage 恢复。

每一轮必须按同样顺序跑。

如果随机拖窗口,很难判断第 18 次出现的错误到底对应哪条路径。

三、我给所有系统监听做了统一计数

前面几期已经分别注册过:

windowSizeChange
foldStatusChange
hoverStatus

开发时每个 Manager 自己 on/off 很容易漏。

最终我加 SubscriptionRegistry:

export class SubscriptionRegistry {
  private windowCount: number = 0
  private foldCount: number = 0
  private timerCount: number = 0

  onWindowBind(): void {
    this.windowCount++
  }

  onWindowRelease(): void {
    this.windowCount--
  }

  onFoldBind(): void {
    this.foldCount++
  }

  onFoldRelease(): void {
    this.foldCount--
  }

  onTimerCreate(): void {
    this.timerCount++
  }

  onTimerRelease(): void {
    this.timerCount--
  }

  snapshot() {
    return {
      window: this.windowCount,
      fold: this.foldCount,
      timer: this.timerCount
    }
  }
}

这不是为了替代 off(),只是让最终验收有证据。

正常运行时:

activeWindowListeners=1
activeFoldListeners=1
activeTimers=0

WindowStage Destroy 以后:

0
0
0

如果 Window listener 变成 2,就不用等用户说“拖动时有点抖”才发现。

四、Layout Apply 也要有自己的去重统计

02 做事件合并时已经有 layoutApply=1。

最后一篇把这个指标提升成全局回归项。

每次 AdaptiveSnapshot 真正发生模式变化才记一次:

export class LayoutApplyMetrics {
  private applyCount: number = 0
  private duplicateCount: number = 0
  private lastSignature: string = ''

  record(snapshot: AdaptiveSnapshot): void {
    const signature =
      `${snapshot.mode}:` +
      `${snapshot.widthVp}:` +
      `${snapshot.foldStatus}:` +
      `${snapshot.hoverMode}`

    if (signature === this.lastSignature) {
      this.duplicateCount++
      return
    }

    this.lastSignature = signature
    this.applyCount++
  }

  duplicate(): number {
    return this.duplicateCount
  }
}

这一轮:

layoutTransitions=80
duplicateLayoutApply=0

这里的 80 是 25 轮测试中真正需要发生的布局转换次数。

不是所有 windowSizeChange 都应该产生 Layout Apply。用户拖窗口时宽度可能变化很多次,但只要还在同一个 Mode、关键布局条件也没变化,就没必要重建页面结构。

五、状态丢失要定义成自动断言

以前我靠肉眼看 insight_042 还在不在。

06 改成每个 case 结束自动断言:

export interface ExpectedState {
  selectedItemId: string
  filter: string
  routeTop: string
}

export class StateContinuityAssert {
  verify(
    current: BoardRestoreState,
    expected: ExpectedState
  ): boolean {
    return (
      current.selectedItemId ===
        expected.selectedItemId &&
      current.filter ===
        expected.filter &&
      current.routeTop ===
        expected.routeTop
    )
  }
}

统一期望:

selectedItem=insight_042
filter=全部
routeTop=Detail

25 轮结束:

stateLoss=0

这样“状态连续性”终于不是文章里的形容词,而是一个可以失败的测试项。

六、布局耗时看平均值还不够,P95 更有意义

窗口重排不是每次都一样快。

第一次创建 EXPANDED 三栏需要创建更多组件,单纯看平均值会把偶发慢帧藏起来。

最终数据:

avg=14.8ms
p95=22.6ms
max=31.0ms

我没有把 16ms 当成绝对红线。

布局重排不是每帧都在执行,而且设备与数据量都会影响结果。当前项目自己的验收规则是:

P95 < 30ms
Max < 50ms

这样更适合作为版本回归基线。

下一版如果 P95 从 22.6ms 变成 45ms,就算肉眼还没明显卡,也应该回头查哪次改动让页面重排变重了。

七、List / Grid 数量大以后,不能用“全量重建”掩盖适配问题

InsightBoard 当前列表只有几十条,性能还比较轻。

API 26 已经提供 LazyDynamicLayout / LazyLayoutAlgorithm 相关能力,用于懒加载和自定义布局;setAdjustedOffset() 还能在列数、间距变化时保持可视区域相对位置。

这一篇没有为了最终验收临时换成新容器。

但我给后续扩展留了明确判断:

如果 EXPANDED 下列表数据上百
而布局变化每次都重建大量子节点
→ 先优化 Lazy Layout

不要继续靠减少动画掩盖

这也是技术连载最后应该留下的边界,而不是硬塞一个新 API。

八、内存回归关注“释放后的基线”,不只看峰值

多形态页面的峰值会变化。

EXPANDED 三栏肯定比 COMPACT 多一些组件;HoverMode 也会切不同 Pane。

真正危险的是:

每切一轮
基线都多 2MB

本轮测试:

baseline:
128.4MB

after25Cycles:
129.1MB

delta:
+0.7MB

0.7MB 不代表完全没有缓存或系统波动,但至少没有形成明显的阶梯增长。

我同时检查 Window listener、Fold listener、Timer 和恢复临时对象,最后 WindowStage 销毁后必须全部回 0。

九、资源释放代码必须和创建代码在同一个 Manager 里

最终我把这一条写成工程规则:

谁 on
谁 off

谁 setTimeout
谁 clearTimeout

谁创建 Coordinator
谁 dispose

谁保存 Window
谁在 Stage destroy 清引用

不能 A 模块注册,B 页面顺手释放。

这会让 06 的验收简单很多。

例如 ViewportManager:

export class ViewportManager {
  private mainWindow?: window.Window
  private bound: boolean = false

  bind(mainWindow: window.Window): void {
    if (this.bound) {
      return
    }

    this.mainWindow = mainWindow
    this.mainWindow.on(
      'windowSizeChange',
      this.onWindowSizeChange
    )

    SubscriptionRegistry.shared()
      .onWindowBind()

    this.bound = true
  }

  dispose(): void {
    if (!this.bound ||
        this.mainWindow === undefined) {
      return
    }

    this.mainWindow.off(
      'windowSizeChange',
      this.onWindowSizeChange
    )

    SubscriptionRegistry.shared()
      .onWindowRelease()

    this.mainWindow = undefined
    this.bound = false
  }
}

幂等 bind / dispose 是最终版本必须具备的能力。

十、测试 Runner 不能依赖人工操作节奏

如果验收仍然靠我自己“展开一下、缩一下、再点一下”,每轮条件都不一样。

所以最后新增 AdaptiveAcceptanceRunner,把五种 case 固化:

export class AdaptiveAcceptanceRunner {
  private readonly cycles: number = 25

  async run(): Promise<void> {
    for (
      let cycle = 1;
      cycle <= this.cycles;
      cycle++
    ) {
      await this.runCase(
        DeviceCase.PHONE_COMPACT
      )
      await this.runCase(
        DeviceCase.FOLDABLE_MEDIUM
      )
      await this.runCase(
        DeviceCase.FOLDABLE_HOVER
      )
      await this.runCase(
        DeviceCase.TABLET_EXPANDED
      )
      await this.runCase(
        DeviceCase.PC_FREE_WINDOW
      )

      this.assertState()
      this.assertSubscriptions()
      this.recordMemory(cycle)
    }
  }
}

这个 Runner 不属于正式用户功能,而是项目里的回归工具。

它让每个版本都有相同的“跑法”。

十一、25 轮里我故意插入了 5 次 WindowStage 重建

只做尺寸变化还不够。

第五期已经证明 WindowStage 重建是独立场景,所以最终 25 轮里,每 5 轮主动加入一次:

save snapshot
→ destroy stage
→ recreate
→ restore
→ continue matrix

五次都要求:

selectedItem=insight_042
filter=全部
scrollOffset 可恢复
routeTop=Detail

这也是 stateLoss=0 真正有价值的地方。

不是只在同一个页面树里跑了 25 次。

十二、失败时必须把第一条异常停住,不继续刷屏

自动回归一旦失败,如果继续跑后面 20 轮,HiLog 很快被淹没。

所以 Runner 的失败策略是:

发现 duplicateApply
→ 立即停止

发现 stateLoss
→ 立即停止

发现 listenerLeak
→ 立即停止

同时保留:

cycle
deviceCase
viewport
foldStatus
selectedItem
activeListeners

这样回头看第一条失败证据,比最后面对几百行重复错误更有效。

本轮没有触发停止条件。

十三、DevEco 图只保留验收矩阵

最后一张开发图不再展示某个具体布局。

它只展示:

5 device cases
25 cycles

layoutTransitions=80
duplicateApply=0
stateLoss=0
listenerLeak=0

avg=14.8ms
p95=22.6ms
max=31.0ms

memoryDelta=+0.7MB

result=PASS

HiLog:

case PHONE_COMPACT PASS
case FOLDABLE_MEDIUM PASS
case FOLDABLE_HOVER PASS
case TABLET_EXPANDED PASS
case PC_FREE_WINDOW PASS

cycle 10
stateLoss=0
listenerLeak=0

cycle 20
memory=128.9MB

cycle 25
memory=129.1MB
delta=+0.7MB

RESULT PASS

十四、最终运行图展示的是“这套适配真的跑完了”

最终结果:

统一数据:

taskId:
adapt_accept_20261002_06

cases:
5 / 5

cycles:
25

layoutTransitions:
80

duplicateApply:
0

stateLoss:
0

listenerLeak:
0

avg:
14.8ms

p95:
22.6ms

max:
31.0ms

memory:
128.4 → 129.1MB

delta:
+0.7MB

status:
PASS

到这里,InsightBoard 的 6 篇主线完整闭环。

从 01 的“窗口宽度决定布局”,一直走到 06 的“多设备回归和资源释放”,中间没有换 Demo,也没有靠重复介绍断点凑篇数。

最终项目留下的是这些边界:

Viewport 决定布局
FoldStatus 描述设备形态
HoverMode 是独立交互场景
大屏增加信息密度
WindowStage 重建恢复业务上下文
系统监听必须成对释放
适配结果必须能回归验收

这个系列在 06 正式结束。

下一轮如果继续多形态,只会开始重复 Navigation、Window 和状态保持。更合理的做法是换成明显不同的技术方向与 Demo,从新的 01 开始。

十五、回归环境也要固定,不然性能数字没有可比性

这一轮我把测试设备、系统版本、数据集和窗口初始状态都写进验收记录。

原因很简单:同样是 P95=22.6ms,如果上一次用 24 条数据,这一次用 240 条数据,两次结果不能直接比较。

当前回归环境固定:

HarmonyOS 7 / API 26
Insight 数据 48 条
默认 selectedItem=insight_042
默认 filter=全部
动画配置保持一致
窗口缩放路径保持一致

每个 case 都从干净状态开始,不复用上一个 case 的临时 Timer 和动画对象。

尤其是 HoverMode。它退出以后如果还留着上一轮 scheduleApply(),下一轮折叠屏测试就会收到一条“幽灵布局 Apply”,最终把 duplicateApply 从 0 变成 1。

所以环境初始化本身也是验收的一部分。

十六、窗口拖动阶段,不应该给每一个像素变化都加完整过渡动画

做 PC 自由窗口测试时,我还发现一个视觉问题。

如果每一次 windowSizeChange 都带完整 300ms 动画,用户拖动窗口时动画不断被打断,反而会比没有动画更抖。

最终策略是:

同一 Mode 内连续 Resize
→ 关闭结构动画
→ 只更新尺寸

Mode 真正发生变化
COMPACT ↔ MEDIUM ↔ EXPANDED
→ 才执行一次短过渡

当前过渡时长控制在 120ms 左右,而且不把它计入 14.8ms 的 Layout Apply 计算。

我把“布局计算耗时”和“视觉动画时长”分开统计。

否则一个页面动画 120ms,很容易被误解成“布局本身花了 120ms”。

这类口径如果不拆开,性能报告看起来有数字,实际上没法指导优化。

十七、内存曲线必须看趋势,不能只看第一轮和最后一轮

128.4MB → 129.1MB 这两个端点看起来很稳定。

但如果中间曾经:

128
145
162
180
129

最后又因为系统回收掉下来,单看起点和终点也会错过问题。

所以 25 轮每轮都保留释放后内存值。

本轮趋势大致是:

cycle 1   128.5
cycle 5   128.7
cycle 10  128.8
cycle 15  128.8
cycle 20  128.9
cycle 25  129.1

没有持续阶梯上升。

这条曲线和峰值是两回事。EXPANDED 或 Hover 时内存临时上涨很正常,关键是离开场景后有没有稳定回落。

最终我把验收规则写成:

释放后基线持续上升
→ FAIL

单次峰值升高但可稳定回落
→ 继续观察,不直接判泄漏

这样对资源问题的判断更克制,也更接近真实工程。

十八、最终报告必须能反推到具体 case,而不是只有一个绿色 PASS

如果最终页面只显示:

PASS

出了问题还是不知道从哪里查。

所以 AcceptanceResult 同时保存每个 case 的摘要:

PHONE_COMPACT
apply=14
stateLoss=0
listenerLeak=0

FOLDABLE_MEDIUM
apply=16
coalesceOk=true

FOLDABLE_HOVER
hingeGap=36vp
timerReleased=true

TABLET_EXPANDED
visibleItems=9
nav=RAIL

PC_FREE_WINDOW
restoreCost=64ms
stageRecovery=PASS

最后的 PASS 是这些结果的聚合,不是替代。

如果下一版只有 PC_FREE_WINDOW 失败,日志能直接停在这个 case,不需要把手机、折叠屏重新全部查一遍。

这也是我对这个系列最后的一个要求:适配不仅要“跑起来”,还要“能证明自己跑对了”。

参考资料

  • HarmonyOS 多设备通用适配指南:https://developer.huawei.com/consumer/cn/multidevice/adaptive-apps/
  • 多窗口布局适配:https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V14/multi-window-layout-adapt-V14
  • API 26 LazyLayoutAlgorithm:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-arkui-lazylayoutalgorithm
  • HarmonyOS 7 / API 26 升级适配:https://developer.huawei.com/consumer/en/doc/harmonyos-releases/upgrade-adaptation

相关推荐

HarmonyOS 7 平行视界实战 05:生命周期、恢复与成品化打磨,完成“双栏研读台”最终收尾【鸿蒙心迹】

第五篇聚焦“双栏研读台”的收尾与成品化,不再新增功能,而是强化生命周期管理、状态恢复与工程规范。通过重构目录结构,将状态、路由、存储分离;定义统一的RestoreSnapshot快照协议,精准保存分栏比例、滚动位置等细节;引入StateSyncService实现跨场景状态同步与持久化。重点解决应用重启、切后台、多设备适配下的自然恢复问题,使Demo从“可演示”迈向“可交付”的原型阶段,真正体现工程闭环能力。

李游的博客 256

HarmonyOS 7 平行视界实战 04:分栏比例 + 状态同步解决“双栏研读台”多尺寸适配问题【鸿蒙心迹】

第四篇聚焦“双栏研读台”在HarmonyOS平行视界下的响应式体验,提出基于窗口宽度的智能分栏比例系统。通过定义可解释的RatioType模型与断点策略(<900:1:1, 900–1360:1:2, ≥1360:2:1),实现自动适配;结合LayoutService与StateSyncService,确保比例切换时阅读状态(文章、滚动位置等)可恢复、可同步。项目结构清晰分离布局与状态逻辑,使双栏体验在不同设备上保持一致性,真正实现“像同一个产品”。

李游的博客 104

HarmonyOS 7 平行视界实战 03:导航固定 + 覆盖切换重构“双栏研读台”大屏阅读体验【鸿蒙心迹】

本文聚焦大屏阅读中“固定导航+覆盖切换”模式的实现,解决第二篇“连续推进”带来的导航混乱问题。通过明确三条产品规则:左侧导航不动、右侧覆盖切换、返回仅恢复内容区状态,构建稳定体验。项目目录工程化拆分,引入FixedNavLayout、OverlayRouteService与ReadingSessionStore三核心组件,重构Index.ets为总装配台,以Stack结构实现内容层覆盖。强调导航职责单一——维持用户方向感,最终实现结构清晰、切换明确、返回可溯的大屏阅读链。

李游的博客 203

HarmonyOS 7 平行视界实战 02:左右推挤 + 路由关联完善“双栏研读台”连续浏览链路【鸿蒙心迹】

“双栏研读台”第二篇聚焦于构建连续阅读链路,通过Navigation路由系统实现文章间的层级推进,区分push与replace,确保浏览路径可追踪。引入路由历史、去重机制与来源标记(list/related),提升体验连贯性与可维护性。明确应用路由与系统平行视界职责分离,为大屏连续浏览提供清晰、可持续的架构基础。

李游的博客 255

HarmonyOS 7 平行视界实战 01:Navigation + ArkUI 搭建“双栏研读台”第一版分栏阅读【鸿蒙心迹】

本文聚焦于构建HarmonyOS平行视界下的“双栏研读台”第一版,核心是搭建稳定的页面关系骨架:通过Navigation分栏模式实现左列表、右详情的主从结构,使用NavPathStack管理路由切换,确保大屏下双栏布局的可演进性。项目目录清晰,优先用模拟数据验证分栏逻辑与点击跳转流程,不追求功能复杂度,为后续“左右推挤”“固定导航”“比例自适应”等交互能力的逐步扩展奠定基础。

李游的博客 271

HarmonyOS ohpm install × Git diff:三方库锁文件意外变更的发布前门禁【鸿蒙心迹】

同一个 HarmonyOS 工程,在开发机上安装第三方库之后可以正常启动,到了发布分支却多出一份没有人解释的锁文件变化。这时最麻烦的往往不是“到底哪个包升级了”,而是根本不知道变化来自主动更新、清理缓存之后的重装,还是有人随手执行了安装命令。等到上架构建报错再去倒查,版本记录、安装日志和提交历史通常已经分散。本文做一个很窄的发布前门禁:识别 Git 工作区中依赖清单与锁文件是否出现未经解释的变化,并把差异交回给维护者复核。这里需要先划清官方能力和项目脚本的边界。是工程或模块的依赖声明文件,

李游的博客 28

HarmonyOS ArkUI Slider × Stack:超分前后对比滑杆的零宽保护与位置校准【鸿蒙心迹】

做图片超分功能时,最容易吸引注意力的是处理后有多清晰。但真正给用户验收效果的页面,往往只是两张照片和一根可以左右移动的滑杆。它看起来很简单,却有一个容易忽视的问题:比对位置应当对应原图和增强图中的。如果布局初始宽度尚未确定,或者前后图以不同裁切方式铺满容器,视觉上就会出现“滑杆移动,山峰也跟着跑”的错觉。本文不实现超分算法,而是把比对组件本身做成有明确边界的 ArkUI Demo。

李游的博客 90

HarmonyOS ArkUI focusControl × id:平行视界列表重排后的焦点定位与失效回退【鸿蒙心迹】

更糟的是某条结果被过滤后,开发者继续请求一个已经不存在的组件 ID,只看到焦点请求失败,却没有可预测的回退路径。双栏资料浏览器有一个不太显眼的问题:内容换成了第二条,蓝色选中态也停在第二条,但接上键盘继续操作时,焦点可能回到第一条。另外,示例把已选中的 N-902 保存在父组件中,不依赖点击后的页面栈来恢复,因此也不等同于 Navigation 自动替应用保存焦点。这份方案的价值不在于创造新的“平行视界 API”,而是把列表业务键、焦点目标 ID、焦点请求受理和焦点实际落点拆成可核查的四个量。

李游的博客 53

HarmonyOS ohpm list × Node.js fs:三方库目录体积阈值与资源副本预检【鸿蒙心迹】

可靠的脚本至少应检查目标是否仍落在项目根下,区分普通文件与目录,拒绝跨目录的符号链接,并将读取失败当成明确错误而非记作零字节。示例对候选资源读取字节并计算 SHA-256,先按字节数分桶,再对疑似相同的内容求摘要,最后给出资源对。查看已安装依赖关系,人工或由 CI 维护一份被批准的目标目录映射,再让 Node.js 读取这些确定路径,不去猜某个版本的内部 lockfile 结构。这种做法少了一点“全自动发现”的炫目,却更容易审核:扫描范围是受控的,某个目录变了要修改配置,而不是让脚本在整个。

李游的博客 61

HarmonyOS ArkUI GridRow × accessibilityText:折叠屏大字模式下操作卡片的断点与朗读校验【鸿蒙心迹】

但当用户把系统字体调大,或者应用处于窄窗口时,标题变成两行,按钮的朗读信息却依然只有一个“查看”,四张卡片都是相同提示。这个函数只是测试用的契约校验,不属于 ArkUI 或系统无障碍 API,更不能替代真实聚焦和朗读顺序的体验测试。在本例里,四个按钮可见文字都叫“查看”,却分别设置“文档管理,查看”“图片处理,查看”等上下文标签。第四次开启屏幕朗读,从 A-01 依次移动到 A-04,记录实际读到的标签、动作、描述,以及聚焦跳转顺序。则为相邻卡片留出间距,不能用一个很大的空白文本元素强行撑开布局。

李游的博客 169

HarmonyOS 3DGS × Node.js:相机位姿时间戳与角度单位的重建前门禁【鸿蒙心迹】

前一轮已经讨论过输入帧序与缺口,这里换一个更深的位置:帧号连续只说明文件清单能排上队,不能证明同一场景的位姿元数据可用。3DGS 项目最让人头疼的环节未必是建模,而是输入数据看起来齐全,实际却有两类难以肉眼发现的元数据问题:相机位姿中的角度单位没有统一,或者采集时间戳在导出、合并时倒退。它不会触发拍摄,不会重建点云,不会向远端服务提交素材,反而方便把隐私敏感的拍摄数据与审计摘要分开保存。如果未来需要真正联动,需要另做可信的报告传递、签名和读取流程,不能把图片里的“导出预检清单”按钮当作已实现的系统能力。

李游的博客 99

HarmonyOS ArkUI ForEach × ArkTS Map:闪控窗候选提醒的 TTL 淘汰与重复合并【鸿蒙心迹】

本文代码和配图用于说明工程设计,示例时间、订单号、日志及屏幕都是;不表示已在 DevEco Studio 编译或真机跑通,也不表示接通系统闪控窗。所谓“候选提醒”,专指应用自行管理的展示列表。

李游的博客 175

HarmonyOS ArkUI $r × Node.js:上架前多语言占位符漂移与回退清单审计【鸿蒙心迹】

文章、日志、审核结果与配图均为,不是华为应用市场官方审核结论、真实审核接口调用或已完成的真机测试。本文的“BLOCK”只表示团队自定义发布门禁未通过。

李游的博客 159

HarmonyOS ArkData Preferences × ArkTS:精准碰一碰确认超时与撤回恢复【鸿蒙心迹】

Demo:TouchConsent|任务编号:TP-206|业务素材:DOC-418 / 会议资料.pdf / 2.3 MB内容性质:精准碰一碰的业务确认层方案。数据、日志、示意界面均由案例构造,未接入或实测系统精准碰一碰回调。

李游的博客 209

HarmonyOS ArkUI Image × ArkTS Promise:超分预览回包乱序与跨图串帧防护【鸿蒙心迹】

Demo:UltraPreview|任务编号:SR-206|方向:图像超分业务预览层内容性质:基于官方组件资料编写的工程示例;文中日志、数据和图片是,未在真机或 DevEco Studio 中实测,也不代表系统自带超分推理接口。

李游的博客 158

HarmonyOS 7 + ArkUI GridRow:折叠盘点页的筛选快照与断点渲染解耦【鸿蒙心迹】

本文通过 StockFold Demo 演示了折叠屏下响应式布局变化引发的查询错位风险:界面断点切换导致布局重构,若将当前视图状态误作导出条件,易造成“用户看到的”与“导出的”不一致。核心解决方案是:冻结筛选快照(QuerySnapshot),以 id 为唯一标识,确保异步回执比对快照而非实时输入;同时分离布局与业务状态,避免 onBreakpointChange 干扰查询逻辑。强调三类验证顺序与日志追踪,保障导出一致性,提升跨设备体验可靠性。

李游的博客 27

HarmonyOS 7 + Node.js JSON5:上架受限权限的发布凭据与视频证据映射【鸿蒙心迹】

本文介绍ReleaseProof本地发布材料预检工具,针对华为AppGallery Connect上架中“包内声明、发布配置、证据材料”三份清单不一致的常见问题。通过模拟检查受限权限R-01的视频缺失,输出NEEDS_REVIEW与具体缺项,实现对人工准备材料的完整性校验。工具仅做映射核对,不替代审核结论,强调清单来源可信、人工复核必要,并建议生成可追踪的工单以提升协作效率。

李游的博客 23

HarmonyOS 7 + ohpm nativeComponents:Native HAR 的 SDK 兼容声明分层校验【鸿蒙心迹】

本文介绍 NativeCompatGate 兼容性预检机制,针对 HAR 引入 Native 代码时的 SDK 版本不一致问题。通过分析 oh-package.json5 中的 compatibleSdkVersion 与 nativeComponents 字段,仅校验元数据(不反编译 ELF),识别如 NATIVE_SDK_TOO_NEW 等风险。基于整数版本比对,区分宿主、HAR 及 Native 组件的 SDK 标识,避免误判。报告页面清晰展示各层版本与问题来源,强调“本地门禁”非编译失败,提升复用组

李游的博客 26

HarmonyOS 7 + ArkUI Slider:折叠屏时间轴的朗读步长与精细编辑分离【鸿蒙心迹】

本文介绍FoldTrim项目中如何解决折叠屏下时间轴裁切的无障碍操作矛盾。通过分离“普通编辑步长”(step=1)与“朗读手势步长”(scrollStep=5),实现精准控制与高效操作的平衡。采用配置校验函数确保参数合法性,避免隐式错误;页面状态独立于布局变化,保障数据一致性;并通过纯函数测试验证逻辑正确性,区分推演与真实设备行为,提升开发可维护性与可测性。

李游的博客 23

HarmonyOS ArkTS×3DGS:相机位姿矩阵正交性检查与坏帧隔离【鸿蒙心迹】

本文提出名为 PoseFence (PF-1010) 的端侧3DGS重建前置校验工具,针对相机位姿数据中常见的旋转矩阵非法问题。通过检查矩阵正交性、单位长度及行列式符号,区分“缩放错误”(SKEW)与“镜像反射”(MIRRORED),避免误判重建算法缺陷。基于ArkTS实现轻量级校验逻辑,支持行优先格式输入,输出详细诊断报告。六组示例验证得4帧通过、1帧SKEW、1帧MIRRORED,强调校验不修改原始数据,仅作门禁拦截,保障后续重建流程可靠性。

李游的博客 17

HarmonyOS ArkUI×accessibilityText:发布前图标按钮无障碍标签覆盖巡检【鸿蒙心迹】

本文提出一种轻量级无障碍自查方案,通过维护静态控件清单与本地脚本审计图标按钮的可访问性标签。针对“无文字图标”易被忽略的问题,强调accessibilityText与accessibilityDescription的正确使用,并以AX-1011为例,实现4项自动通过、1项人工复核的可解释检查流程。方案不依赖自动扫描,重在建立业务责任机制:确保每个图标入口有唯一ID、清晰标签与语义说明,辅以断言验证与人工复核,避免仅凭数量达标而忽视真实可用性。最终目标是推动发布前可读性审查落地,而非替代设备实测。

李游的博客 27

HarmonyOS AppGallery Connect×Node.js:上架截图规格离线检查门禁【鸿蒙心迹】

本文介绍如何为华为AppGallery Connect发布构建本地图片门禁系统,通过Node.js脚本自动校验图标与竖版截图的尺寸、数量及文件大小,实现对AG-909任务的静态检查。脚本仅读取PNG头部信息,快速识别错误(如02-task.png高度不符),输出可追溯的修复建议,并以非零退出码提示失败,助力团队在发版前精准定位问题,提升上架效率与准确性。

李游的博客 33

HarmonyOS ArkUI List×平行视界:筛选后滚动锚点回填与右栏定位隔离【鸿蒙心迹】

本文探讨宽屏应用中左右分栏布局的锚点恢复问题,核心是区分“索引”与“记录ID”——筛选后列表顺序变化,仅靠索引无法准确还原用户浏览位置。通过引入anchorId(锚点)、selectedId(详情)和visible(筛选结果)三者分离的设计,确保滚动恢复不干扰右侧详情。利用纯函数resolveAnchor实现基于业务规则的兜底策略,结合ArkUI的Scroller与稳定key,实现精准锚点定位。同时建议以首个可见项更新锚点,避免因滚动误判位置,提升用户体验一致性。

李游的博客 21

HarmonyOS ArkTS×3DGS:采集包断号与失联帧的重建前门禁【鸿蒙心迹】

摘要(≤150字): 为解决拍摄中断后清单完整性误判问题,开发 FrameLedger 工具,在3DGS重建前校验采集清单。它独立检查序号缺失(如4、6)、空URI(如7),区分“未采集”与“引用失效”,输出三类计数:记录数、缺失序号、空引用序号。不依赖重建接口,仅基于自定义清单,确保结果可复现、不可混淆。通过明确边界与阻断逻辑,防止错误导出,保障数据可追溯性,提升采集流程可靠性。

李游的博客 21

HarmonyOS string.json×Node.js:上架前多语言占位符漂移巡检【鸿蒙心迹】

本文针对多语言本地化中“资源存在但文案不完整”的隐蔽问题,提出用Node.js编写静态巡检脚本LocaleProof,通过对比基准语言与目标语言的占位符数量与类型,精准识别如日语pickup_eta缺参数、privacy_hint缺失等2类问题。脚本拒绝静默覆盖,强制校验重复键与格式错误,输出具体文件与键名问题,支持CI流程集成。强调自动化检查无法替代人工审校,尤其在语序翻转、文化合规、布局适配等方面仍需人工介入。

李游的博客 17

HarmonyOS Image Kit×PixelMap:超分前ROI裁剪越界保护与资源归属【鸿蒙心迹】

本文针对图像超分流程中的裁剪预检环节,提出并实现 RoiBench 的边界校验逻辑(任务号 ROI-708)。针对原始像素坐标与界面缩放坐标的差异,设计 clampRoi 函数,通过角点计算确保选区合法,自动截取有效交集。结合 cropAndReleaseOwnedPixelMap 实现资源安全释放,避免共享 PixelMap 引发的副作用。进一步通过 estimateTarget 预估二倍超分所需内存(约 1.10 MiB),为后续处理提供预算参考。整体流程强调输入合法性、所有权清晰与可复查日志,不涉及实

李游的博客 14

HarmonyOS 闪控窗×ArkTS:取件倒计时前后台补偿与终态幂等【鸿蒙心迹】

本文以 QueuePulse 取件任务 QP-707 为例,揭示前后台切换下倒计时状态错乱的根源:将 remainingSec 当作唯一真相会导致业务事实失真。提出三层次设计:以 dueAtMs 为不可变截止时间,status 表示终态,remainingSec 仅作为实时计算值;通过 DeadlineClock 分离刷新调度与状态更新,确保恢复前台后正确重算剩余时间;引入 TerminalGate 防止“完成取件”与“到期关闭”重复提交。强调倒计时仅为展示,终态必须由幂等闸门控制,日志应区分刷新与业务事件

李游的博客 17

HarmonyOS ArkTS×精准碰一碰:交接回执幂等防重与状态回退【鸿蒙心迹】

本文以“现场交接”为场景,通过TapReceipt样例拆解物理触发、业务受理与回执落账三者差异。基于唯一requestId实现幂等判重,区分确认、重复与冲突状态;页面独立统计接收次数与有效确认数,确保可观测性;强调本地台账仅作临时缓冲,最终幂等需由服务端保障。同时提醒:状态不可逆、时间戳可信、日志过滤严谨,并指出跨进程持久化与版本控制等工程边界,为真实接入“碰一碰”能力提供前置设计参考。

李游的博客 16

HarmonyOS HAR×ArkGuard:混淆发布后公共接口契约保护【鸿蒙心迹】

本文聚焦HarmonyOS HAR库发布时的混淆兼容性问题,强调“debug通过≠release可靠”。核心指出:公共API稳定性不等于内部标识符不变,反射字符串、序列化字段等动态依赖易被忽略。需通过consumerFiles传递明确保留规则,并建立静态检查、构建产物验证与消费端运行回归三重隔离。建议以最小化保留策略保护真实契约,杜绝凭经验添加规则。巡检应区分“静态通过”与“发布通过”,关键路径必须人工复核,避免误判。最终强调:版本变更须同步更新契约与回归用例,确保发布可信。

李游的博客 28

HarmonyOS ArkWeb×JSBridge:营销H5消息白名单与过期会话隔离【鸿蒙心迹】

本文介绍鸿蒙应用中通过ArkWeb实现H5与原生交互的安全机制——PromoGate。针对外部页面可能发送非法或过期消息的风险,设计了基于sessionId、action、couponId的三重校验策略,仅允许特定动作(如openCoupon)且拒绝类型不符或旧会话请求。通过限制JSBridge暴露方法为单一submit,结合白名单控制与会话生命周期管理,确保消息可信、权限可控。示例验证三条测试用例:放行1条、拒绝类型1条、过期会话1条,强调安全边界应由原生侧严格把控,而非依赖前端校验。

李游的博客 16
上一篇: HarmonyOS 7 InsightBoard 多形态适配实录 05:WindowStage × Navigation:多窗口恢复、页面栈与业务状态持久化【鸿蒙心迹】
下一篇: HarmonyOS 7 DualCart 平行视界适配实录 01:Navigation × EasyGo:主页关联页与列表详情双栏链路【鸿蒙心迹】
李游Leo
李游Leo 北京杰森游睿教育科技有限公司 北京杰森游睿教育科技有限公司
博客等级 码龄14年 2155粉丝 668原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值