Communication between Unity WebGL and a Page

After building custom Template for Unity WebGL, and creating own JS plugin for it, it’s finally time to make another step! Make communication between Unity WebGL and a page!

I would recommend reading about these two posts before continuing with this one, as we will use know-how from them!

But if you already have an understanding of how to write plugins in JS and create your own templates or how to make your own pages, feel welcome here. 🤓

Prep work 🛠

To start, we need two things – a JS plugin and a receiver (bridge) in Unity.

In the old times you could call JS functions in WebGL directly from C# using Application.ExternalCall(), but we can’t do it any longer.

Now we have to follow new rules for interacting with browser scripting.

Unity WebGL -> Page 🖼

The first step to creating communication between Unity WebGL and the page will be to create a JS plugin. It will serve the purpose of sending a message from Unity to the page.

In our case, we will have just one method in it.

using System.Runtime.InteropServices;

// Read more about creating JS plugins: https://www.patrykgalach.com/2020/04/27/unity-js-plugin/

/// <summary>
/// Class with a JS Plugin functions for WebGL.
/// </summary>
public static class WebGLPluginJS
{
    // Importing "SendMessageToPage"
    [DllImport("__Internal")]
    public static extern void SendMessageToPage(string text);
}
// Read more about creating JS plugins: https://www.patrykgalach.com/2020/04/27/unity-js-plugin/

// Creating functions for the Unity
mergeInto(LibraryManager.library, {

   // Method used to send a message to the page
   SendMessageToPage: function (text) {
      // Convert bytes to the text
      var convertedText = Pointer_stringify(text);

      // Pass message to the page
      receiveMessageFromUnity(convertedText); // This function is embeded into the page
   }
});

However, the code in the plugin will not be enough for us here. We also need to create a method on our page to receive the message and do something with it!

<!-- Place for displaying a message from Unity -->
<div class="centered">
   <h2>Message from Unity</h2>

   <p id="lblMessage">...</p>
</div>

<script>
   // Function which receives a message from Unity
   function receiveMessageFromUnity(txt) {
      // Get element to assign the message
      const lblMessage = document.getElementById("lblMessage");

      // Assign received from Unity message
      lblMessage.innerText = txt;
   }
</script>

Great! I think this will do for us here. 🤓

Page -> Unity WebGL 🕳

The second part is a little bit harder to do.

We will have to create a panel or form on our page to enter the message which will be passed to Unity.

<!-- Message form for sending stuff to Unity -->
<div class="message-form centered">
   <h2>Message for Unity</h2>

   <input type="text" name="txtMessage" id="txtMessage" placeholder="Enter message..." />
   <button onclick="sendMessageToUnity()">Send</button>
</div>

With form ready, now we need a function to go with it.

<script>
   // Function which sends the message to Unity
   function sendMessageToUnity() {
      // Get the input field
      const txtMessage = document.getElementById("txtMessage");
      // Get the message
      const message = txtMessage.value;
      // Clear the input field
      txtMessage.value = "";

      // Send message to the Unity scene
      // Params: "Target object in the scene", "Function name", "Parameters"
      unityInstance.SendMessage("[Bridge]", "ReceiveMessageFromPage", message);
   }
</script>

Awesome! But this won’t work yet. We are still missing the receiver of that message!

We have to create one in the scene, I’ll call it “[Bridge]” like in code.

Create a receiver in the scene

Of course, we will need a script for it with the method we’ve provided on the page.

using UnityEngine;

/// <summary>
/// Bridge used to communicate with a page
/// </summary>
public class BridgeScript : MonoBehaviour
{
    // Reference to the UI panel to display received message.
    [SerializeField]
    private UIFromPage fromPage;

    /// <summary>
    /// Receives the message from a page.
    /// </summary>
    /// <param name="message">Message.</param>
    public void ReceiveMessageFromPage(string message)
    {
        // Display the message
        fromPage.DisplayMessage(message);
    }

   ...
}

And with that, we basically have everything done!

Issue: Unity captures all keyboard input 🔩

By default, Unity captures all keyboard input, and you can’t write anything onto input fields on your page.

To fix that issue, you have to change the value of WebGLInput.captureAllKeyboardInput to false.

Just like here:

using UnityEngine;

/// <summary>
/// Disable capturing whole input on the page
/// Read more: https://docs.unity3d.com/ScriptReference/WebGLInput-captureAllKeyboardInput.html
/// </summary>
public class DisableWebGLInputCapture : MonoBehaviour
{
    void Start()
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        WebGLInput.captureAllKeyboardInput = false;
#endif
    }
}

Oh, and don’t forget to attach this component somewhere in the scene. 😜

