前言

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

SecureGate 是用户能直接看到的部分——当应用锁定时,一层毛玻璃效果的遮罩覆盖在内容上方,用户什么都看不清。这个效果完全用 Flutter Widget 实现,不依赖任何原生 UI,所以在 OpenHarmony 上天然就能工作。

但理解它的实现原理,对于调优模糊效果、自定义锁屏界面都很有帮助。今天我们把 SecureGate 的每一行代码都讲透。

一、SecureGate 的整体结构

1.1 Widget 定义

class SecureGate extends StatefulWidget {
  final Widget child;
  final Widget Function(BuildContext context,
      SecureApplicationController? secureApplicationController)? lockedBuilder;
  final double blurr;
  final double opacity;

  const SecureGate({
    Key? key,
    required this.child,
    this.blurr = 20,
    this.opacity = 0.6,
    this.lockedBuilder,
  }) : super(key: key);
}

1.2 参数说明

参数 类型 默认值 说明
child Widget 必填 需要保护的内容
blurr double 20 高斯模糊半径(越大越模糊)
opacity double 0.6 遮罩层透明度(0透明,1不透明)
lockedBuilder Function? null 锁定时显示在遮罩上方的自定义 Widget

1.3 blurr 值与视觉效果

blurr 值 效果 适用场景
5 轻微模糊,能隐约看到内容 非敏感内容
20 中度模糊,基本看不清 一般场景(默认值)
60 重度模糊,完全看不清 金融/医疗等高敏感场景
100 极度模糊,纯色效果 最高安全级别

💡 实际经验:blurr=20 配合 opacity=0.6 在大多数场景下效果不错。如果内容中有大字号文字,建议提高到 40 以上。

二、Stack + BackdropFilter 布局

2.1 build 方法


Widget build(BuildContext context) {
  return Stack(
    children: <Widget>[
      widget.child,
      if (_gateVisibility.value != 0)
        Positioned.fill(
          child: BackdropFilter(
            filter: ImageFilter.blur(
                sigmaX: widget.blurr * _gateVisibility.value,
                sigmaY: widget.blurr * _gateVisibility.value),
            child: Container(
              decoration: BoxDecoration(
                  color: Colors.grey.shade200
                      .withOpacity(widget.opacity * _gateVisibility.value)),
            ),
          ),
        ),
      if (_lock && widget.lockedBuilder != null)
        widget.lockedBuilder!(context, _secureApplicationController),
    ],
  );
}

2.2 三层 Stack 结构

┌─────────────────────────────────┐
│  第3层:lockedBuilder(解锁按钮)  │  ← 只在锁定时显示
├─────────────────────────────────┤
│  第2层:BackdropFilter(模糊遮罩) │  ← 动画控制显隐
├─────────────────────────────────┤
│  第1层:child(受保护的内容)       │  ← 始终存在
└─────────────────────────────────┘

2.3 BackdropFilter 的工作原理

BackdropFilter 是 Flutter 提供的一个 Widget,它会对其下方的所有内容应用滤镜效果:

BackdropFilter(
  filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
  child: Container(
    color: Colors.grey.shade200.withOpacity(0.6),
  ),
)
属性 作用
sigmaX 水平方向的模糊半径
sigmaY 垂直方向的模糊半径
child 遮罩层本身的内容(半透明灰色背景)

📌 注意:BackdropFilter 必须配合 Positioned.fill 使用,确保它覆盖整个区域。如果不用 Positioned.fill,模糊效果可能只应用到部分区域。

2.4 Positioned.fill 的作用

Positioned.fill(
  child: BackdropFilter(...)
)

Positioned.fill 等价于 Positioned(left: 0, right: 0, top: 0, bottom: 0),让 BackdropFilter 填满整个 Stack 区域。

三、AnimationController 动画控制

3.1 动画初始化

class _SecureGateState extends State<SecureGate> with SingleTickerProviderStateMixin {
  bool _lock = false;
  late AnimationController _gateVisibility;

  
  void initState() {
    _gateVisibility = AnimationController(
        vsync: this,
        duration: kThemeAnimationDuration * 2)
      ..addListener(_handleChange);
    SecureApplicationNative.opacity(widget.opacity);
    super.initState();
  }
}

3.2 动画参数

参数 说明
vsync this 使用 SingleTickerProviderStateMixin 提供的 Ticker
duration kThemeAnimationDuration * 2 约 400ms(200ms × 2)
value 范围 0.0 ~ 1.0 0=完全透明,1=完全模糊

3.3 锁定与解锁的动画行为

void _sercureNotified() {
  if (_lock == false && _secureApplicationController!.locked == true) {
    // 锁定:立即显示遮罩
    _lock = true;
    _gateVisibility.value = 1;  // 直接设为1,不做动画
  } else if (_lock == true && _secureApplicationController!.locked == false) {
    // 解锁:动画淡出遮罩
    _lock = false;
    _gateVisibility.animateBack(0).orCancel;  // 从1渐变到0
  }
}
操作 动画方式 原因
锁定 立即显示(value=1) 安全优先,不能让用户看到内容
解锁 渐变消失(animateBack) 用户体验,平滑过渡

💡 设计巧思:锁定时不做动画是有意为之。如果锁定也做渐变动画,在动画过程中用户可能短暂看到敏感内容,这是安全隐患。

3.4 _handleChange 回调

void _handleChange() {
  setState(() {
    // The listenable's state is our build state, and it changed already.
  });
}

每帧动画都触发 setState,让 build 方法重新执行,更新模糊强度。

3.5 动画值与模糊强度的关系

// 模糊强度 = blurr参数 × 动画值
sigmaX: widget.blurr * _gateVisibility.value
// 当 _gateVisibility.value = 0.5 时,模糊强度是 blurr 的一半
// 当 _gateVisibility.value = 1.0 时,模糊强度是 blurr 的全部

解锁时的渐变效果:

时间 0ms:   value=1.0  →  sigma=20  →  完全模糊
时间 100ms: value=0.75 →  sigma=15  →  较模糊
时间 200ms: value=0.5  →  sigma=10  →  中等模糊
时间 300ms: value=0.25 →  sigma=5   →  轻微模糊
时间 400ms: value=0.0  →  sigma=0   →  完全清晰

四、Controller 监听与生命周期

4.1 获取 Controller

SecureApplicationController? _secureApplicationController;


void didChangeDependencies() {
  if (_secureApplicationController == null) {
    _secureApplicationController = SecureApplicationProvider.of(context);
    _secureApplicationController!.addListener(_sercureNotified);
    _sercureNotified();  // 立即检查当前状态
  }
  super.didChangeDependencies();
}

为什么在 didChangeDependencies 而不是 initState 中获取?因为 SecureApplicationProvider.of(context) 需要 BuildContext,而 initState 中的 context 还不完整。

4.2 opacity 同步


void didUpdateWidget(SecureGate oldWidget) {
  super.didUpdateWidget(oldWidget);
  if (oldWidget.opacity != widget.opacity) {
    SecureApplicationNative.opacity(widget.opacity);
  }
}

当 opacity 参数变化时(比如用户拖动滑块),同步通知原生端。这主要是为了 iOS 平台的原生模糊遮罩。

4.3 资源释放


void dispose() {
  _secureApplicationController!.removeListener(_sercureNotified);
  _gateVisibility.dispose();
  super.dispose();
}

两件事:

  1. 移除 Controller 的监听器,防止内存泄漏
  2. 释放 AnimationController

五、lockedBuilder 自定义解锁界面

5.1 基本用法

SecureGate(
  blurr: 20,
  lockedBuilder: (context, controller) => Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Icon(Icons.lock, size: 64, color: Colors.white),
        SizedBox(height: 16),
        Text('应用已锁定', style: TextStyle(color: Colors.white, fontSize: 24)),
        SizedBox(height: 32),
        ElevatedButton(
          onPressed: () => controller?.authSuccess(unlock: true),
          child: Text('点击解锁'),
        ),
      ],
    ),
  ),
  child: MyProtectedContent(),
)

