HarmonyOS 7 + EasyGo-ArkUI VisibleArea:平行视界双窗曝光事件的去重与停留门禁【鸿蒙心迹】

示例项目:DualMetric
页面:ReadingWorkspacePage

平行视界把列表和详情同时摆到大屏上之后,页面可见性不再等同于一次完整曝光。列表中的文章卡片还露着一角,右侧详情已经打开;用户拖动分隔比例时,两侧组件又会连续触发可见区域变化。如果把 aboutToAppear 或每一次可见回调都当成曝光,统计会比真实阅读次数膨胀许多。

DualMetric 关注的不是如何把两个页面分栏,而是分栏完成后的观测语义:什么叫“看见”,停留多久才算一次,列表卡片与详情页能否分别统计,窗口缩放和路由重用又该如何去重。本文数据均为演示快照,不是线上埋点结果,也不冒充真机测量。

一、双窗把“页面出现”拆成了多种事实

在单页应用里,页面进入往往可以近似理解为一次浏览开始。平行视界同时展示主窗和辅窗后,这个近似失效了。左侧 FEED 里 article_2048 的卡片可能只有 40% 可见,右侧 DETAIL 已显示同一篇文章的正文;用户拖动分隔线时,左侧比例从 0.62 降到 0.58,再回到 0.65,短时间内产生多个边界回调。

官方多设备适配资料说明,平行视界面向折叠屏、平板等大屏设备提供应用内分屏体验;ArkUI 的可见区域变化事件可以报告组件可见状态及比例。两者结合后,开发者仍需自行定义业务曝光,系统不会替产品决定“多少比例、停留多久、同一内容是否合并”。

本文把事实分为四层:组件存在、可见比例达标、停留时间达标、逻辑曝光已提交。它们对应 HIDDEN → CANDIDATE → DWELLING → COMMITTED。任何窗口变化都可以让候选退回 HIDDEN,但已经提交的曝光不会因为一次尺寸抖动重复发送。

本次演示任务是 EXPOSURE-DUAL-0074,会话为 pv-s29,内容 ID 为 article_2048。可见阈值设为 0.60,停留门槛为 1200 ms。原始回调 14 次,最终提交 2 次:FEED 卡片一次、DETAIL 正文一次;9 次重复被丢弃,3 次因停留不足被取消。

二、曝光键必须包含“位置语义”

若只以 article_2048 去重,列表卡片和详情正文会互相吞掉;若只以组件实例去重,窗口重组后新实例又会重复计数。DualMetric 的曝光键由会话、窗格、内容、放置位和修订号组成。窗格是 FEED 或 DETAIL,放置位描述 card 或 reader,revision 用来区分内容实质变化。

这段代码解决什么问题。 它定义稳定曝光身份,避免组件实例 ID、数组下标和路由对象被误当成业务主键。

type Pane = 'FEED' | 'DETAIL'
type ExposureState = 'HIDDEN' | 'CANDIDATE' | 'DWELLING' | 'COMMITTED'

interface ExposureIdentity {
  sessionId: string
  pane: Pane
  placement: 'card' | 'reader'
  contentId: string
  revision: number
}

function exposureKey(id: ExposureIdentity): string {
  return [id.sessionId, id.pane, id.placement, id.contentId, id.revision].join('|')
}

const feedIdentity: ExposureIdentity = {
  sessionId: 'pv-s29', pane: 'FEED', placement: 'card',
  contentId: 'article_2048', revision: 29
}

sessionId 的范围是一次工作区会话,不是永久用户标识;页面重新冷启动时可生成新会话。revision 只在正文或卡片语义发生变化时递增,不能跟着每次 UI 重组变化,否则去重失去意义。

实际项目还要明确统计口径。如果产品只关心详情阅读,可以完全不提交 FEED 卡片;如果需要漏斗,就让 card 与 reader 成为两个 placement。关键是把口径写成配置,而不是在埋点平台里事后猜测两个同名事件为什么数量不同。

三、可见比例只是候选,不是提交条件

ArkUI 的 onVisibleAreaChange 很适合捕捉比例跨越。示例监听 0、0.6、1.0 三个阈值,但回调到达时只把事实交给协调器。组件不直接发埋点,也不持有长期计时器逻辑,避免列表复用和页面重组造成多套状态。

这段代码解决什么问题。 它把 FEED 卡片的可见比例送入统一协调器,并在组件退出时显式撤销候选。

@Component
struct FeedExposureCard {
  @Prop contentId: string = ''
  private identity: ExposureIdentity = feedIdentity

  build() {
    Column() {
      Text('组件可见性不是曝光')
      Text(this.contentId)
    }
    .onVisibleAreaChange([0.0, 0.6, 1.0],
      (_isVisible: boolean, currentRatio: number) => {
        exposureCoordinator.observe(this.identity, currentRatio, Date.now())
      })
  }

  aboutToDisappear(): void {
    exposureCoordinator.hide(this.identity, Date.now())
  }
}

当比例从 0.59 变为 0.61,状态进入 CANDIDATE,随后开启 1200 ms 停留检查。比例跌回阈值以下时,候选立即撤销。aboutToDisappear 作为资源收口,不代表曝光提交;它只确保组件消失时不会遗留计时器。

容易出错的是把 isVisible=true 直接等同于比例超过 0.60。回调同时给出 currentRatio,业务应按自己的阈值判断。列表滚动、窗口遮挡和分栏拖动都可能让比例来回穿越,协调器必须能处理频繁的候选创建和取消。

四、停留门禁需要一份可撤销的计时器

定时器最常见的问题不是“不触发”,而是旧候选已经失效,回调仍在 1200 ms 后提交。DualMetric 为每个 exposureKey 保存 token。每次重新候选都会生成新 token;计时器醒来时除了检查比例,还核对 token,只有仍属于当前候选才有提交权。

这段代码解决什么问题。 它把短暂可见与有效停留分开,并让过期计时器无法提交。

interface Candidate {
  state: ExposureState
  ratio: number
  since: number
  token: number
  timer?: number
}

class ExposureCoordinator {
  private readonly threshold: number = 0.60
  private readonly dwellMs: number = 1200
  private candidates: Map<string, Candidate> = new Map()
  private tokenSeed: number = 0

  observe(id: ExposureIdentity, ratio: number, now: number): void {
    const key = exposureKey(id)
    if (ratio < this.threshold) {
      this.hide(id, now)
      return
    }
    const current = this.candidates.get(key)
    if (current?.state === 'COMMITTED' || current?.timer !== undefined) return

    const token = ++this.tokenSeed
    const timer = setTimeout(() => this.tryCommit(id, token), this.dwellMs)
    this.candidates.set(key, {
      state: 'DWELLING', ratio, since: now, token, timer
    })
  }

  hide(id: ExposureIdentity, _now: number): void {
    const key = exposureKey(id)
    const current = this.candidates.get(key)
    if (current?.timer !== undefined) clearTimeout(current.timer)
    if (current?.state !== 'COMMITTED') this.candidates.delete(key)
  }
}

状态先从 HIDDEN 进入 CANDIDATE,再到 DWELLING。为了压缩代码,示例在同一个 observe 中完成前两步;诊断快照仍会保留这两个业务状态。重复回调看到 timer 已存在就直接返回,因此 14 次原始回调不会制造 14 个计时器。

页面离开、列表项回收和工作区销毁都要调用 hide 或 dispose。clearTimeout 与 setTimeout 成对处理;仅依赖垃圾回收不能阻止定时器闭包继续持有 identity。真实埋点发送还应在网络失败时进入独立队列,不要用曝光计时器承担重试职责。

图中的 DevEco Studio 为演示配图,不是实际运行证据。左侧是 DualMetric 工程,中央代码圈出 threshold=0.60、dwellMs=1200 与 token 校验,右侧模拟器显示 FEED/DETAIL 两个窗格,底部 HiLog 记录 callbacks=14、committed=2、duplicateDropped=9、shortDropped=3。

五、提交时还要经过会话级去重

计时器解决了抖动,却不能解决组件重建。平行视界改变显示比例、详情路由被复用或状态恢复后,同一个逻辑曝光可能对应新的组件实例和新协调器。最终提交前还需要一个会话级集合,记录已经成功交付的 exposureKey。

这段代码解决什么问题。 它在计时器回调与实际事件发送之间增加幂等门禁,并输出可核对的丢弃原因。

class ExposureSink {
  private committed: Set<string> = new Set()

