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.
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.
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! ?
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.
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?
I have an error with this line. What am I missing?
private UIFromPage fromPage;
It’s in the repository with a link at the end of the post 🙂
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 🙂
I guess I need to link all of these pages together… ?
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?
You would need to use WebGLInput. The user focuses on the Unity you should change WebGLInput.captureAllKeyboardInput to true.
Very usefull, Thanks!
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 »
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
Im also having this error, did you ever find a solution? Thanks.
canada rx
Beneficial posts. Thanks!
And what about receiving messages from Unity?!?!