5.2 集成生物识别

lockedBuilder: (context, controller) => Center(
  child: ElevatedButton.icon(
    icon: Icon(Icons.fingerprint),
    label: Text('指纹解锁'),
    onPressed: () async {
      final localAuth = LocalAuthentication();
      final didAuth = await localAuth.authenticate(
        localizedReason: '请验证身份以查看内容',
      );
      if (didAuth) {
        controller?.authSuccess(unlock: true);
      } else {
        controller?.authFailed();
      }
    },
  ),
)

5.3 lockedBuilder 的显示条件

if (_lock && widget.lockedBuilder != null)
  widget.lockedBuilder!(context, _secureApplicationController),

两个条件同时满足才显示:

  1. _lock == true:当前处于锁定状态
  2. widget.lockedBuilder != null:开发者提供了自定义 Builder

如果没有提供 lockedBuilder,锁定时只显示模糊遮罩,没有解锁按钮。这种情况下解锁需要通过 SecureApplication.onNeedUnlock 回调来处理。

六、blurr 与 opacity 的动态调节

6.1 运行时调节

class _MyAppState extends State<MyApp> {
  double _blurr = 20;
  double _opacity = 0.6;

  
  Widget build(BuildContext context) {
    return SecureGate(
      blurr: _blurr,
      opacity: _opacity,
      child: Column(
        children: [
          Slider(
            value: _blurr,
            min: 0, max: 100,
            onChanged: (v) => setState(() => _blurr = v),
          ),
          Slider(
            value: _opacity,
            min: 0, max: 1,
            onChanged: (v) => setState(() => _opacity = v),
          ),
          Text('受保护的内容'),
        ],
      ),
    );
  }
}

6.2 不同组合的效果

blurr opacity 效果
0 0 无遮罩(不安全)
5 0.3 轻微遮挡
20 0.6 标准效果
60 0.8 强遮挡
100 1.0 完全不透明

📌 建议:不要把 blurr 和 opacity 都设为0,那样锁定时用户还是能看到内容,失去了保护的意义。

七、在 OpenHarmony 上的表现

7.1 渲染兼容性

SecureGate 使用的是标准 Flutter Widget:

  • Stack:布局容器
  • BackdropFilter:高斯模糊
  • AnimationController:动画控制
  • Container + BoxDecoration:背景色

这些都是 Flutter 框架的核心 Widget,在 OpenHarmony 上的 Flutter 渲染引擎中完全支持,不需要任何适配。

7.2 性能考量

BackdropFilter 的高斯模糊是 GPU 加速的,在 OpenHarmony 设备上的性能表现:

设备类型 blurr=20 blurr=60 blurr=100
高端手机 流畅 流畅 流畅
中端手机 流畅 轻微掉帧 可能掉帧
低端设备 流畅 可能掉帧 建议降低

7.3 与原生隐私模式的配合

SecureGate 的模糊遮罩和原生端的 setWindowPrivacyMode互补关系

层级 机制 保护范围
Flutter 层 BackdropFilter 模糊遮罩 用户回到 App 时看到的内容
原生层 setWindowPrivacyMode 应用切换器中的缩略图、截屏

两者缺一不可:

  • 只有 Flutter 层遮罩:应用切换器中还是能看到内容
  • 只有原生层隐私模式:用户回到 App 时能直接看到内容

总结

本文详细分析了 SecureGate 模糊遮罩的实现原理:

  1. 三层 Stack 结构:child + BackdropFilter + lockedBuilder
  2. BackdropFilter:GPU 加速的高斯模糊,sigmaX/sigmaY 控制模糊强度
  3. AnimationController:锁定立即显示,解锁渐变消失
  4. lockedBuilder:支持自定义解锁界面,可集成生物识别
  5. 跨平台兼容:纯 Flutter Widget 实现,OpenHarmony 上无需适配

下一篇我们分析 Android 端的 FLAG_SECURE 实现——理解它有助于我们在 OpenHarmony 上找到对应的方案。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

请添加图片描述

SecureGate 锁定状态下的高斯模糊遮罩效果

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