  async commit(id: ExposureIdentity, ratio: number, dwellMs: number): Promise<boolean> {
    const key = exposureKey(id)
    if (this.committed.has(key)) {
      hilog.info(0x0000, 'DualMetric', 'duplicateDropped key=%{public}s', key)
      return false
    }
    await analyticsAdapter.send('parallel_exposure', {
      pane: id.pane,
      placement: id.placement,
      contentId: id.contentId,
      revision: id.revision,
      ratio,
      dwellMs,
      sessionId: id.sessionId
    })
    this.committed.add(key)
    return true
  }
}

只有发送成功后才写入 committed。如果适配器失败,事件留在待重试队列;但重试队列必须有自己的 eventId,避免“发送成功但响应丢失”造成重复。示例把 analyticsAdapter 明确为项目适配层,不把它包装成 HarmonyOS 系统接口。

若用户在同一会话里离开文章再回来,是否允许第二次曝光,需要产品口径决定。本文选择会话内去重,因此仍为一次;若要统计重访,可以在内容真正退出 30 秒后生成新的 visitId,并把它纳入 key。不要暗中用组件重建替代重访定义。

六、右侧详情与左侧卡片要分别计时

同一内容同时出现在 FEED 和 DETAIL,最容易出现两种极端:全部合并成一个事件,漏掉漏斗;全部当成详情阅读,又把卡片露出算作深度阅读。DualMetric 让窗格与 placement 进入 identity,因此 card 达到 60% 并停留 1200 ms 后提交 FEED/card,正文达到门槛后提交 DETAIL/reader。

运行页时间为 12:18,电量 76%,任务 EXPOSURE-DUAL-0074、会话 pv-s29、内容 article_2048。页面显示 FEED 比例 0.72、DETAIL 比例 1.00,两个 placement 都已 COMMITTED;原始回调 14、最终提交 2、重复丢弃 9、短停留丢弃 3,与日志完全一致。

这里的 2 次不是重复数据,而是两个事先定义好的漏斗节点。如果业务只需要一次“文章阅读”,则可以让 reader 提交时关联 cardEventId,并在报表层统计转化,而不是把两个事件强行压成一个无法解释的名称。

七、分栏拖动期间先冻结判断,避免边界振荡

用户拖动平行视界分隔区域时,可见比例可能在几百毫秒内频繁跨过 0.60。若每次都重新启动完整计时器,会产生大量对象和难读日志。DualMetric 在检测到高频变化后进入 180 ms 稳定窗口:只保存最后比例,窗口结束再决定是否创建候选。

这个稳定窗口不是延长曝光门槛。真正的 dwell 仍从稳定后的达标时刻计算,不能把拖动期间零散的 300 ms、400 ms 拼成 1200 ms。用户没有连续看到内容,就不应被算作有效停留。

稳定逻辑同样属于项目层。平行视界提供的是布局与显示体验,onVisibleAreaChange 提供可见事实;曝光语义、时间窗口和去重策略由应用承担。将责任边界写清楚,能避免后续把统计差异误判成系统回调缺陷。

八、诊断页应该还原一次曝光的证据链

只输出“事件已发送”不足以调试。DualMetric 为每个 key 保留最近一次诊断:最高比例、首次达标时间、累计连续停留、token、状态变化、提交结果和丢弃原因。它不保存用户阅读文本,也不记录永久标识,只保留定位这次会话所需的短期事实。

详情页展示 HIDDEN → CANDIDATE → DWELLING → COMMITTED,并列出 threshold 0.60、dwell 1200 ms、稳定窗口 180 ms。红圈分别标出 duplicateDropped=9 和 shortDropped=3,旁边说明前者来自回调重复与组件重建,后者来自不足 1200 ms 的短暂可见。

诊断数据应有容量上限,例如只保留最近 50 个 key,并在工作区结束时释放。开发版可以展示完整时间线,发布版日志要控制字段和等级,避免把内容标题、用户账号或可识别信息写入公共日志。

九、验证重点不是“回调有没有来”

第一组测试让 FEED 比例在 0.58 与 0.62 之间往返 10 次,最后稳定在 0.72;预期只有一个 timer,且 1200 ms 后提交一次。第二组让 DETAIL 达到 1.0 后仅停留 700 ms,预期进入 shortDropped,不得提交。第三组在计时期间重建组件,旧 token 回调必须失效。

