鸿蒙防窥能力适合接到哪些业务页面,不适合哪些页面

适合谁看

  • 想判断鸿蒙防窥能力落点的人

  • 做内容型、工具型、隐私型页面设计的人

  • 不想为了展示能力而牺牲体验的人

问题背景

系统能力一旦接进项目,大家很容易出现两个极端:

  • 什么页面都不接

  • 什么页面都接

真正合理的做法,是让能力只出现在它真正有价值的页面。

项目中的真实场景

食界探味当前的防窥命名已经给了一个很强的信号:

复制代码
// anti_peep_protection_channel.dart

static Future<void> activateCollectionProtection() async {
  await _invoke('activateCollectionProtection');
}

static Future<void> deactivateCollectionProtection() async {
  await _invoke('deactivateCollectionProtection');
}

方法名里的 Collection 说明它优先面向收藏页。

激活时机在 app.dart 的底部导航栏管理中:

复制代码
_scheduleCollectionProtectionSync(
  isLoggedIn && widget.navigationShell.currentIndex == 2,  // index 2 = 收藏页
);

只有用户切到收藏页(index 2)且已登录时才激活防窥。

核心实现

一、适合接入防窥的页面

页面 为什么适合 防窥价值
收藏页 展示用户收藏的菜品,暴露个人口味偏好
心愿单页 展示用户"想吃"的菜品,暴露个人兴趣
个人资料页 展示用户名、头像、个人设置 中高
订单/历史页 展示用户消费记录
AI 对话历史 展示用户和 AI 的对话内容 中高

这些页面的共同特点:内容和个人身份、偏好、消费行为强关联。被旁人看到可能造成真实困扰。

食界探味当前选择收藏页作为防窥对象,原因很明确:

复制代码
收藏页的内容:
  - 用户收藏了哪些菜品 → 暴露口味偏好
  - 用户喜欢哪个国家的菜 → 暴露饮食习惯
  - 用户收藏的频率和时间 → 暴露生活规律

被旁人看到的后果:
  - "你怎么收藏了这么多日料" → 尴尬
  - "你居然喜欢这个" → 隐私暴露

二、不适合接入防窥的页面

页面 为什么不适合 防窥价值
首页/探索页 公共推荐内容,和个人无关
搜索页 搜索结果是公共数据
菜品详情页 展示的是公共菜品信息
食材列表页 公共食材数据
风味地图页 公共地理数据
关于页/设置页 不涉及个人数据

这些页面即使不开防窥,实际风险也不高。如果强行开启,反而会:

  • 打断用户浏览公共内容的体验

  • 增加不必要的系统开销

  • 让用户困惑"为什么看个菜谱还要防窥"

三、判断框架------3 个问题

判断一个页面是否适合接入防窥,问自己 3 个问题:

问题 是 → 适合 否 → 不适合
这里展示的内容是否明显带有用户偏好? 适合 不适合
被旁人看到会不会造成真实困扰? 适合 不适合
开启防窥后会不会明显打断主要操作? 不适合 适合

三个条件需要同时满足前两个"是",且第三个"否",才值得接。

用这个框架检验食界探味的收藏页:

问题 收藏页 探索页
内容带有用户偏好? ✅ 是 ❌ 否
被看到有困扰? ✅ 是 ❌ 否
会打断操作? ❌ 否(只是隐藏内容) ❌ 否
结论 ✅ 适合 ❌ 不适合

四、食界探味的页面分析

食界探味当前的主要页面:

页面 Tab 个人数据 防窥适合度
探索页 首页 ❌ 不适合
灵感页 Tab 2 ❌ 不适合
收藏页 Tab 3 有(收藏的菜品) ✅ 适合
我的页 Tab 4 有(个人资料) ⚠️ 可考虑
AI 助手页 独立页 有(对话历史) ⚠️ 可考虑
搜索页 独立页 ❌ 不适合
菜品详情页 独立页 ❌ 不适合
食材详情页 独立页 ❌ 不适合

当前只在收藏页激活防窥,这是一个合理的起点。未来可以考虑扩展到 AI 助手页(对话历史可能暴露用户兴趣)。

五、为什么不应该全局开启

全局开启防窥的问题:

问题 说明
体验断裂 用户看个菜谱都要被遮罩,体验很差
系统开销 鸿蒙一直监听防窥事件,浪费资源
用户困惑 "为什么这个页面也要防窥?"
误触发 公共内容被遮罩,用户以为 app 出 bug 了
比赛扣分 评委看到全局防窥会质疑产品判断力

六、防窥的激活时机设计

食界探味的激活时机设计:

复制代码
// app.dart → _ScaffoldWithNavBarState

