michaeled / uisleuth

A Xamarin.Forms Inspector
MIT License
22 stars 6 forks source link
dotnet xamarin xamarin-forms

UI Sleuth

A Xamarin.Forms Inspector

Download Desktop Client · Download NuGet Package · Installation Guide · Wiki


What is UI Sleuth?

UI Sleuth is a Xamarin.Forms debugging tool. If you’ve ever made a web site, it’s similar to Microsoft’s F12 tools or Chrome Developer Tools. You can use it to efficiently track down layout issues, prototype a new design, and remotely control a device.

Screenshots


Attached to Android tablet.


Inspecting a ViewModel

Overview

UI Sleuth is composed of two components: the desktop client and the design server. The desktop client communicates with your mobile app via WebSockets and a simple JSON protocol. The .NET library that you reference in your Xamarin.Forms application is a WebSocket server and workflow engine.

The workflow engine is implemented using a BlockingCollection that dispatches incoming messages to listeners, called Reactions. Once a request has been received, its serialized into the appropriate .NET type. Each request type is associated with a reaction. When the corresponding reaction is determined, its instantiated and invoked. The implementing reaction can read the incoming message, perform some behavior, and return a response to the client.

As an example, the following code is used to respond to a screenshot request from the desktop client.

1) Define the request and response types (server code)

namespace UISleuth.Messages
{
    internal class ScreenShotRequest : Request {}

    internal class ScreenShotResponse : Response
    {
        public byte[] Capture { get; set; }
    }
}

2) Create a custom reaction class (server code)

    internal class ScreenShotReaction : Reaction
    {
        protected override void OnExecute(UIMessageContext ctx)
        {
            var request = ctx.Get<ScreenShotRequest>();
            if (request == null) return;

            var screenshot = InspectorContainer.Current.Resolve<IScreenShot>();
            byte[] capture = null;

            Thread.Invoke(() =>
            {
                capture = screenshot.Capture();
            });

            ctx.SetResponse<ScreenShotResponse>(r =>
            {
                r.Capture = capture;
                r.Suggest<GetVisualTreeRequest>();
            });
        }
    }

3) Associate the request type to the reaction (server code)

Reaction.Register<ScreenShotRequest, ScreenShotReaction>();

4) Request a screenshot via WebSocket (client code)

websocket.send("{action: 'ScreenShotRequest'}");

The action property above matches the C# type name of ScreenShotRequest. Additional parameters can be present in this message. Utility methods exist to easily deserialize these messages into the appropriate .NET objects.

* Request types are optional. You may chose to send an OkResponse

Why WebSockets?

When this project started, Xamarin.Forms was a UI toolkit for iOS, Android, and Windows Phone apps only. I needed a simple, out of process way to communicate with external emulators and devices. WebSockets just made sense.

Now that we're seeing Xamarin.Forms target WPF, GTK#, and macOS a whole new level of possibilites for UI Sleuth are emerging. Let's imagine your new client wants to communicate with your Xamarin.Forms app via IPC instead of WebSockets for out-of-process communication. That's great; start by extending the InspectorSocket type and register it with the DI service.

Documentation

This project site is a work in progress. You can find all the documentation on the project's Wiki.

@mykldavis