Screenshot in einer Xamarin.Forms App machen
Lesedauer: 2 Minuten

Manchmal benötigt man einen Screenshot vom aktuellen Screen einer App. Derzeit gibt es keine Lösung, welche auf allen Plattformen zur Verfügung steht. Daher möchte ich euch in diesem Beitrag zeigen, wie wir mit Hilfe des DepdencyServices von Xamarin eine Lösung schaffen, welche es uns ermöglicht den gesamten Screen unkompliziert als Byte-Array abzuspeichern.

Wir beginnen mit einer ganz normalen Xamarin.Forms Vorlage und legen im portablen Teil des Projekts ein Interface mit dem Namen IScreenshotService an. Dieses Interface bietet eine Methode, nämlich CaptureScreen, welche ein Byte-Array zurückgibt.

public interface IScreenshotService
{
    byte[] CaptureScreen();
}

Nun kümmern wir uns um die Implementierung sowohl für Android als auch iOS. Zunächst installieren wir das NuGet-Paket Plugin.CurrentActivity im Android-Projekt und initialisieren dieses, wie es in der Beschreibung dargestellt wird. Anschließend legen wir im Android-Projekt eine neue Klasse mit dem Namen ScreenshotService an, welche das Interface IScreenshotService implementiert. Innerhalb der CaptureScreen-Methode holen wir uns die aktuelle View und zeichnen dann die View auf ein Canvas, welche wir dann als Byte-Array codieren.

public class ScreenshotService : IScreenshotService
{
    public byte[] CaptureScreen()
    {
        var view = CrossCurrentActivity.Current.Activity.Window.DecorView.RootView;

        using (var screenshot = Bitmap.CreateBitmap(view.Width, 
            view.Height, Bitmap.Config.Argb8888))
        {
            var canvas = new Canvas(screenshot);
            view.Draw(canvas);

            using (var stream = new MemoryStream())
            {
                screenshot.Compress(Bitmap.CompressFormat.Jpeg, 100, stream);
                return stream.ToArray();
            }
        }
    }
}

Wichtig ist die folgende Zeile, welche außerhalb der Namespace-Deklaration hinzugefügt werden muss, so dass wir später Zugriff auf die Implementierung von unserem portablen Code haben. Dabei stammt Dependency aus dem Xamarin.Forms-Namespace.

[assembly: Dependency(typeof(ScreenshotService))]

Für die Umsetzung unter iOS ist kein zusätzlichen Package notwendig. Das bedeutet, dass wir hier direkt im iOS-Projekt eine neue Klasse mit dem Namen ScreenshotService erstellen, welche das Interface IScreenshotService implementiert. Der Aufbau der CaptureScreen-Methode ist analog zu Android.

public class ScreenshotService : IScreenshotService
{
    public byte[] CaptureScreen()
    {
        var view = UIScreen.MainScreen;
        var capture = view.Capture();
        
        using (var data = capture.AsJPEG())
        {
            var bytes = new byte[data.Length];
            Marshal.Copy(data.Bytes, bytes, 0, Convert.ToInt32(data.Length));
            return bytes;
        }
    }
}

Auch hier müssen wir die Dependency-Anweisung außerhalb der Namespace-Deklaration angeben.

Damit sind wir mit der Umsetzung bereits fertig und wir können uns ans Testen der Funktionalität machen. Dazu habe ich einen einfachen Screen gestaltet, welcher einen Button beinhaltet, der einen Screenshot erstellt. Dafür nutzen wir den folgenden Aufruf:

// get screenshotservice
var screenshotService = DependencyService.Get<IScreenshotService>();

// take screenshot
var imageBytes = screenshotService.CaptureScreen();

Anschließend können wir mit dem Byte-Array weiterarbeiten und uns zum Beispiel in einem Image-Control ausgeben lassen:

// show image
Image.Source = ImageSource.FromStream(() => 
    new MemoryStream(imageBytes));

Hier nun das fertige Ergebnis unter Android. Im linken Bild sehen wir den „normalen“ Zustand bevor der Screenshot aufgenommen wurde. Im rechten Bild wurde der Screenshot aufgenommen und auf dem Screen angezeigt.

Und hier entsprechend die beiden Screenshots von der iOS-Version.

In diesem Beitrag habe ich gezeigt, wie man mit wenig Aufwand einen Screenshot des aktuellen Screens erstellen und verarbeiten kann. Den Beispielcode findet ihr natürlich wieder auf GitHub.

SignalR: Echtzeitkommunikation zwischen Backend und Frontend Deutschlands Kennzeichen: Meine erste iOS-App Xamarin.Forms Controls: RepeaterView mit alternativen Zeilenfarbe