从页面操作到内容理解:HarmonyOS 7 屏幕智感交互接入与边界处理实践

接入屏幕智感能力以后,系统不再只能"看到"页面上有什么控件,而是能理解这个页面在干什么。比如用户在订单详情页,系统知道当前展示的是哪个订单、按钮是"确认收货"还是"申请退款",就可以在合适的时机给出对应建议。
听起来很美好,但真正接入的时候发现,要让系统理解你的页面,光把组件画出来不够。你得告诉它每个区域是什么意思、哪些内容是动态变化的、哪些是敏感信息不能让它读。这些事情开发文档里不会详细讲,都是实际接了以后踩坑才知道的。
一、页面内容不是画出来就够了
刚开始接入的时候我以为,页面上有文字、有按钮、有列表,系统自己就能看懂。结果系统识别出来的信息一团糟——它把一个金额"¥128.00"识别成了普通文本,不知道这是价格;把"立即支付"按钮当成了普通文字,不知道这是可点击操作。
问题出在哪?系统看的不是你用了什么组件,而是组件上有没有附带语义描述。一个 Button 组件,如果你不给它加语义信息,系统就只能看到"这是一个按钮",看不到按钮上写的是什么、点击以后要干什么。
所以接入的第一步,是给页面上关键元素补上语义描述。文字区域说明它展示的是什么内容,按钮说明它的业务含义,列表项说明每条数据是什么。有了这些描述,系统才能真正理解页面,而不是只看到一堆 UI 元素。
二、业务数据和界面语义怎么对应
这是最花时间的部分。页面上显示的"订单号 202401010001",对用户来说是订单号,对系统来说如果只给它一个文本"订单号 202401010001",它不知道这个号码是什么意思。
正确的做法是:在语义描述里把业务含义带上。比如这个区域标注为"订单编号",值是"202401010001"。系统拿到这个语义,就知道这是订单号,而不是随便一串数字。
我在项目里封装了一个 SemanticHelper.ets,统一管理页面上需要被识别的语义信息。每个业务页面在 aboutToAppear 里注册自己的语义结构,在 aboutToDisappear 里注销。这样系统看到的就是结构化的业务信息,而不是散落在页面各处的文本。
下面这段代码放在 SemanticHelper.ets 里,定义了一个页面语义信息的结构,以及注册和更新的接口。它解决的问题:把页面上需要被屏幕智感识别的内容结构化,业务页面只填数据,不用关心底层怎么提交给系统。
export interface SemanticNode {
key: string;
label: string;
value: string;
sensitive: boolean;
}
export class SemanticHelper {
private static nodes: SemanticNode[] = [];
static register(nodes: SemanticNode[]): void {
this.nodes = nodes.map(n => ({
key: n.key,
label: n.label,
value: n.sensitive ? this.maskSensitive(n.value) : n.value,
sensitive: n.sensitive
}));
console.info(`[Semantic] registered ${this.nodes.length} nodes`);
}
static update(key: string, newValue: string): void {
const idx = this.nodes.findIndex(n => n.key === key);
if (idx >= 0) {
this.nodes[idx].value = this.nodes[idx].sensitive
? this.maskSensitive(newValue) : newValue;
console.info(`[Semantic] updated key=${key}`);
}
}
private static maskSensitive(value: string): string {
if (value.length <= 4) return '****';
return value.slice(0, 2) + '****' + value.slice(-2);
}
static clear(): void {
this.nodes = [];
}
}
这段代码要解决的问题:敏感字段(手机号、身份证、金额)在注册语义信息时自动脱敏,系统拿到的是打码后的值;非敏感字段直接传原值。页面数据变化时调 update 方法同步最新值,不用重新注册整个节点。
实际使用时要注意:maskSensitive 的脱敏规则要根据业务调整,不同敏感字段的脱敏方式不一样。update 方法只更新值,不改变节点结构——如果页面布局变了(比如多了一个列表项),需要重新调 register。sensitive 标记不要滥用,只对真正隐私的字段打标,普通业务数据脱敏反而会让系统识别不准。
三、动态页面变化以后如何同步最新状态

静态页面好处理,进入页面时注册一次语义信息就行了。但业务页面大部分是动态的——列表刷新数据变了、订单状态从"待发货"变成"已完成"、弹窗弹出来又消失。这些变化发生以后,如果不同步给系统,系统还以为页面是旧的。
我最开始踩的坑是:列表刷新以后新数据已经显示在界面上了,但语义信息还是旧的。系统读到的订单状态是"待付款",实际已经是"已完成"了。后来在列表数据更新的回调里调了 SemanticHelper.update(),把变化的字段同步过去,这个问题才解决。
还有一个容易忽略的点:页面切到后台再回来,要不要重新同步?我在 onPageShow 里加了一次完整的语义注册,确保每次页面显示到前台时,系统看到的都是最新状态。虽然多调了一次接口,但比系统读到过期信息要稳妥。
四、列表刷新和页面切换怎么避免识别旧内容
列表是动态内容的重灾区。一个列表有几十条数据,不可能每条都注册语义信息。实际做法是:只注册当前可视区域内的列表项语义,列表滚动时更新可视区域的节点。
页面切换的情况更简单:从 A 页面跳到 B 页面,A 页面 aboutToDisappear 里调 clear() 清掉语义信息,B 页面 aboutToAppear 里注册自己的。这样系统在任何时候都只看到当前页面的语义,不会把上一个页面的残留信息当成当前内容。
五、敏感内容和隐私信息的边界
屏幕智感能力会读取页面内容,哪些能读、哪些不能读,这个边界必须自己控制好。
手机号、身份证号、银行卡号这些绝对不能让系统拿到明文。金额、收货地址这些业务数据,要看业务场景决定要不要脱敏。我的做法是在 SemanticNode 里加了 sensitive 标记,注册时自动脱敏,系统拿到的是打码后的值。
还有一种情况:密码输入框、验证码输入框。这些区域直接不注册语义信息,系统看不到输入内容。不要想着"反正系统只用来做建议",隐私这件事宁可多遮一层。
六、识别不完整和状态过期怎么处理
不是所有页面都能被系统完整识别。复杂的自定义组件、WebView 里的内容、动态渲染的卡片,系统可能识别不出来或者识别不完整。这种时候不要硬塞错误的语义信息,识别不完整就降级处理——告诉系统"这个区域内容未知",比给它错误信息要好。
状态过期的情况也要考虑:页面已经退出了,但系统那边可能还在处理之前注册的语义。所以页面销毁时一定要 clear(),把过期信息主动失效。如果系统还拿着旧信息做建议,那就是我们没清理干净。

接入屏幕智感这件事,核心不是"让系统看到我的页面",而是"让系统看到正确的、最新的、不包含隐私的页面信息"。语义结构化、动态同步、敏感脱敏、过期清理,这四件事做到位了,这个能力才不会出问题。
更多推荐



所有评论(0)