Result 🏆

Now, let’s slap some UI on that so we can test what we’ve created.

Communication between Unity WebGL and the Page

And what do you think about it? Let me know in the comment section below! 🤩

If you know someone that might need this, share it with him! I would really appreciate that! 🥰

And if you are interested in getting emails when I release a new post, sign up for the newsletter!

The whole project is available at my public repository. 🔗

Hope to see you next time! 🤓

4.9 7 votes
Article Rating
Subscribe
Notify of
guest
11 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Jon Nielsen
Jon Nielsen
1 year ago

Nice overview, thanks>
Note that disabling WebGLInput.captureAllKeyboardInput
Makes text input in Unity impossible, you will need to toggle keyboardInput to allow page or unity text entry.

Anton
Anton
1 year ago

Hi, Patryk, thank you for a nice post! I suceeded with all but that I can’t type anything in the form on the webpage. I noticed that this happens as soon as Unity content is inserted with standard block <div id=”unityContainer” style=”width: 960px; height: 600px”></div> – otherwise the textfield works well. Do you have an idea of why this can occur? 

Will
Will
1 year ago

I have an error with this line. What am I missing?
private UIFromPage fromPage;

VIRAL AP
VIRAL AP
1 year ago

Hi Patryk, thanks for this whole thing. But TBH I found this very unclear and incomplete. The article makes no sense unless i have been through other two articles and codes of all 3 pages.
But the code is perfect and works fine (except for the Keyboard Input Part).

Thanks 🙂

herbert rush
herbert rush
10 months ago

I pulled down your project. I built in the one of the latest Unity versions. Built it and put it on my website for testing.

Here is the link
https://dfassistants.com/UnityV1/

Using Chrome. I cannot type on the left side- From Unity.
I can send to page – right side seems ok.

I am trying to understand this thing before I start to tinker with it. This is learning exercise.

I see a 404 for style.css in the console!

What do you think is the problem?

Raphael
Raphael
9 months ago

Very usefull, Thanks!

Daniel Doronin
Daniel Doronin
8 months ago

Wow, many thanks. This entire blog is a goldmine! I am working on a Team Fortress 2 project called Gravel Wars (a reference to TF2 comics) and this article along with a few related ones really helped me overcome some critical challenges. The project involves: Ruby on Rails for login and page delivery. Unity WebGL as a user interface to the RTS part of the game. C# Console Application as the main server with all the RTS logic and launching TF2 servers on-demand. SourcePawn (SourceMod) plugin for communication between the main server and the TF2 server events. This is my… Read more »

Last edited 8 months ago by Daniel Doronin
Sergey Kolesnik
Sergey Kolesnik
6 months ago

Thank you! very much this is a great guide!
but, unfortunately, at startup, unity throws this error:

EntryPointNotFoundException: SendMessageToPage
BridgeScript.SendMessageToPage (System.String message) (at Assets/Scripts/Bridge/BridgeScript.cs:29)
UIFromUnity.SendMessageToPage () (at Assets/Scripts/UI/UIFromUnity.cs:28)
UnityEngine.Events.InvokableCall.Invoke () (at <f38c71c86aa64e299d4cea9fb7c715e1>:0)
UnityEngine.Events.UnityEvent.Invoke () (at <f38c71c86aa64e299d4cea9fb7c715e1>:0)
UnityEngine.UI.Button.Press () (at C:/Program Files/Unity/Hub/Editor/2019.3.0f6/Editor/Data/Resources/PackageManager/BuiltInPackages/com.unity.ugui/Runtime/UI/Core/Button.cs:68)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at C:/Program Files/Unity/Hub/Editor/2019.3.0f6/Editor/Data/Resources/PackageManager/BuiltInPackages/com.unity.ugui/Runtime/UI/Core/Button.cs:110)
UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at C:/Program Files/Unity/Hub/Editor/2019.3.0f6/Editor/Data/Resources/PackageManager/BuiltInPackages/com.unity.ugui/Runtime/EventSystem/ExecuteEvents.cs:50)
UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at C:/Program Files/Unity/Hub/Editor/2019.3.0f6/Editor/Data/Resources/PackageManager/BuiltInPackages/com.unity.ugui/Runtime/EventSystem/ExecuteEvents.cs:261)
UnityEngine.EventSystems.EventSystem:Update() (at C:/Program Files/Unity/Hub/Editor/2019.3.0f6/Editor/Data/Resources/PackageManager/BuiltInPackages/com.unity.ugui/Runtime/EventSystem/EventSystem.cs:377)

I get a similar error every time I try to call webgl JavaScript from unity