Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] (WebView) - Expose C# classes in JS #9424

Open
TGSAN opened this issue Aug 14, 2022 · 5 comments
Open

[Enhancement] (WebView) - Expose C# classes in JS #9424

TGSAN opened this issue Aug 14, 2022 · 5 comments

Comments

@TGSAN
Copy link

TGSAN commented Aug 14, 2022

Description

Add AddHostObjectToScript to MAUI's WebView so that the same code can be used to implement JSBridge on any platform
The API design can be found in the Microsoft WebView2 documentation:
https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.addhostobjecttoscript

This feature is proposed to enhance the flexibility of calls between Javascript code and C# code in WebView.

It is possible to expose specific C# classes for Javascript code in WebView, so that Javascript code can call members on the classes (for notifications or transferring data). Previously using MAUI required developers to write duplicate code for each platform to implement similar functionality (a capability available in WebView implementations on various platforms), when this feature is implemented in MAUI, developers can focus solely on writing MAUI common code, lowering the barrier to use.

Public API Changes

In C#

[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class BridgeAnotherClass
{
    public string Prop { get; set; } = "Example";
}

[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class Bridge
{
    public string Func(string param)
    {
        return "Example: " + param;
    }

    public string BytesToString(byte[] bytes)
    {
        Encoding enc = new UTF8Encoding(true, true);
        return enc.GetString(bytes);
    }

    public byte[] StringToBytes(string str)
    {
        Encoding utf8 = Encoding.UTF8;
        return utf8.GetBytes(str);
    }

    public BridgeAnotherClass AnotherObject { get; set; } = new BridgeAnotherClass();

    [System.Runtime.CompilerServices.IndexerName("Items")]
    public string this[int index]
    {
        get { return m_dictionary[index]; }
        set { m_dictionary[index] = value; }
    }
    private Dictionary<int, string> m_dictionary = new Dictionary<int, string>();
}

In C# (Then add instances of those classes via AddHostObjectToScript(String, Object))

webView.AddHostObjectToScript("bridge", new Bridge());

In Javascript (C# class as a Javascript proxy object)

const bridge = window.DotNet.WebView.hostObjects.bridge;
console.log(await bridge.Func("testing..."));
// Uint8Array send to C#
const enc = new TextEncoder();
const bytes1 = enc.encode("This is a string converted to a Uint8Array");
console.log(await bridge.BytesToString(bytes1));
// C# to Javascript Unit8Array to C#
const bytes2 = await bridge.StringToBytes("This is a string converted to a Uint8Array");
console.log(await bridge.BytesToString(bytes2));

Intended Use-Case

In my project, I want to reuse some binary data processing libraries written in Javascript, and then notify and give the processed binary data to C# for processing. As another example, there are many HyperApps, that need to notify the C# side after the Javascript initialization on the web side is finished (e.g. the login is done in the WebView and then the Token is passed to the App).

@jfversluis
Copy link
Member

Thank you so much for the suggestion @TGSAN! I don't know a lot about this area, but I see a lot of COM stuff, which immediately makes me think this is very specific to Windows? So this will only work on Windows?

@ghost ghost added the legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor label Aug 15, 2022
@jfversluis jfversluis added this to the Backlog milestone Aug 15, 2022
@ghost
Copy link

ghost commented Aug 15, 2022

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@TGSAN
Copy link
Author

TGSAN commented Aug 15, 2022

Thank you so much for the suggestion @TGSAN! I don't know a lot about this area, but I see a lot of COM stuff, which immediately makes me think this is very specific to Windows? So this will only work on Windows?

No, it can be implemented on any platform. Currently only WebView2 (Windows) provides this API. but this API design can be available on any platform (e.g. iOS and Android).

The specific implementation can be achieved through the WebView of different platforms. Register a proxy (Javascript Object) to the WebView Document through JSBridge, and when Javascript calls the members of the Proxy, the corresponding method is called in C# using reflection.

@Eilon Eilon removed the legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor label May 10, 2024
@GitClickOk
Copy link

GitClickOk commented Jun 22, 2024

Thank you so much for the suggestion @TGSAN! I don't know a lot about this area, but I see a lot of COM stuff, which immediately makes me think this is very specific to Windows? So this will only work on Windows?

Both Android WebView and iOS WKWebView implement this similar functionality, but not the Windows version, making this a stopper to any advanced task in MAUI+WebView. And this functionality works in other Windows platforms like WPF or Windows Forms...

All these are community hacks:
https://learn.microsoft.com/en-us/answers/questions/1291522/using-addhostobjecttoscript-in-maui-apps
https://stackoverflow.com/questions/73217992/js-net-interact-on-maui-webview
https://stackoverflow.com/questions/72683537/corewebview2-addhostobjecttoscript-throws-system-exception
https://stackoverflow.com/questions/73610413/webview2-addhostobjecttoscript-in-uwp-crashes
microsoft/microsoft-ui-xaml#7170

But all these are far from ideal, and most of these force us to work with WinRT adapters. Just look this article:
https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/winrt-from-js?tabs=winui3%2Cwinrtcsharp
Currently, this is the "official" way to make it work. And it conveniently skips the part where we will need at least a ".Net Standard" library with the bridge object to be used by the WinRT Adapter, and then consumed in the final MAUI app (I hope it's possible). In other words, at least 2 extra projects to make it, and no warranties that will break something in the end...

By the way, I don't consider this an "[Enhancement]", but a request for a bug fix. In the end, a bug happens when the expected way does not work as intended, am I right?

EDIT: I got now that it is a "Request to add AddHostObjectToScript to Maui WebView", that currently does not have. But as I said, the only stopper is the Windows WebView (CoreWebView2), which does not correctly implement this.

Regards

@jfversluis
Copy link
Member

As of .NET 9 we will have the HybridWebView, will that help in this scenario? See #22880

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants