如何在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
相关产品推荐
相关产品推荐

