Search Unity

[Solved]: Calling a jslib function from javascript code.

Discussion in 'Web' started by MicroEyes, Sep 21, 2018.

  1. MicroEyes

    MicroEyes

    Joined:
    Jul 3, 2012
    Posts:
    309
    Hi,
    I am working on a WebGL project in Unity 2018.2.7f1. I have defined a function Internal_TestMe() in jslib which i am calling from C#, and its working.

    Now i need to call the same function Internal_TestMe() from my javascript code and i don't know how to call. I am stuck here.
    I already looked into Interacting_with_code page on emscripten github page.

    Here's my simple jslib code:
    Code (JavaScript):
    1. var MyTestJsLib = {
    2.     Internal_TestMe : function() {
    3.         console.log("This is temp log from jslib");
    4.     }
    5. }
    6. mergeInto(LibraryManager.library, MyTestJsLib);
     
    Novack likes this.
  2. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    you should be able to do it using the object returned by instantiate():
    Code (csharp):
    1. gameInstance.Module.asmLibraryArg._Internal_TestMe();
     
  3. MicroEyes

    MicroEyes

    Joined:
    Jul 3, 2012
    Posts:
    309
  4. Rafael_CS

    Rafael_CS

    Joined:
    Sep 16, 2013
    Posts:
    162
    Wow, thank you @Marco-Trivellato

    Saved my life

    PS: You must set the function in C# too if you want to make JS visible in 'asmLibraryArg'. Unity will only make the function of JSLib visible if C# contains the link to this function as external. Otherwise this function will be stripped from the project and will not be acessible in 'asmLibraryArg'

    [DllImport("__Internal")]
    private static extern void Internal_TestMe();
     
    Last edited: Oct 17, 2018
    Novack likes this.
  5. MicroEyes

    MicroEyes

    Joined:
    Jul 3, 2012
    Posts:
    309
  6. bravo075

    bravo075

    Joined:
    Dec 7, 2012
    Posts:
    32
    @Marco-Trivellato Hello, I'm using 2017.4, made the build but I still cannot call the function. Is there an extra step in order to generate the asmLibraryArg?
     
  7. qq98360_unity

    qq98360_unity

    Joined:
    Jun 21, 2020
    Posts:
    5
    good with 2020.1
     
    Novack likes this.
  8. Novack

    Novack

    Joined:
    Oct 28, 2009
    Posts:
    844
    Damn this was hard to find! Should be on the docs :)

    Also there should be a better way to avoid stripping/hiding. In our case we need some functions from JSLib exposed to javascript, but not to C#; yet we are forced to import the functions in C#, for them to be available in javascript (thanks @Rafael_CS).

    @Marco-Trivellato the route seems pretty hideous, and tbh, I wasted a few hours finding how to do a very simple thing! Is this purpossedly discouraged? I'd like to understand if we are doing something against the conceptual framework.
     
  9. De-Panther

    De-Panther

    Joined:
    Dec 27, 2009
    Posts:
    589
    You can use ".jspre" file and declare your JS methods there.

    This line, for example, declares "Module.WebXR.OnStartAR(views_count, left_rect, right_rect)"
    https://github.com/De-Panther/unity...kages/webxr/Runtime/Plugins/WebGL/webxr.jspre
     
  10. Novack

    Novack

    Joined:
    Oct 28, 2009
    Posts:
    844
    Thanks for the answer @De-Panther

    Im a bit lost regarding what would I be achieving with that though :)

    On this case, we have javascript from the web site, sending commands to the unity build, but not using SendMessage. Instead, in C# we import and use some functions that define callbacks in js code, which in time, when invoked ping back to C# code.

    Pretty much in a similar fashion than the old websockets example.

    That is the reason we need the code from jslib accessible from the js global context, and at the same time, despite some of those functions not used from C#, they are pinging back to C# through previously defined callbacks.

    Code in jspre can interact with C#, same as jslib?
     
    Last edited: Jan 6, 2021
  11. De-Panther

    De-Panther

    Joined:
    Dec 27, 2009
    Posts:
    589
    A jslib file, is there to let C# call JS functions. It creates function headers that the C# code can call.
    It adds those functions to the scope of the project framework(e.g. BUILD_NAME.wasm.framework.unityweb file) after renaming them and merging them to the relevant library (you can overwrite existing functions with it, like in this sample https://support.unity.com/hc/en-us/...w-can-I-make-the-canvas-transparent-on-WebGL- where the glClear function is overwritten).
    As part of the "mergeInto" process, the functions are being renamed. So you can still access them from JS, but it's a roundabout way. (Module.asmLibraryArg._Internal_FUNCTION_NAME)

    The jspre file, is there to add JS functionality in general to the scope of the project framework.
    Both codes go into the framework file, as such, you can call the Module and buffer objects from both.

    You can call a function that exist in a jspre file, from a function in the jslib file. So if you have a repeated code in jslib, you can create in jspre a function the wraps it and call that function from the jslib file.

    a function in jslib file doesn't have a special way to call to a function in the binary file (wasm / C# / etc...).
    In both cases you would need to call "Module.SendMessage", "Module.ccall" or "Module.cwrap". https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html

    To call C# functions from JS,
    You can call "Module.SendMessage", but depends on your usages, you might want something with better performance (SendMessage get strings and searching the hierarchy for GameObjects with the name, and then use reflection to find the method name, etc...)

    If you don't want to use SendMessage,
    You can see in the code I linked in the previous comment, how OnStartAR calls Module.cwrap("on_start_ar")
    https://github.com/De-Panther/unity...s/webxr/Runtime/Plugins/WebGL/webxr.jspre#L32
    And on_start_ar is located in a C file that got a reference for a C# method.
    on_start_ar in "webxr.c"
    https://github.com/De-Panther/unity...kages/webxr/Runtime/Plugins/WebGL/webxr.c#L29
    DllImport set_webxr_events in "WebXRSubsystem.cs" to call it with reference to C# methods
    https://github.com/De-Panther/unity...webxr/Runtime/XRPlugin/WebXRSubsystem.cs#L157

    Do pay attention the JS ECMAScript that used in those files is ES5, so keywords like "let" won't work and will raise a build error.
     
  12. Marks4

    Marks4

    Joined:
    Feb 25, 2018
    Posts:
    550
    In Unity 2020 the path is Module.asmLibraryArg._FUNCTION_NAME. Just an underscore before the function's name, no "Internal".

    I wonder about 2021 and 2019. Anyone knows?

    @brendanduncan_u3d
     
    Last edited: Oct 31, 2021
    goldv72 likes this.
  13. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    2022 also missing this `asmLibraryArg` variable
     
    nithinsb and yukunlinykl like this.
  14. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    As far as I can investigate from webgl file that was built from unity 2022.1.11f. the asmLibraryArg are there but not being set to Module object anymore. Instead it was set to `info` variable which I don't know where it was contain

    Also I wish it should expose some other variable so I could access along with function. Such as `activeWebcams` object

    upload_2022-8-15_20-21-39.png
     

    Attached Files:

  15. Marks4

    Marks4

    Joined:
    Feb 25, 2018
    Posts:
    550
    Last edited: Dec 6, 2022
  16. unity_03shiju123

    unity_03shiju123

    Joined:
    Apr 3, 2020
    Posts:
    3
    @Thaina I'm new to webgl can you please give some details on how to access it
     
  17. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168

    There is playbackengine folder in editor folder contain library of each platform. WebGL platform contains many js code that was being used in unity build
     
  18. Merckenator

    Merckenator

    Joined:
    Nov 19, 2020
    Posts:
    1
    @Marks4 In order to do this now, you have to have a .jspre file to go along with the jslib.

    In the .jspre file you need to add an object to the "Module" object so JS can access it via gameInstance.Module.YourObjectName.SomeFunction(). Then you need to add your wrapper functions for each function you want available in JS.

    example jslib file:
    Code (JavaScript):
    1. var CoolJsPlugin= {
    2.  
    3.   $CoolContainer: {
    4.       data: "data",
    5.   },
    6.  
    7.   CoolFunction: function() {
    8.     console.log("Cool");
    9.   },
    10.  
    11. };
    12.  
    13. autoAddDeps(CoolJsPlugin, '$CoolContainer');
    14. mergeInto(LibraryManager.library, CoolJsPlugin);
    example jspre file:
    The object created in Module doesn't have to have same name.
    Code (JavaScript):
    1. Module['CoolJsPlugin'] = Module['CoolJsPlugin'] || {};
    2.  
    3. Module['CoolJsPlugin'].RunCoolFunction = function () {
    4.     _CoolFunction();
    5. }
    6.  
     
    Marks4 likes this.
  19. usernameHed

    usernameHed

    Joined:
    Apr 5, 2016
    Posts:
    93
    Question: how to name the .jslib and where to put it ?
    Question: how to name the .jspre and where to put it ?

    Thanks!
     
  20. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    You can just create anyfile.jspre/anyfile.jslib in your IDE, I use vscode and it just new file there

    If I remember correctly you need to put those files in Plugins/WebGL