- Home /
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 > https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html
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?"
Answer by Bunny83 · Jun 14, 2020 at 09:08 PM
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).
Note that the same limitations hold for native plugins for other targetplatforms which are not compatible with the editor platform. So you can not "test" native iOS or Android plugins inside the Unity editor. Likewise when you develop on a windows machine with a windows Unity editor but your target platform is linux and you include native linux libraries you can't test them inside the editor.
Answer by JeffreyBennett · Jun 15, 2020 at 05:01 PM
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?
Ok, updating to 2019.4.0f1 did NOT fix the issue.
The build to WebGL gave the same result. For what it may be worth, the Scripting window with the progress bar that shows while it is building gets about 90% done, and it says Compile Web Assembly $$anonymous$$odule, then it goes poof and the errors show up in the console.
I get the same four red octagons as before.
Update:
Removing the C# script from Assets > Scripts, as well as the jslib from Assets > Plugins allows a successful build to WebGL.
Update 2 - The following worked! Huzzah!
In Assets > Plugins - A jslib file named js_test03.jslib >
// JavaScript Document mergeInto(Library$$anonymous$$anager.library, { Hello: function () { window.alert("This is a string written in a Javascript Function."); }, });
In Assets > Scripts - A C# file named js_test03.cs (probably should have named these differently, because they're potentially confusing, but whatever...) >
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Runtime.InteropServices; public class js_test03 : $$anonymous$$onoBehaviour { [DllImport("__Internal")] private static extern void Hello(); // Start is called before the first frame update void Start() { Hello(); } / // Update is called once per frame void Update() {
}
*/
}*
So basically what was wrong was two things:
I wasn't actually building the thing and testing it in Firefox from the build folder, but rather trying to test it with the play button in the Editor. Don't do that! Build it and test it in the browser.
I was assu$$anonymous$$g that the example files given in the documentation would work correctly as written. They didn't. But when I significantly reduced that stuff down to just a window alert, it at least builds and works when tested in the browser.
Your answer
Follow this Question
Related Questions
Using C# and Javascript in a project 1 Answer
Is there a way to reference a variable in another script if it's a different type of script? 2 Answers
Compilation Order Quandaries - Cross Language Game-To-Library Communication 1 Answer
Reference a JS script in a C# script? 2 Answers
Unity Scorm WebGl integration ? 0 Answers