第四组模拟发送失败。会话级 committed 不能提前写入,重试成功后才固定 key。第五组改变 revision 为 30,同一 article_2048 可以形成新曝光,证明修订语义有效。第六组结束 pv-s29,所有未完成 timer 都要被清理。

还应分别在折叠屏展开态、平板横屏、自由窗口缩放下观察比例回调。模拟器或预览可以验证 UI 和状态机,但不能据此声称所有目标设备上的窗口行为已经通过;正式统计前需要在目标设备和真实 EasyGo 配置下核对。

1. 停留时间要基于单调时钟,而不是墙上时间

示例为了便于阅读使用 Date.now(),真实停留计算更适合基于单调时钟。用户修改系统时间、网络校时或时区变化,都可能让墙上时间向前或向后跳;一段连续可见如果因此得到负数或异常大的 dwell,会污染统计。事件中的展示时间可以使用墙上时间,持续时长则应由不会随校时回拨的计时来源计算。

如果项目当前只能使用毫秒时间戳,也要增加防御:结束值小于开始值时不提交;单次 dwell 超过合理上限时截断为诊断异常,而不是当成深度阅读。since、committedAt 与 duration 三者应分别保存,不要只传一个模糊的 timestamp。

计时精度也不需要无限高。曝光判断使用 1200 ms 门槛,毫秒级足够;把纳秒级值写入日志只会让跨端比较更困难。更重要的是所有窗格使用同一计时来源,否则 FEED 与 DETAIL 的漏斗顺序可能出现颠倒。

2. 前后台切换必须暂停候选,而不是继续累计

应用进入后台时,组件树可能仍存在,旧计时器也可能继续等待。用户已经看不到内容,停留却累积到 1200 ms,回到前台后立刻提交,这是一类很隐蔽的假曝光。DualMetric 在应用不可见时统一暂停所有 DWELLING 候选,并记录 APP_HIDDEN 原因。

恢复前台后不续上之前的零散时间,而是重新读取当前可见比例,达到 0.60 才创建新候选。这与分栏拖动规则一致:曝光要求连续、真实可见,不能把后台前后的两个片段拼接。已经 COMMITTED 的 key 保持不变,避免恢复时重复发送。

系统弹窗、通知面板和多窗口遮挡是否算不可见,需要结合可获取的窗口事实和产品口径。onVisibleAreaChange 反映组件自身可见区域,不一定覆盖所有外部遮挡语义,因此文章不声称一个回调能证明“用户眼睛真的看到了”。可测的是组件可见和停留,用户注意力仍是统计推断。

3. 事件投递要接受“至少一次”,再靠 eventId 去重

网络发送存在一个经典灰区:服务端已经收到事件,客户端却在收到响应前断网。客户端重试会产生重复,不重试又可能丢失。仅在本地 Set 中记录 exposureKey 不能解决跨进程和服务端重试,因此每次逻辑曝光还应生成稳定 eventId,并让接收端按 eventId 幂等。

eventId 可以由 sessionId、exposureKey 与提交序号计算,不需要包含账号明文。事件写入本地待发送队列后,再由网络模块按顺序投递;服务端确认后删除。页面销毁不清空已落盘事件,但必须取消仍未达到 dwell 的候选。这样“可见性生命周期”和“网络投递生命周期”各自收口,不互相绑死。

队列还需要容量和过期时间。曝光数据失去时效后继续重试,价值可能很低,却会占用存储并影响新事件。示例没有实现真实队列,只把 analyticsAdapter 当作边界;实际项目应在适配器文档中写明最大条数、过期策略、重试退避和清理时机。

4. 策略版本决定一条数据能否与历史比较

把阈值从 0.60 改成 0.50,或把停留从 1200 ms 改成 800 ms,事件数量一定会变化。若上报中没有 policyVersion,数据平台会把口径变化误判成产品增长。DualMetric 因此给本次规则标记 visible-dwell-v3,与 pane、placement 一起发送。

策略调整要先用回放样本比较。可以把一段可见比例时间线喂给旧策略和新策略,观察 committed、duplicateDropped、shortDropped 的变化。本例的固定时间线在 v3 下得到 14→2;如果新规则得到 14→5,就必须解释多出的三次来自哪里,而不是只看总体数量上升。

策略版本不是应用版本。一次应用发布可能不改变曝光规则,也可能通过远程配置调整规则。真正用于报表分组的是能唯一描述阈值、停留、稳定窗口和重访定义的版本;应用版本则作为运行环境事实保留。

