unityInstance is not defined

Hello,
I need to call a c# function from jslib file (JS code). I used unityInstance.SendMessage for this, but no runtime I recieve an error: Uncaught ReferenceError: unityInstance is not defined.
This error is strange because I used the same code in another project and that’s where it works. In the current project, in the same Unity version, an error is received. I tried very hard and could not solve the problem.
Here is the c# code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;

public class GetJSData : MonoBehaviour
{
    [DllImport("__Internal")]
    public static extern void callGame(int gameNum);

    [DllImport("__Internal")]
    public static extern void checkGameLocalStorage();
  

    [DllImport("__Internal")]
    public static extern void resetVaribiles();
  
  
    // Start is called before the first frame update
    void Start()
    {
        checkGameLocalStorage();
      
    }
    public void fromJS(int val){
        Debug.Log("fromJS!!!!!!");

        GameManager.ifGameOut = false;

        if(val==1){
        GameProcess.ifCorrect_fromGame=true;
        } else {
        GameProcess.ifCorrect_fromGame=false;
      }
Debug.Log(GameProcess.ifCorrect_fromGame);

    }
}

And the JS code:

mergeInto(LibraryManager.library, {
  
    resetVaribiles: function(){
        localStorage.removeItem("hagim81Game_Words");
        localStorage.removeItem("hagim81ToGame");
        localStorage.removeItem("hagim81Return");
        localStorage.removeItem("wordSearchSumWords");
        //localStorage.removeItem("");
        localStorage.setItem('refrashIframes',1);

},

    callGame: function (gameNum) {
        localStorage.setItem("hagim81ToGame",gameNum);
 
},

checkGameLocalStorage: function(){
setInterval(function(){
checkGameLocalStorage_1();
},1000)
  

function checkGameLocalStorage_1(){
    if(localStorage.getItem("hagim81Game_Words")!= null && localStorage.getItem("hagim81Game_Words")>0){
        console.log("checkGameLocalStorage")
        localStorage.removeItem("hagim81Game_Words");
        localStorage.removeItem("hagim81ToGame");
        localStorage.setItem("hagim81Return",1);

        unityInstance.SendMessage('GetJSData' , 'fromJS' , 1);
    }
}
},


})

The error is obtained from the code line:
unityInstance.SendMessage(‘GetJSData’ , ‘fromJS’ , 1);
Note: The C# script is on GameObject called “GetJSData”.
The JSLIB file is in PLUGINS folder in assets.

I have .SendMessage working within a .jslib file in 2020.2 - I explicitly assign the reference to **window.**unityInstance in the WebGL template:

createUnityInstance(canvas, config, (progress) => {
  progressBarFull.style.width = 100 * progress + "%";
}).then((unityInstance) => {

  window.unityInstance = unityInstance; // <-- this

…and in my .jslib:

window.unityInstance.SendMessage(...
10 Likes

Thank you. But I am using the 2019.3 version. And like I said in another project it works for me (in the same Unity version).
I will still try what you have suggested.

Honestly, I did not understand where you put the first code … if you can please explain to me. Thanks!

In the WebGL template’s index.html, i.e.:

[unity installation path]\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\WebGLTemplates\Default\index.html

If the template html doesn’t contain “unityInstance” let me know, I’ll install 2019 quickly and take a closer look.

1 Like

Maybe the code in 2019 is different. This is what the HTML looks like:

<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | %UNITY_WEB_NAME%</title>
    <link rel="shortcut icon" href="TemplateData/favicon.ico">
    <link rel="stylesheet" href="TemplateData/style.css">
    <script src="TemplateData/UnityProgress.js"></script>
    <script src="%UNITY_WEBGL_LOADER_URL%"></script>
    <script>
      var unityInstance = UnityLoader.instantiate("unityContainer", "%UNITY_WEBGL_BUILD_URL%", {onProgress: UnityProgress});
    </script>
  </head>
  <body>
    <div class="webgl-content">
      <div id="unityContainer" style="width: %UNITY_WIDTH%px; height: %UNITY_HEIGHT%px"></div>
      <div class="footer">
        <div class="webgl-logo"></div>
        <div class="fullscreen" onclick="unityInstance.SetFullscreen(1)"></div>
        <div class="title">%UNITY_WEB_NAME%</div>
      </div>
    </div>
  </body>
</html>

So looking at the 2019 WebGL template it has this:

var unityInstance = UnityLoader.instantiate("unityContainer", "%UNITY_WEBGL_BUILD_URL%", {onProgress: UnityProgress});

Try changing that to:

var unityInstance = window.unityInstance = UnityLoader.instantiate("unityContainer", "%UNITY_WEBGL_BUILD_URL%", {onProgress: UnityProgress});

Edit: And then using window.unityInstance.SendMessage instead of unityInstance.SendMessage

1 Like
        window.unityInstance.SendMessage('GetJSData' , 'fromJS' , 1);

But:
Uncaught TypeError: Cannot read property ‘SendMessage’ of undefined

You are calling this only during builds, correct (not in the editor)? There is no unityInstance unless the application is being loaded in the web browser, which you probably already know… I can’t think of any other reason aside from scope (which is covered by using window.unityInstance) or that the javascript on the page hasn’t instantiated your build. That doesn’t mean there isn’t another possible reason, just that we haven’t thought of it yet :smile:

1 Like

Thank you. Yes of course, only in build, not in the Editor.
But now I think maybe the problem is that I am presenting the game within Iframe of another platform (Construct 2). I.e. Iframe within Iframe (I make transitions between different games by Iframes). Maybe there’s a problem here that he can not talk to Unity properly from the iframe.
I’m trying to check it out.

I don’t know enough to say what complications that would have - maybe start with getting things to work as expected with the default WebGL template (without being inside of an iframe) and then make a simple page with just an iframe loading that. Then you have an environment set up where you can test things and experiment until you find a solution that works.

1 Like

There might be something useful at the following link where iframes are concerned, although I’m not sure it’s going to be entirely relevant - the puzzling thing is that unityInstance wouldn’t be defined within the same window that instantiated the game. Hopefully someone else with experience re Unity+iframes can help.

1 Like

Unfortunately it still does not work. The maximum I succeeded in was when I started the game outside of the internal Iframe, along with the changes that @adamgolden suggested, and then no error was received, but in practice the function did not work …
I mention it works for me on another project in the same version of Unity. There is something unexplained here.
I have tried a lot already … I am already quite discouraged … I would love if there are more ideas for a solution.

I did a test with 2019.4.8f1 today, calling SendMessage from a click on a div in a parent window into an instance of Unity running within an iframe. It’s working in my browsers on Windows (Chrome, Firefox, Edge).

In the parent page I put a button,

test

For .jslib added this function:

  EnableIFrameParentWindowTest: function(buttonId) {
    var obj = window.parent.document.getElementById(Pointer_stringify(buttonId));
    if (obj != null)
    {
        obj.style.color = "blue"; // the color css of my div is grey, so the text in it turns blue like a link when this runs 
        obj.onclick = function() {
          unityInstance.SendMessage("Javascript", "FromIFrameParentWindow", "msg from iframe parent");
        }
    }
  }

I have an object in the scene root called “Javascript” with a class “Javascript.cs” doing this:

using UnityEngine;
using UnityEngine.UI;
public class Javascript : MonoBehaviour
{
  [DllImport("__Internal")] public static extern void EnableIFrameParentWindowTest(string buttonId);
  public Text output; // I have a Text on a Canvas assigned to this
#if UNITY_WEBGL && !UNITY_EDITOR 
  void Start()
  {
    EnableIFrameParentWindowTest("btnSendTestMessage");
  }
#endif
  public void FromIFrameParentWindow(string msg)
  {
    output.text = msg;
  }
}

After Unity loads in the iframe, Start is called in the Javascript object and the div in the parent window is assigned .onclick - clicking the div changes the Text component in Unity to say “msg from iframe parent”. Note this is all the same domain and if you’re trying to access parent window that’s from a different domain it will probably fail / you would have to restructure things.

Specifying window. before unityInstance wasn’t necessary, it’s working fine without it. Also, if you wanted to add an onclick handler from within .jslib to an element in the same window/iframe, you could use var obj = document.getElementById(Pointer_stringify(buttonId)); without window.parent. before document like was done in EnableIFrameParentWindowTest.

1 Like

Thank you. I also tried a new project, and it worked.
Maybe I found out what the problem is. I see that the project build does not create a TemplateData folder. It seems to me that this is necessary for our purposes. What could be the reason why the folder was not created? Where is it set up?

Well … so that was the problem. There was a Minimal setting in the project player settings for webgl. As a result, no TemplateData folder was created for export, and the setting was probably missing.
Now it works, after a lot of time and effort …
Thank you so much @adamgolden , you are great!
problem solved.

You’re welcome - good luck with your project(s)!

For anyone else trying to figure this out I’ll answer the last question even though you’ve solved it:

Make sure in Project Settings->Player->WebGL tab->Resolution and Presentation that you have the WebGL Template selected that you want to use. The templates listed there are populated automatically based on what’s in the WebGLTemplates folder of the current Unity Editor installation:

[unity installation path]\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\WebGLTemplates\

2 Likes

Thanks polemical - this finally got some of my old code working. It looks like we can’t expect unityInstance to exist as a global variable anymore, unless we explicitly set it in the webgltemplate as you have done. I have been using it in jslib functions. Downside is the custom web template makes it all-but unusable for distributing generic custom code (e.g. through assetstore).

1 Like

Thank you so much for this discussion it helped me greatly

I ran into this problem today with the latest 2020.2.0f1 build, just wanted to make some observations for this release.

As stated you have to use the default template, minimum won’t work.

To get this working in ifames, create a variable in your main.html at the top e.g.

<script>
var GlobalUnityInstance = null;
</script>

then in the generated index.html from unity add the line to the onLoad resolution

<script>
parent.GlobalUnityInstance  = unityInstance;
</script>

The entire function would look like:

script.onload = () => {
        createUnityInstance(canvas, config, (progress) => {
          progressBarFull.style.width = 100 * progress + "%";
        }).then((unityInstance) => {
          loadingBar.style.display = "none";
           parent.GlobalUnityInstance  = unityInstance; //add this line
          fullscreenButton.onclick = () => {
            unityInstance.SetFullscreen(1)
          };
        }).catch((message) => {
          alert(message);
        });
      };

in your main.html create an iframe that references the generated index and you can use GlobalUnityInstance to send messages e.g.

GlobalUnityInstance.SendMesaage(...

Huge thanks @adamgolden , the window.unityInstance thing worked for me.

Since you clearly know more about this than me: am I right in saying that some recent Unity version introduced a change to the Default WebGL template that totally breaks the standard unityInstance.SendMessage code they have here Unity - Manual: Interaction with browser scripting ? And people have written whole libraries based on (e.g. FirebaseWebGL/Assets/FirebaseWebGL at master · rotolonico/FirebaseWebGL · GitHub)

If so, thats… wow. Bad. So many jslibs dying. Should I do a bug report?

2 Likes