You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter应用中阻止截屏及第三方应用截取屏幕?

Flutter 彻底阻止截屏及第三方应用录屏方案

Android 端实现

核心设置:FLAG_SECURE

Android 系统提供 FLAG_SECURE 标记,用于阻止系统截屏、录屏及第三方应用捕获屏幕内容。之前失效大概率是未覆盖所有窗口(主Activity、弹窗、WebView容器等),需确保所有展示内容的窗口都添加该标记。

在 MainActivity 中配置主窗口:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 给主窗口添加安全标记
    window.setFlags(
        WindowManager.LayoutParams.FLAG_SECURE,
        WindowManager.LayoutParams.FLAG_SECURE
    )
}

针对弹窗或自定义窗口,需单独设置:

// 示例:给Dialog添加FLAG_SECURE
val dialog = Dialog(this)
dialog.window?.setFlags(
    WindowManager.LayoutParams.FLAG_SECURE,
    WindowManager.LayoutParams.FLAG_SECURE
)

监听录屏启动(Android 12+)

部分第三方录屏应用通过 MediaProjection 权限捕获屏幕,可通过广播监听录屏状态,及时重新生效安全标记:

private val mediaProjectionReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_MEDIA_PROJECTION_STARTED) {
            // 检测到录屏启动,重新设置FLAG_SECURE
            window.setFlags(
                WindowManager.LayoutParams.FLAG_SECURE,
                WindowManager.LayoutParams.FLAG_SECURE
            )
            // 可选:提示用户停止录屏或隐藏敏感内容
        }
    }
}

override fun onResume() {
    super.onResume()
    registerReceiver(mediaProjectionReceiver, IntentFilter(Intent.ACTION_MEDIA_PROJECTION_STARTED))
}

override fun onPause() {
    super.onPause()
    unregisterReceiver(mediaProjectionReceiver)
}

iOS 端实现

核心设置:窗口安全属性

iOS 通过 UIWindow.isSecure 标记阻止截屏和录屏,该属性对系统及第三方应用均有效(非越狱设备)。

在 AppDelegate 中配置:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 标记主窗口为安全窗口
    window?.isSecure = true
    // 监听屏幕捕获状态变化
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(screenCaptureStateChanged),
        name: UIScreen.capturedDidChangeNotification,
        object: nil
    )
    return true
}

@objc private func screenCaptureStateChanged() {
    if UIScreen.main.isCaptured {
        // 检测到截屏/录屏,重新设置安全属性
        window?.isSecure = true
        // 可选:隐藏敏感内容或提示用户
    }
}

Flutter 层联动处理

通过 MethodChannel 实现原生与Flutter状态联动,在检测到屏幕被捕获时,动态隐藏敏感内容或显示遮罩:

Flutter 端代码

import 'package:flutter/services.dart';

class ScreenCaptureMonitor {
  static const _channel = MethodChannel('screen_capture_monitor');

  // 监听屏幕捕获状态流
  static Stream<bool> get captureStatusStream {
    return _channel.receiveBroadcastStream().map((event) => event as bool);
  }
}

在页面中使用:

bool _showContentMask = false;

@override
void initState() {
  super.initState();
  ScreenCaptureMonitor.captureStatusStream.listen((isCaptured) {
    setState(() {
      _showContentMask = isCaptured;
    });
  });
}

@override
Widget build(BuildContext context) {
  return Stack(
    children: [
      // 你的页面内容
      if (_showContentMask)
        Container(
          color: Colors.black,
          child: Center(child: Text("禁止录屏/截屏")),
        ),
    ],
  );
}

原生端补充实现

Android 端在 MainActivity 中添加MethodChannel逻辑:

private val channel = MethodChannel(flutterEngine!!.dartExecutor.binaryMessenger, "screen_capture_monitor")

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    channel.setMethodCallHandler { call, result ->
        when (call.method) {
            "isCaptured" -> {
                // 可结合广播状态实现捕获状态检测
                val isCaptured = false
                result.success(isCaptured)
            }
        }
    }
    // 捕获状态变化时主动发送事件到Flutter
}

iOS 端在 AppDelegate 中补充:

private let channel = FlutterMethodChannel(name: "screen_capture_monitor", binaryMessenger: window?.rootViewController as! FlutterBinaryMessenger)

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    channel.setMethodCallHandler { call, result in
        switch call.method {
        case "isCaptured":
            result.success(UIScreen.main.isCaptured)
        default:
            result.notImplemented()
        }
    }
    // 捕获状态变化时发送事件
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(sendCaptureStatus),
        name: UIScreen.capturedDidChangeNotification,
        object: nil
    )
    return true
}

@objc private func sendCaptureStatus() {
    channel.invokeMethod("captureStatusChanged", arguments: UIScreen.main.isCaptured)
}

关键注意事项

  • 无绝对完美方案:越狱/root设备可绕过系统限制,上述方案仅针对非越狱/root设备有效。
  • 功能权衡:设置安全标记后,应用无法使用屏幕共享、投屏等功能,需根据业务场景评估。
  • 覆盖所有窗口:确保应用内所有弹出窗口(Dialog、BottomSheet等)都添加安全标记,避免遗漏导致截屏漏洞。

内容的提问来源于stack exchange,提问作者Nassim Solimam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 22:04:58