跳转至正文

Capacitor Privacy Screen:隐藏应用内容

添加 Capacitor privacy screen,在应用切换器中隐藏应用内容并阻止截屏,支持逐屏控制、配置及平台注意事项。

为 Capacitor 应用添加隐私屏幕的安全设置示意图

Capacitor 隐私屏幕可以在用户打开应用切换器时隐藏应用内容,并在 Android 上阻止截屏和录屏。如果没有它,iOS 和 Android 会截取你最后一个屏幕的快照,导致银行余额、医疗记录或一次性 code 仍会显示在最近应用列表中。 @capgo/capacitor-privacy-screen 只需一次调用或一个配置标志即可添加此功能,并让你只保护需要保护的屏幕。

应用切换器会暴露哪些信息

当用户离开你的应用时,两个系统都会截取当前屏幕的图像:

  • iOS 在应用失去活跃状态时截取快照,并在应用切换器中显示,同时在应用重新启动时短暂显示。
  • Android 在“最近使用”中显示实时或缓存的预览。

任何瞥见手机的人都会看到该快照。屏幕共享通话的人,或为支持工单录制屏幕的用户也是如此。截图还会同步到云端照片库,这正是敏感数据真正泄露的地方。

哪些应用需要此功能

应用类型 可能泄露的内容
银行、金融科技、加密货币 余额、卡号、IBAN、交易记录
密码管理器、身份验证器 密码、TOTP 验证码、恢复密钥
健康与医疗 诊断结果、处方、化验单
即时通讯 私密对话
人力资源、薪资、法务 薪资、合同
约会、私密媒体 照片和匹配

针对这些类别的安全审查和渗透测试通常会标记缺少应用切换器保护的问题。OWASP MASVS 包含对通过 UI 暴露敏感数据的检查,审计人员会专门测试这一点。

安装

bun add @capgo/capacitor-privacy-screen
bunx cap sync

该插件 8.x 版本支持 Capacitor 8。

方案 1:从启动起保护整个 App

在以下位置设置: capacitor.config.ts。原生插件在加载时、在您的 JavaScript 运行之前就会读取它,因此连第一个快照也受保护:

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.bank',
  appName: 'Example Bank',
  webDir: 'dist',
  plugins: {
    PrivacyScreen: {
      enabled: true,
      android: {
        dimBackground: false,
        privacyModeOnActivityHidden: 'splash',
      },
      ios: {
        blurEffect: 'dark',
      },
    },
  },
};

export default config;

运行 bunx cap sync 修改配置后。该 enabled 该选项仅从 Capacitor 配置中读取,并非运行时选项。

方案 2:保护特定页面

import { PrivacyScreen } from '@capgo/capacitor-privacy-screen';

export async function enterSensitiveScreen() {
  await PrivacyScreen.enable({
    android: { dimBackground: true },
    ios: { blurEffect: 'light' },
  });
}

export async function leaveSensitiveScreen() {
  await PrivacyScreen.disable();
}

const { enabled } = await PrivacyScreen.isEnabled();

把这些挂到路由里,覆盖每一条进出路径。以 Vue Router 为例:

router.afterEach(async (to) => {
  if (to.meta.sensitive) {
    await PrivacyScreen.enable();
  } else {
    await PrivacyScreen.disable();
  }
});

在 Angular 中,使用 guard 或 NavigationEnd subscription。在 React Router 中,在 layout 组件里放一个 hook 就行。关键是返回导航、deep link 和标签页切换都走同一套逻辑,否则敏感页面可能得不到保护。

各选项的作用

Android

  • 保护机制使用 WindowManager.LayoutParams.FLAG_SECURE。开启后,系统会拦截截屏和录屏,并隐藏最近任务预览。
  • dimBackground: true 在应用切换器中显示暗色遮罩。使用 false时,插件会在可用时显示 splash drawable,否则回退为变暗。
  • privacyModeOnActivityHidden 控制 Activity 被其他内容(例如系统生物识别 prompt)遮挡时显示什么: 'none' (默认), 'dim' 或 'splash'.
  • 进行设置。旧版 preventScreenshots 选项已弃用且被忽略。 FLAG_SECURE 在保护开启期间始终生效。若需允许在特定屏幕截图,请调用 disable() 在其之前,并在 enable() 之后调用。