5. 埋点字段应比诊断界面更克制

诊断页可以显示内容 ID、窗格和状态链,但正式事件不应顺手携带完整标题、正文片段或用户输入。对曝光去重真正必要的是业务 ID、placement、revision、比例、停留、策略和会话;能从服务端关联的展示文案不必重复上传。

日志同样需要分级。开发构建可以输出完整 exposureKey,发布构建至少要避免可识别账号、URL 查询参数和正文。若内容 ID 本身包含敏感业务信息,可以在本地映射为短期不可逆标识,同时保留排查所需的 revision 与 placement。

数据最小化不是统计精度的对立面。字段越明确,越容易发现某个值其实没有决策用途。把“可能以后会用”的大对象塞进事件,既增加隐私风险,也让版本演进和服务端解析更困难。

十、结论:曝光是一次带证据的提交

平行视界让信息并列呈现,也让传统“页面出现即曝光”的假设失效。可靠的统计需要四个条件同时成立:稳定业务身份、明确可见比例、连续停留门槛和会话级幂等提交。组件生命周期只是证据来源,不是业务结论。

DualMetric 的演示结果是 14 次原始回调收敛为 2 次有效曝光,9 次重复和 3 次短停留被解释性丢弃。这个数字不代表平台性能,只说明状态机在固定输入下的输出。真正上线时,阈值、停留时间和重访口径都应由产品与数据团队共同确认,并写入版本化策略。

真正值得复用的不是 0.60 或 1200 ms 这两个数,而是“事实采集、候选计时、幂等提交、可解释诊断”四层分离。以后即使平行视界增加新的显示模式,或者同一内容同时出现在更多区域,也可以通过扩展 pane 与 placement 继续沿用,而不必把回调逻辑重新散落到每个组件里。

上线后的首轮观察也应克制:同时查看原始回调数、候选数、提交数和丢弃分布,而不是只盯曝光总量。若某类设备 duplicateDropped 激增,优先核对窗口重组和组件复用;若 shortDropped 激增,再检查阈值与交互节奏。状态机让这些判断有证据可循。

当数据口径需要调整时,保留旧策略的回放结果与诊断样本。新旧规则在同一时间线上并行计算,差异经过确认后再切换,能避免一次看似微小的阈值调整让历史趋势失去可比性。

参考资料:

  • HarmonyOS 多设备通用适配指南:https://developer.huawei.com/consumer/cn/multidevice/adaptive-apps/
  • HarmonyOS 7 平行视界能力说明:https://developer.huawei.com/consumer/cn/forum/topic/0201221235973021541
  • ArkUI onVisibleAreaChange 相关官方 FAQ:https://developer.huawei.com/consumer/cn/doc/doccenter-dev-faq/faqs-arkui-1603

相关推荐

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

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

李游的博客 253

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

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

李游的博客 99

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

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

李游的博客 196

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

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

李游的博客 253

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

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

李游的博客 270

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

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

李游的博客 26

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

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

李游的博客 88

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

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

李游的博客 51

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

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

李游的博客 59

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

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

李游的博客 166

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

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

李游的博客 97

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

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

李游的博客 173

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

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

李游的博客 157

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

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

李游的博客 208

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

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

李游的博客 156

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

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

李游的博客 26

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

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

李游的博客 21

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

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

李游的博客 24

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,强调校验不修改原始数据,仅作门禁拦截,保障后续重建流程可靠性。

李游的博客 16

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

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

李游的博客 24

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

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

李游的博客 31

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

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

李游的博客 21

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

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

李游的博客 20

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

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

李游的博客 16

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 防止“完成取件”与“到期关闭”重复提交。强调倒计时仅为展示,终态必须由幂等闸门控制,日志应区分刷新与业务事件

李游的博客 16

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

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

李游的博客 15

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

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

李游的博客 27

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

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

李游的博客 15
上一篇: HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 高斯参数的非有限值隔离与可渲染性门禁【鸿蒙心迹】
下一篇: HarmonyOS 7 + Node.js-fast-xml-parser:RSS-Atom 源结构漂移的规范化与实体门禁【鸿蒙心迹】
李游Leo
李游Leo 北京杰森游睿教育科技有限公司 北京杰森游睿教育科技有限公司
博客等级 码龄14年 2155粉丝 668原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值