Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

JSLIB wait to receive variables from javascript

Discussion in 'Scripting' started by Zaskar7777, Jun 5, 2021.

  1. Zaskar7777

    Zaskar7777

    Joined:
    Oct 17, 2020
    Posts:
    36
    Hi,
    I have a JSLIB script working with Unity.

    I call it as simple as this.

    Code (CSharp):
    1. string receivedString = "";
    2. receivedString = GetValueFromJsLib();
    The jslib is getting called however the code doesn't wait for the variable receivedString to receive the value from jslib and hence I always get a blank value in receivedString. I have made sure to check if I am receiving the value from jslib through console.

    How can I wait till the variable receivedString receives the value?

    Regards
     
  2. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,571
    I can not make much sense of what you wrote ^^. When you call a nativ javascript function from C# it is executed synchonously. So the return value of your method will for sure arrive properly. However since you want to return a string you probably do it the wrong way. Keep in mind that C# is a managed language. C# Strings live on the managed heap which is "emulated" in a WebGL build. You can not simply return a javascript string to C#. There's an example in the documentation. Specifically:

    Code (CSharp):
    1. StringReturnValueFunction: function () {
    2.     var returnStr = "bla";
    3.     var bufferSize = lengthBytesUTF8(returnStr) + 1;
    4.     var buffer = _malloc(bufferSize);
    5.     stringToUTF8(returnStr, buffer, bufferSize);
    6.     return buffer;
    7.   },
    So you have to use _malloc to allocate the actual managed string object on the managed heap and copy the data using "stringToUTF8"
     
  3. Zaskar7777

    Zaskar7777

    Joined:
    Oct 17, 2020
    Posts:
    36
    Thanks for the response. And yes I have taken care of this already. This is how my jslib code looks like.

    Code (CSharp):
    1. mergeInto(LibraryManager.library, {
    2. GetLoc: function (){
    3.    navigator.geolocation.getCurrentPosition(function(pos)
    4.    {
    5.     var coors = pos.coords.latitude+", "+pos.coords.longitude;
    6.     console.log("COOOR "+coors);
    7.            var returnStr = coors;
    8.     var bufferSize = lengthBytesUTF8(returnStr) + 1;
    9.     var buffer = _malloc(bufferSize);
    10.     stringToUTF8(returnStr, buffer, bufferSize);
    11.     console.log("buffer "+buffer);
    12.     return buffer;
    13.     });
    14. },
    15. });
     
  4. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,571
    Well, that doesn't work at all ^^. The getCurrentPosition method seems to be an asynchronous call and all your code is inside the callback of that async call. Returning something from such a callback makes no sense at all ^^.

    Such an asynchronous call can not be made synchronous. So you have two options here:

    Either split the whole process into a two method process, so the first one starts the async task, you store the result in a JS variable and the second method call just reads out the last received value.

    Another option is to actually use a callback. The simplest way would be to use SendMessage, though that's somewhat messy. It should be able to actually directly call a C# delegate from your callback. I have never tested this, but it should be something like this:

    Code (CSharp):
    1.  
    2.     mergeInto(LibraryManager.library, {
    3.     GetLoc: function (callback){
    4.         navigator.geolocation.getCurrentPosition(function(pos) {
    5.             var coors = pos.coords.latitude+", "+pos.coords.longitude;
    6.             console.log("COOOR "+coors);
    7.             var returnStr = coors;
    8.             var bufferSize = lengthBytesUTF8(returnStr) + 1;
    9.             var buffer = _malloc(bufferSize);
    10.             stringToUTF8(returnStr, buffer, bufferSize);
    11.             Runtime.dynCall('vi', callback, [buffer]);
    12.         });
    13.     }
    14.     });
    15.  
    Now our GetLoc method does not return anything (well, it never did in the first place) but instead requires a callback that takes a string as argument. So the signature on the C# side should look something like this:

    Code (CSharp):
    1.  
    2.     [DllImport("__Internal")]
    3.     public static extern void GetLoc(Action<string> aCallback);
    4.  
    So calling GetLoc would still not return any string since it can't. However the asynchronous JS call should call our callback when the request has finished. Something like that:

    Code (CSharp):
    1.  
    2. void SomeMethod()
    3. {
    4.     GetLoc((location) => {
    5.         Debug.Log("Location from JS: " + location);
    6.     });
    7. }
     
    Last edited: Jun 6, 2021
  5. Zaskar7777

    Zaskar7777

    Joined:
    Oct 17, 2020
    Posts:
    36
    Thanks @Bunny83. That worked. Appreciate the help.
     
  6. MiguelAtencio

    MiguelAtencio

    Joined:
    May 7, 2019
    Posts:
    4
    Hello I tried that and get an error: IL2CPP does not support marshaling delegates that point to instance methods to native code. The method we're attempting to marshal is: TestJS+<>c::<SomeMethod>b__5_0.
    Any help is appreciated.
     
  7. martinig

    martinig

    Joined:
    Apr 12, 2022
    Posts:
    2
    Getting the same IL2CPP error mentioned above. Is there a known solution to this?
     
  8. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,788
    Bunny83 likes this.