iOS

  • 当应用失去活跃状态时,插件会添加一个覆盖层,确保应用切换器中的快照不显示您的内容。
  • blurEffect: 'light' 或 'dark' 使用原生模糊效果。 'none' (默认)在可用时显示启动屏幕,否则显示系统背景。
  • 启用期间,应用内容也会被放置在安全渲染层中。请将 iOS 截图拦截视为尽力而为:Apple 未提供官方的 API 来阻止截图,且行为可能随 iOS 版本变化。

Web 端

Web 实现仅跟踪启用标志,以便您的 code 在所有地方运行。浏览器无法隐藏标签页预览或阻止截图。

结合生物识别使用

银行类应用的常见模式:在切换器中模糊显示,然后在应用恢复后一段时间要求 Face ID 或指纹。该插件的 privacyModeOnActivityHidden 在 Android 生物识别提示显示期间保持内容被覆盖。

import { App } from '@capacitor/app';
import { NativeBiometric } from '@capgo/capacitor-native-biometric';

// null until the app has really gone to the background
let backgroundedAt: number | null = null;

App.addListener('appStateChange', async ({ isActive }) => {
  if (!isActive) {
    backgroundedAt = Date.now();
    return;
  }
  const away = backgroundedAt === null ? 0 : Date.now() - backgroundedAt;
  backgroundedAt = null;
  if (away > 60_000) {
    await NativeBiometric.verifyIdentity({ reason: 'Confirm it is you' });
  }
});

请参阅 原生生物识别插件 用于设置和错误处理。

官方插件和 Capgo 插件

Capacitor 团队还发布了 @capacitor/privacy-screen 具有非常相似的 API(enable, disable, isEnabled 以及相同的平台选项)。Capgo 插件保留了该 API 并添加了:

  • enabled: true 在 Capacitor 配置中,因此保护会在任何 JavaScript 运行前生效。官方插件只能从 JavaScript 端启用。
  • 启用时 iOS 会安全渲染内容,这已作为插件行为的一部分记录在文档中,此外还有应用切换器覆盖层。
  • getPluginVersion() 用于诊断。
  • 一个 Web 实现,保留启用标志,让同一个 code 能在浏览器预览中运行。

如果你已经在使用官方插件,切换基本上只是改一下 import。

至关重要的 UX 细节

  • 不要无缘无故地在所有地方拦截截图。 用户会截取收据、确认码和设置界面。除非安全策略要求,否则应仅保护包含敏感数据的页面,而非整个 App。
  • 告知用户原因。 如果 Android 用户尝试截图却只得到一张黑图,在帮助中心提供简短说明可以减少支持工单。
  • 测试屏幕共享。 在 Android 上,视频通话和投屏会被拦截,只要 FLAG_SECURE 该设置处于启用状态。如果你的 App 有“与客服共享屏幕”的流程,请针对该流程禁用保护。
  • 检查无障碍功能。 屏幕阅读器仍然可以配合使用 FLAG_SECURE但无论如何都要使用 TalkBack 和 VoiceOver 进行测试。

测试清单

  1. 打开敏感屏幕,切换到应用切换器。两个平台上的内容都必须被隐藏。
  2. 在 Android 上,尝试截图和录屏。两者都必须显示为黑色或被阻止。
  3. 触发生物识别 prompt,并检查背景。
  4. 从敏感屏幕返回到普通屏幕。如果使用 per-screen 模式,保护应自动关闭。
  5. 强制关闭并重新启动应用。使用 enabled: true 在配置中,第一个快照必须受到保护。
  6. 在 iPad 上测试 Split View 和 Slide Over。应用未激活时可能仍然可见。

故障排除

iOS 上的快照仍会显示内容。 您在应用已退到后台后才启用了保护,或者仅在部分路由上启用。请使用配置选项实现全应用保护。

Android 的最近任务中显示黑屏,而非启动画面。 设置 dimBackground: false 并确保 splash drawable 已存在,否则插件会回退到变暗模式。

Android 端截图仍然可用。 查看 isEnabled()。你 App 的其他部分可能会调用 disable() 在页面跳转时。

OTA 更新后保护失效。 配置值属于原生层。如果你更改了 plugins.PrivacyScreen 中的 capacitor.config.ts,请发布新的商店版本。运行时 enable() 以及 disable() JavaScript 中的调用可以通过以下方式更改: Capgo 实时更新.

Privacy Screen 是移动端安全检查清单中的一项。此外,还应关注安全存储、证书固定和 Root 检测。Capgo 提供以下插件: SSL Pinning 以及 Root 和越狱检测;此外,我们关于 Apple 针对 Capacitor 应用的隐私规则的文章 涵盖了审核方面的细节。完整的插件选项请参阅 Privacy Screen 文档.

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。