如何在MAUI(iOS和Windows平台)截取含副屏的全屏截图
MAUI实现包含副屏的全屏截图方案
MAUI内置的Screenshot.Default.CaptureAsync()仅能捕获应用自身界面,要实现包含副屏的全屏截图,需依赖各平台原生API进行定制开发,以下是各主流平台的实现方案:
Windows平台
利用Windows.Graphics.Capture API实现多显示器捕获,支持直接获取所有显示设备的画面:
using Windows.Graphics.Capture; using Windows.Media.Capture; using Windows.Storage; using Windows.UI.Core; public async Task CaptureAllMonitors() { // 获取系统中所有显示监视器 var allMonitors = await GraphicsCaptureMonitor.GetAllMonitorsAsync(); if (allMonitors.Count == 0) return; foreach (var monitor in allMonitors) { var captureItem = GraphicsCaptureItem.CreateFromMonitor(monitor); var captureSession = new GraphicsCaptureSession(captureItem); // 开启鼠标捕获 captureSession.IsCursorCaptureEnabled = true; // 创建帧池,指定捕获格式与尺寸 var framePool = Direct3D11CaptureFramePool.Create( GraphicsCaptureHelper.GetDevice(), DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, captureItem.Size); var frameReader = framePool.CreateFrameReader(); frameReader.FrameArrived += async (sender, args) => { using var capturedFrame = frameReader.TryGetNextFrame(); if (capturedFrame == null) return; // 将捕获帧保存为PNG文件 var saveFile = await KnownFolders.PicturesLibrary.CreateFileAsync( $"Monitor_{monitor.DisplayId}_Capture.png", CreationCollisionOption.ReplaceExisting); await GraphicsCaptureHelper.SaveFrameToFile(capturedFrame, saveFile); }; // 启动捕获 captureSession.StartCapture(); // 延迟确保捕获完成(可根据需求调整或通过事件触发停止) await Task.Delay(1000); // 释放资源 captureSession.Close(); framePool.Close(); frameReader.Dispose(); } }
注意事项:
- 需要在Package.appxmanifest中添加
graphicsCapture权限 - 需确保应用拥有文件读写权限
Android平台
通过MediaProjection API实现全屏捕获,需先获取用户授权:
1. 请求屏幕捕获权限
using Android.App; using Android.Content; using Android.Media; using Android.OS; using Android.Views; private const int ScreenCaptureRequestCode = 1001; private MediaProjection _mediaProjection; public void RequestFullScreenCapturePermission() { var projectionManager = (MediaProjectionManager)Android.App.Application.Context .GetSystemService(Context.MediaProjectionService); var captureIntent = projectionManager.CreateScreenCaptureIntent(); ((Activity)Platform.CurrentActivity).StartActivityForResult(captureIntent, ScreenCaptureRequestCode); }
2. 处理授权结果并启动捕获
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); if (requestCode == ScreenCaptureRequestCode && resultCode == Result.Ok) { var projectionManager = (MediaProjectionManager)Android.App.Application.Context .GetSystemService(Context.MediaProjectionService); _mediaProjection = projectionManager.GetMediaProjection((int)resultCode, data); StartScreenCapture(); } } private void StartScreenCapture() { var displayMetrics = new DisplayMetrics(); Platform.CurrentActivity.WindowManager.DefaultDisplay.GetRealMetrics(displayMetrics); int screenWidth = displayMetrics.WidthPixels; int screenHeight = displayMetrics.HeightPixels; int screenDensity = displayMetrics.DensityDpi; // 创建ImageReader用于接收屏幕帧 var imageReader = ImageReader.NewInstance(screenWidth, screenHeight, ImageFormatType.Rgba8888, 2); _mediaProjection.CreateVirtualDisplay( "FullScreenCapture", screenWidth, screenHeight, screenDensity, DisplayFlags.Public, imageReader.Surface, null, null); // 设置帧可用监听 imageReader.SetOnImageAvailableListener(new ScreenCaptureImageListener(this), null); } // 自定义帧处理监听器 private class ScreenCaptureImageListener : Java.Lang.Object, ImageReader.IOnImageAvailableListener { private readonly MainPage _owner; public ScreenCaptureImageListener(MainPage owner) => _owner = owner; public void OnImageAvailable(ImageReader reader) { using var capturedImage = reader.AcquireNextImage(); if (capturedImage == null) return; // 将Image转换为Bitmap var planes = capturedImage.Planes; var buffer = planes[0].Buffer; int pixelStride = planes[0].PixelStride; int rowStride = planes[0].RowStride; int rowPadding = rowStride - pixelStride * capturedImage.Width; var bitmap = Bitmap.CreateBitmap( capturedImage.Width + rowPadding / pixelStride, capturedImage.Height, Bitmap.Config.Argb8888); bitmap.CopyPixelsFromBuffer(buffer); // 保存图片到本地 var savePath = Android.OS.Environment.GetExternalStoragePublicDirectory( Android.OS.Environment.DirectoryPictures).AbsolutePath; var saveFile = new Java.IO.File(savePath, "FullScreenCapture.png"); using var fileStream = new FileStream(saveFile.AbsolutePath, FileMode.Create); bitmap.Compress(Bitmap.CompressFormat.Png, 100, fileStream); bitmap.Recycle(); // 停止捕获 _owner._mediaProjection.Stop(); } }
注意事项:
- 在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" /> - Android 10及以上版本需额外申请
MANAGE_EXTERNAL_STORAGE权限
iOS平台
受iOS系统安全限制,仅能捕获当前应用在所有屏幕上的内容,无法捕获其他应用界面。可通过UIScreen API获取所有屏幕并捕获:
using UIKit; using Foundation; using Photos; public async Task CaptureAllAppScreens() { foreach (var screen in UIScreen.Screens) { var screenBounds = screen.Bounds; UIGraphics.BeginImageContextWithOptions(screenBounds.Size, false, screen.Scale); var graphicsContext = UIGraphics.GetCurrentContext(); // 捕获屏幕层级内容 screen.CaptureHierarchyWithOptions(graphicsContext, screenBounds, UIScreenCaptureOptions.IncludingWindows); var capturedImage = UIGraphics.GetImageFromCurrentImageContext(); UIGraphics.EndImageContext(); // 保存图片到本地 var imageData = capturedImage.AsPNG(); var docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var saveFilePath = Path.Combine(docPath, $"Screen_{screen.DeviceName}_Capture.png"); File.WriteAllBytes(saveFilePath, imageData); // 保存到相册(需先申请权限) var authStatus = await PHPhotoLibrary.RequestAuthorizationAsync(); if (authStatus == PHAuthorizationStatus.Authorized) { PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { PHAssetCreationRequest.CreateAssetFromImage(imageData); }, (success, error) => { if (!success) Console.WriteLine(error?.LocalizedDescription); }); } } }
注意事项:
- 需在Info.plist中添加
NSPhotoLibraryAddUsageDescription权限描述 - iOS系统限制,无法捕获非当前应用的屏幕内容
内容的提问来源于stack exchange,提问作者kayalvizhi s
相关产品推荐
相关产品推荐

