Use C# Script to Call JavaScript Function/Method

I’m doing something wrong and I don’t know what, so maybe if I detail my process someone can point to my error.

I’m using information in the documentation from here > Unity - Manual: Interaction with browser scripting

Step 1
From that page I just copy and paste the entire first section of code into a JavaScript editor file, then save it as a Javascript library and name it something like js_test.jslib:

Code Sample:

mergeInto(LibraryManager.library, {

  Hello: function () {
    window.alert("Hello, world!");
  },

  HelloString: function (str) {
    window.alert(Pointer_stringify(str));
  },

  PrintFloatArray: function (array, size) {
    for(var i = 0; i < size; i++)
    console.log(HEAPF32[(array >> 2) + i]);
  },

  AddNumbers: function (x, y) {
    return x + y;
  },

  StringReturnValueFunction: function () {
    var returnStr = "bla";
    var bufferSize = lengthBytesUTF8(returnStr) + 1;
    var buffer = _malloc(bufferSize);
    stringToUTF8(returnStr, buffer, bufferSize);
    return buffer;
  },

  BindWebGLTexture: function (texture) {
    GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[texture]);
  },

});

Step 2
In my Unity project I go into my Assets folder and create a folder named Plugins. so that is Assets > Plugins.

Step 3
I put the js_test.jslib file into that Plugins folder.

Step 4
In my Unity project, under Assets > Scripts I create a new C# script and name it something like cs_js_test.cs.

Step 5
I go back to the Unity documents and copy the entire second section of code, pasting it into that C# script, so it looks like:

Code Sample:

using UnityEngine;
using System.Runtime.InteropServices;

public class NewBehaviourScript : MonoBehaviour {

    [DllImport("__Internal")]
    private static extern void Hello();

    [DllImport("__Internal")]
    private static extern void HelloString(string str);

    [DllImport("__Internal")]
    private static extern void PrintFloatArray(float[] array, int size);

    [DllImport("__Internal")]
    private static extern int AddNumbers(int x, int y);

    [DllImport("__Internal")]
    private static extern string StringReturnValueFunction();

    [DllImport("__Internal")]
    private static extern void BindWebGLTexture(int texture);

    void Start() {
        Hello();
        
        HelloString("This is a string.");
        
        float[] myArray = new float[10];
        PrintFloatArray(myArray, myArray.Length);
        
        int result = AddNumbers(5, 7);
        Debug.Log(result);
        
        Debug.Log(StringReturnValueFunction());
        
        var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false);
        BindWebGLTexture(texture.GetNativeTextureID());
    }
}

Step 6
In my Unity project, I drag that C# script and place it on the camera (because that is a game object that is active at the beginning of the game).

Step 7
I attempt to play the game (Play button in the Unity Editor).

My Result
The console shows the following error: EntryPointNotFoundException: Hello cs_js_test.cs.Start() (at Assets/Scripts/cs_js_test.cs:27)

Line 27, where the error is, is the first call to a function, the Hello() function in the JavaScript library file.

My question is this: I don’t see how the C# script is supposed to “know” that there is a JavaScript library named js_test.jslib, even if it is in the Plugins folder. In the C# script are calls to import a dynamic link library, such as at line 7 - [DllImport(“__Internal”)] , however I don’t see any way to reference my exact .jslib file, which is named js_test.jslib.

Surely that is the reason for the “I can’t find the function named "Hello()” error I’m getting, because it doesn’t know to look in that file. Shouldn’t there be something in the C# script that says “go to Assets > Plugins and open the file named js_test.jslib?

A jslib is a native javascript library. Of course that only works in a build webgl application. When you test your game inside the Unity editor you can not run native javascript code. So of course when you test inside the editor those methods do not exist and the extern linking fails.

The name of your js lib is irrelevant. The actual js lib contains code that actuall merges the content of your lib into the js lib manager so the methods are available “globally” from the virtual machine environment in which your game code runs in.

As already mentioned you can not make the javascript code to work inside the editor. However you can provide an alternative implementation when testing inside the editor (or when the target platform isn’t webgl). A common solution is what I did in my URLParameters script. The actual js lib is included in that cs script and is auto-extracted by some editor code. The actual extern definitions are here, though are placed inside pre-processor tags so they are only included in an actual webgl build. When testing inside the editor those alternative methods are used which are essentially stubs / mocks which allows testing of the usage without the actual methods being available.