void _scheduleCollectionProtectionSync(bool shouldProtect) {
  if (_lastCollectionProtectionTarget == shouldProtect) return;
  _lastCollectionProtectionTarget = shouldProtect;
  WidgetsBinding.instance.addPostFrameCallback((_) {
    if (!mounted) return;
    if (shouldProtect) {
      AntiPeepProtectionChannel.activateCollectionProtection();
    } else {
      AntiPeepProtectionChannel.deactivateCollectionProtection();
    }
  });
}

调用时机:

复制代码
用户切 Tab
  │
  ├─ currentIndex == 2(收藏页)→ activate
  ├─ currentIndex != 2 → deactivate
  │
  ▼
页面退出
  │
  └─ dispose() → deactivate(确保取消)

这个设计保证了:

  • 只在收藏页时激活,其他页面不激活

  • 切走时立即取消,不残留

  • 退出时兜底取消,不泄漏

七、防窥和页面体验的平衡

防窥保护会增加一层"被监控感"。所以在设计时需要平衡:

维度 好的设计 差的设计
激活范围 只在敏感页面 全局所有页面
用户感知 自然,无感 突然出现蒙层
退出处理 切走即取消 需要手动关闭
内容处理 隐藏敏感内容 遮住整个屏幕
系统提示 不打扰用户 弹窗提醒"已开启防窥"

食界探味当前的做法是"进入收藏页自动激活,离开自动取消",用户完全无感。这是最好的体验。

八、如果要扩展到更多页面

如果以后要在更多页面接入防窥,建议:

  1. 按敏感度分级 --- 收藏页 > AI 对话 > 个人资料 > 其他

  2. 渐进式扩展 --- 先收藏页,验证效果后再扩展

  3. 保持按需激活 --- 永远不要全局常驻

  4. 页面级控制 --- 每个页面自己决定是否需要防窥

关键代码位置

文件 作用
app/lib/core/platform/anti_peep_protection_channel.dart 防窥通道
app/lib/app.dart 页面级激活/取消防窥
app/ohos/entry/src/main/ets/plugins/AntiPeepProtectionPlugin.ets 鸿蒙原生插件

常见坑

  • 为了展示能力,对所有页面全局开启 --- 体验断裂,评委质疑

  • 只从比赛展示角度判断,不从用户场景判断 --- 用户不需要看菜谱时防窥

  • 页面敏感度其实不高,却引入了额外交互打扰 --- 公共内容不需要防窥

  • 没有退出页面后的关闭逻辑 --- 防窥残留,影响后续页面

  • 没有检查用户是否已登录 --- 未登录时没有个人数据,不需要防窥

  • 防窥和页面动画冲突 --- 蒙层出现时页面正在转场,体验差

可复用模板

页面防窥判断模板

复制代码
判断页面是否需要防窥:
  □ 内容是否带有用户偏好/个人数据?
  □ 被旁人看到是否造成真实困扰?
  □ 开启后是否打断主要操作?
  □ 用户是否有明确的隐私预期?

  4 个"是"→ 适合
  3 个"是"→ 考虑
  2 个及以下 → 不适合

页面级防窥激活模板

复制代码
class SensitivePage extends StatefulWidget {
  @override
  State<SensitivePage> createState() => _SensitivePageState();
}

class _SensitivePageState extends State<SensitivePage> {
  @override
  void initState() {
    super.initState();
    AntiPeepProtectionChannel.activateCollectionProtection();
  }

  @override
  void dispose() {
    AntiPeepProtectionChannel.deactivateCollectionProtection();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<AntiPeepVisibilityState>(
      valueListenable: AntiPeepProtectionChannel.visibilityState,
      builder: (context, state, child) {
        if (state == AntiPeepVisibilityState.hidden) {
          return const SafePlaceholder();
        }
        return child!;
      },
      child: const SensitiveContent(),
    );
  }
}

Tab 级防窥激活模板

复制代码
// 根据当前 Tab 决定是否激活
void syncProtection(int currentIndex) {
  final shouldProtect = currentIndex == SENSITIVE_TAB_INDEX;
  if (shouldProtect) {
    AntiPeepProtectionChannel.activateCollectionProtection();
  } else {
    AntiPeepProtectionChannel.deactivateCollectionProtection();
  }
}

本篇总结

防窥能力应该按页面价值接入,而不是按"能接就接"。核心判断标准:

  1. 内容敏感度 --- 是否带有用户偏好和个人数据

  2. 暴露后果 --- 被旁人看到是否造成困扰

  3. 体验影响 --- 开启后是否打断主要操作

食界探味当前只在收藏页激活防窥,是因为收藏页是整个 app 中个人数据最集中、隐私敏感度最高的页面。探索页、搜索页、详情页都是公共内容,不需要防窥。

对系统能力做业务筛选,本身就是成熟项目的一部分。"能接"不代表"该接",选择在哪里接、不在哪里接,体现的是产品判断力。