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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:09:50