Any “extern” method definition is essentially a runtime linked method. So if the actual implementation is available or not is not known at compile time. So an error is thrown when you try to call such a method and no implementation was found. When you test your example in an actual WebGL build it should just work fine. However I would always recommend to use pre-processor tags and provide stub methods for all other platforms (including in-editor-testing).

I really appreciated your reply!

I’ve cut this down to only the jslib and c# script, but the the build to WebGL is failing - This is in Unity 2019.3.0f6

I’ve opened a brand new project, which does have Standard Assets from the Unity Asset Store, and the FPSController from the Standard Assets is in the scene, replacing the default camera.

I normally get an error or two when I first bring in the Standard Assets to a new project, but those have been cleared. The game plays in the editor with no errors or warnings.

After ensuring that runs with no issues, I’ve brought in the jslib and the C# script as described above, and then tried to build in WebGL.

So basically all that is in the game now is:

  • The FPSController from the Standard Assets
  • A cube
  • A plane
  • A directional light
  • The js library is in the Assets > Plugins folder.
  • The C# script to interact with that library is in Assets > Scripts.

Building to WebGL fails and gives the following warnings and errors:

  • Warning - CS0618 - ‘Texture.GetNativeTextureID()’ is obsolete: ‘Use GetNativeTexturePtr instead.’ - This was coming from lines 39&40 of the jslib copied from the documents, so I commented those out and the warning is gone on subsequent builds.

  • Error - Failed running python -E “/Applications/Unity/2019.3.0f6/PlaybackEngines/….long path…/Assets/Temp/emcc_arguments.resp”

  • Error - Exception: Failed building WebGL Player. - UnityEditor.WebGL.ProgramUtils.StarProgramChecked (System.Diagnostics…)…long path…WebGL.extensions/ProgramUtils.cs:48

  • Error - Build completed with a result of ‘Failed’ - UnityEngine.GUIUtilityProcessEvent(Int32, IntPtr)(at /Users/builduser/…long path…IMGUI/GUIUtility/:cs:187)

  • Error - UnityEditor.BuildPlayerWindow - BuildMethodExceptions: 3 errors at UnityEditor.BuildPlayerWindow+DefaultBuildMethods…long path…:cs:191

So, with nothing in the project to speak of, the game will not build to WebGL using just the jslib from the documents section. So is this an issue with my version of Unity (an update is available, to 2019.4.f01), with something in the jslib / c# script I copied and pasted in from the Documentation, or (more likely) something I’m forgetting to do / add?

Rather than posting a question and answering it myself. This question is close enough and was found in my Google search for the answer to a problem with the provided code sample in the unity docs…

specifically looking at the 2021.3 documentation for the latest LTS as of the date of this posting.

the following 2 lines caused error in Rider.

var texture = new Texture2D(0, 0, Tex tureFormat.ARGB32, false);
BindWebGLTexture(texture.GetNativeTexturePtr());

ChatGPT gave a workable solution:

var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false);
// BindWebGLTexture(texture.GetNativeTexturePtr());
IntPtr nativeTexturePtr = texture.GetNativeTexturePtr();
int textureId = nativeTexturePtr.ToInt32();
BindWebGLTexture(textureId);

but to expand on that and follow up on what others said about it not working in the unity editor… I would think the code demo would be better for some if provided with a few extra lines like shown below where one uses defined symbols to control things. adding #if UNITY_WEBGL && !UNITY_EDITOR , #else and #endif simple but effective and good for those who may not know see in code examples like this that will only ever work on the one platform as far as currently known. Like WebGL is only platform that uses jslib AFAIK. anyway here is the updated Start() method

  void Start() {
#if UNITY_WEBGL && !UNITY_EDITOR
        Hello();
        
        HelloString("This is a string.");
        
        float[] myArray = new float[10];
        PrintFloatArray(myArray, myArray.Length);
        
        int result = AddNumbers(5, 7);
        Debug.Log(result);
        
        Debug.Log(StringReturnValueFunction());
        
        var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false);
        IntPtr nativeTexturePtr = texture.GetNativeTexturePtr();
        int textureId = nativeTexturePtr.ToInt32();
        BindWebGLTexture(textureId);
        // BindWebGLTexture(texture.GetNativeTexturePtr());
#else
        //Run what ever code you like if not WebGL including for the editor play mode.
#endif
    }