Flutter桌面应用:macOS与Windows防截屏及录屏实现方案
Flutter桌面应用macOS+Windows截屏/录屏限制完整实现方案
macOS 平台录屏限制补充(含完整整合)
你已实现截屏拦截,这里补充录屏限制的原生实现,通过监听系统录屏状态通知,结合界面遮挡实现限制:
原生Swift代码(AppDelegate.swift)
import Cocoa import FlutterMacOS import AVFoundation @NSApplicationMain class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } override func applicationDidFinishLaunching(_ aNotification: Notification) { guard let controller = window?.contentViewController as? FlutterViewController else { return } let channel = FlutterMethodChannel(name: "screen_protection", binaryMessenger: controller.engine.binaryMessenger) // 监听系统录屏启停通知 NotificationCenter.default.addObserver(self, selector: #selector(onScreenRecordingStateChanged), name: .AVScreenCaptureDidStart, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(onScreenRecordingStateChanged), name: .AVScreenCaptureDidStop, object: nil) channel.setMethodCallHandler { [weak self] call, result in switch call.method { case "checkRecordingStatus": let isRecording = AVCaptureDevice.authorizationStatus(for: .screen) == .authorized result.success(isRecording) case "enableProtection": self?.showProtectionOverlay() result.success(nil) case "disableProtection": self?.hideProtectionOverlay() result.success(nil) default: result.notImplemented() } } } @objc private func onScreenRecordingStateChanged(_ notification: Notification) { let isRecording = notification.name == .AVScreenCaptureDidStart guard let controller = window?.contentViewController as? FlutterViewController else { return } let channel = FlutterMethodChannel(name: "screen_protection", binaryMessenger: controller.engine.binaryMessenger) // 通知Flutter端状态变化 channel.invokeMethod("recordingStateChanged", arguments: isRecording) // 自动开启/关闭遮挡 isRecording ? showProtectionOverlay() : hideProtectionOverlay() } // 显示全屏黑色遮挡层 private func showProtectionOverlay() { guard let window = self.window, let contentView = window.contentView else { return } let overlay = NSView(frame: contentView.bounds) overlay.wantsLayer = true overlay.layer?.backgroundColor = NSColor.black.cgColor overlay.tag = 1001 contentView.addSubview(overlay, positioned: .above, relativeTo: nil) } // 移除遮挡层 private func hideProtectionOverlay() { guard let contentView = window?.contentView else { return } contentView.subviews.forEach { if $0.tag == 1001 { $0.removeFromSuperview() } } } }
Flutter Dart层调用代码
import 'package:flutter/services.dart'; class ScreenProtection { static const _channel = MethodChannel('screen_protection'); // 检测当前是否在录屏 static Future<bool?> checkRecordingStatus() async { return await _channel.invokeMethod<bool>('checkRecordingStatus'); } // 手动开启屏幕保护 static Future<void> enableProtection() async { await _channel.invokeMethod('enableProtection'); } // 手动关闭屏幕保护 static Future<void> disableProtection() async { await _channel.invokeMethod('disableProtection'); } // 监听录屏状态变化 static void listenRecordingStatus(void Function(bool isRecording) callback) { _channel.setMethodCallHandler((call) async { if (call.method == 'recordingStateChanged') { callback(call.arguments as bool); } }); } }
macOS权限配置
在Info.plist中添加录屏权限描述:
<key>NSScreenCaptureUsageDescription</key> <string>需要限制屏幕录制以保护敏感内容</string>
Windows 平台完整实现(截屏+录屏限制)
Windows采用两种方案结合:系统API禁止窗口被捕获,同时检测常见录屏进程:
原生C++代码(集成到Flutter Windows工程)
在flutter_window.cpp或单独插件文件中添加:
#include <windows.h> #include <dwmapi.h> #include <tlhelp32.h> #include <flutter/method_channel.h> #include <flutter/plugin_registrar_windows.h> #include <flutter/standard_method_codec.h> #include <memory> #include <vector> #include <string> #pragma comment(lib, "dwmapi.lib") class ScreenProtectionPlugin : public flutter::Plugin { public: static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar); ScreenProtectionPlugin() = default; ~ScreenProtectionPlugin() override = default; private: void HandleMethodCall(const flutter::MethodCall<flutter::EncodableValue>& call, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result); // 设置窗口为受保护状态(禁止截屏/录屏) void SetWindowProtected(HWND hwnd, bool protect) { BOOL value = protect ? TRUE : FALSE; DwmSetWindowAttribute(hwnd, DWMWA_PROTECTED, &value, sizeof(value)); } // 检测是否存在活跃录屏进程 bool IsRecordingActive() { HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot == INVALID_HANDLE_VALUE) return false; PROCESSENTRY32 pe; pe.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(snapshot, &pe)) { CloseHandle(snapshot); return false; } // 常见录屏进程列表 const std::vector<std::wstring> recorderProcesses = { L"obs64.exe", L"Bandicam.exe", L"CamtasiaStudio.exe", L"Snagit.exe", L"XboxGameBar.exe", L"ShareX.exe" }; do { for (const auto& procName : recorderProcesses) { if (_wcsicmp(pe.szExeFile, procName.c_str()) == 0) { CloseHandle(snapshot); return true; } } } while (Process32Next(snapshot, &pe)); CloseHandle(snapshot); return false; } }; void ScreenProtectionPlugin::RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar) { auto channel = std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>( registrar->messenger(), "screen_protection", &flutter::StandardMethodCodec::GetInstance()); auto plugin = std::make_unique<ScreenProtectionPlugin>(); channel->SetMethodCallHandler( [plugin_ptr = plugin.get()](const auto& call, auto result) { plugin_ptr->HandleMethodCall(call, std::move(result)); }); registrar->AddPlugin(std::move(plugin)); } void ScreenProtectionPlugin::HandleMethodCall(const flutter::MethodCall<flutter::EncodableValue>& call, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { if (call.method_name() == "checkRecordingStatus") { result->Success(flutter::EncodableValue(IsRecordingActive())); } else if (call.method_name() == "enableProtection") { SetWindowProtected(GetForegroundWindow(), true); result->Success(nullptr); } else if (call.method_name() == "disableProtection") { SetWindowProtected(GetForegroundWindow(), false); result->Success(nullptr); } else { result->NotImplemented(); } } // 在RegisterPlugins中注册插件 void RegisterPlugins(flutter::PluginRegistry* registry) { ScreenProtectionPlugin::RegisterWithRegistrar( flutter::PluginRegistrarManager::GetInstance() ->GetRegistrarForPlugin("ScreenProtectionPlugin")); }
Flutter Dart层调用代码
复用之前的ScreenProtection类即可,无需额外修改。
Windows注意事项
DWMWA_PROTECTED仅支持Windows 10 1809及以上版本,低版本系统建议添加窗口遮挡逻辑(类似macOS的黑色overlay)。- 进程检测列表可根据需要补充更多录屏工具的进程名。
通用使用示例
在Flutter页面中调用:
@override void initState() { super.initState(); // 监听录屏状态变化 ScreenProtection.listenRecordingStatus((isRecording) { if (isRecording) { // 显示提示或自动开启保护 ScreenProtection.enableProtection(); } else { ScreenProtection.disableProtection(); } }); }
内容的提问来源于stack exchange,提问作者GNANA PRAKASH
相关产品推荐
相关产品推荐

