Flutter屏幕截图方法:桌面端仅捕获组件问题及全屏/窗口截图方案
2. Flutter桌面应用中如何截取系统屏幕/窗口(而非仅当前Widget)?
这里要划重点:Flutter自带的API只能捕获应用内部的内容,要截取整个系统屏幕或者其他外部窗口,必须借助各桌面平台的原生能力,通过Platform Channel调用原生API实现,下面分平台给你示例:
Windows平台
可以通过Win32 API实现,推荐用win32包简化调用:
- 先在
pubspec.yaml添加依赖:
dependencies: win32: ^5.0.0 image: ^4.0.17 # 用来处理位图转PNG
- Dart端调用代码:
import 'package:win32/win32.dart'; import 'dart:typed_data'; import 'package:image/image.dart' as img; Future<Uint8List?> captureWindowsFullScreen() async { final hdcScreen = GetDC(NULL); final hdcMem = CreateCompatibleDC(hdcScreen); final screenRect = GetWindowRect(GetDesktopWindow()); final width = screenRect.right - screenRect.left; final height = screenRect.bottom - screenRect.top; // 创建兼容屏幕的位图 final hBitmap = CreateCompatibleBitmap(hdcScreen, width, height); final oldBitmap = SelectObject(hdcMem, hBitmap); // 将屏幕内容复制到位图 BitBlt(hdcMem, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY); SelectObject(hdcMem, oldBitmap); // 将位图转换为PNG字节(解决图片倒置问题) final bitmapInfo = BITMAPINFO(); bitmapInfo.bmiHeader.biSize = sizeOf<BITMAPINFOHEADER>(); bitmapInfo.bmiHeader.biWidth = width; bitmapInfo.bmiHeader.biHeight = -height; // 翻转Y轴,避免截图倒置 bitmapInfo.bmiHeader.biPlanes = 1; bitmapInfo.bmiHeader.biBitCount = 32; bitmapInfo.bmiHeader.biCompression = BI_RGB; final buffer = Uint8List(width * height * 4); GetDIBits(hdcScreen, hBitmap, 0, height, buffer, bitmapInfo, DIB_RGB_COLORS); final image = img.Image.fromBytes(width, height, buffer, format: img.Format.rgba); final pngBytes = img.encodePng(image); // 释放系统资源 DeleteDC(hdcMem); ReleaseDC(NULL, hdcScreen); DeleteObject(hBitmap); return pngBytes; }
macOS平台
借助Quartz框架实现,通过Platform Channel调用Objective-C代码:
- 在macOS Runner项目的
RunnerViewController.m中添加平台方法:
#import <Cocoa/Cocoa.h> #import <Flutter/Flutter.h> @interface ScreenCapturePlugin : NSObject<FlutterPlugin> @end @implementation ScreenCapturePlugin + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"com.yourapp.screencapture" binaryMessenger:[registrar messenger]]; ScreenCapturePlugin* instance = [[ScreenCapturePlugin alloc] init]; [registrar addMethodCallDelegate:instance channel:channel]; } - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([@"captureFullScreen" isEqualToString:call.method]) { // 获取主屏幕的截图 CGDirectDisplayID displayID = CGMainDisplayID(); CGImageRef screenImage = CGDisplayCreateImage(displayID); if (!screenImage) { result(FlutterError(@"CaptureFailed", @"无法捕获屏幕内容", nil)); return; } // 转换为PNG格式数据 NSBitmapImageRep* bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:screenImage]; NSData* pngData = [bitmapRep representationUsingType:NSPNGFileType properties:@{}]; CFRelease(screenImage); result(pngData); } else { result(FlutterMethodNotImplemented); } } @end
- 在Dart端调用:
import 'package:flutter/services.dart'; final MethodChannel _screenCaptureChannel = MethodChannel('com.yourapp.screencapture'); Future<Uint8List?> captureMacOSFullScreen() async { try { return await _screenCaptureChannel.invokeMethod('captureFullScreen'); } on PlatformException catch (e) { print("截图失败:${e.message}"); return null; } }
Linux平台
使用GDK的截图能力,推荐gtk包:
- 添加依赖到
pubspec.yaml:
dependencies: gtk: ^2.0.0
- Dart端代码:
import 'package:gtk/gtk.dart'; Future<Uint8List?> captureLinuxFullScreen() async { final display = GdkDisplay.getDefault(); final screen = display.getDefaultScreen(); final rootWindow = screen.getRootWindow(); // 获取整个屏幕的Pixbuf对象 final pixbuf = GdkPixbuf.getFromWindow(rootWindow, 0, 0, screen.getWidth(), screen.getHeight()); if (pixbuf == null) return null; // 保存为PNG字节数据 return pixbuf.saveToBuffer('png'); }
总结
如果不想自己写原生代码,也可以找找专门的桌面截图第三方库,但这类库数量不多,大部分场景还是需要自己通过Platform Channel对接原生API实现系统级截图。
内容的提问来源于stack exchange,提问作者Jagadeesh




