[DllImport("__Internal")]
private static extern string InternalGetUsername();
void Start () {
Debug.Log("Username: " + InternalGetUsername());
Outputs:
[From InternalGetUsername()] InternalGetUsername: Username, 21830760
[From Start()] Username:
DGordon:
I can successfully call InternalGetUsername() from Start(). When I trace out the username inside of the function, it logs into the web browser correct. However, when I try to return that value back into Unity it comes back as an empty string. Any idea why?
I’ve tried it using _malloc, as well as gameInstance.Module._malloc.
PS: The docs need to be updated to use stringToUTF8 and not the deprecated writeStringToMemory … as well as whatever is going wrong here, if its not my own fault.
https://docs.unity3d.com/2017.2/Documentation/Manual/webgl-interactingwithbrowserscripting.html
var MyPlugin = {
InternalGetUsername: function()
var username = GetUsername();
var buffer = gameInstance.Module._malloc(lengthBytesUTF8(username) + 1);
stringToUTF8(username, buffer);
console.log("InternalGetUsername: " + username + ", buffer: " + buffer);
return buffer;
mergeInto(LibraryManager.library, MyPlugin);
[DllImport("__Internal")]
private static extern string InternalGetUsername();
void Start () {
Debug.Log("Username: " + InternalGetUsername());
Outputs:
[From InternalGetUsername()] InternalGetUsername: Username, 21830760
[From Start()] Username:
you are right, we should updated the docs.
I think the problem might be that stringToUTF8 is supposed to have a third parameter for the buffer size.
perhaps it should be:
var MyPlugin = {
InternalGetUsername: function()
var username = GetUsername();
var bufferSize = lengthBytesUTF8(username) + 1;
var buffer = gameInstance.Module._malloc(bufferSize);
stringToUTF8(username, buffer, bufferSize);
console.log("InternalGetUsername: " + username + ", buffer: " + buffer);
return buffer;
mergeInto(LibraryManager.library, MyPlugin);
Do we have any certain answer to this question yet? The “perhaps it should be” solution won’t build for me.
It would be great if the docs could be updated to show how to do this properly so that we don’t have to go searching around for it. Currently the docs say this:
“To return a string value you need to call _malloc to allocate some memory and the stringToUTF8 helper function to write a JavaScript string to it. If the string is a return value, then the il2cpp
runtime will take care of freeing the memory for you.”
Hi, how to get text from this code? var buffer returns numbers, but not string type
function onDataGet(data)
console.log(data);
var bufferSize = gameInstance.Module.lengthBytesUTF8(data) + 1;
var buffer = gameInstance.Module._malloc(bufferSize);
gameInstance.Module.stringToUTF8(data, buffer, bufferSize);
gameInstance.SendMessage('DataUpdateTest','SetPageData',buffer.toString());
If you use SendMessage(), you can pass the string as is.
https://docs.unity3d.com/ja/2020.2/Manual/webgl-interactingwithbrowserscripting.html
my string is a huge JSON and it wont allow me to transfer it, throws error that game needs more memory
EvgenyTorkin:
my string is a huge JSON and it wont allow me to transfer it, throws error that game needs more memory
In that case, you’ll have to consider another method.
For example, after saving to a file on the JS side, load the file on the C# side.
// *.jslib
mergeInto(LibraryManager.library, {
$persistentDataPath: {},
$onLoadCallback: 0,
$txtDecoder: {},
LoadLargeJsonLib_Init__deps: ['$persistentDataPath', '$onLoadCallback', '$txtDecoder'],
LoadLargeJsonLib_Init: function(basePath, onLoadCB) {
txtDecoder = txtDecoder || new TextDecoder();
persistentDataPath = basePath;
onLoadCallback = onLoadCB;
window.loadLargeJson = function (jsonString) {
var filePath = persistentDataPath + '/largeJson.json';
var data = txtDecoder.decode(jsonString);
FS.writeFile(filePath, data);
dynCall_v(loadFileCB);
using System;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;
public class LargeJsonLib : MonoBehaviour
[DllImport("__Internal")]
private static extern void LoadLargeJsonLib_Init(string persistentDataPath, Action OnloadCB);
[AOT.MonoPInvokeCallback(typeof(Action))]
private static void OnLoadCallback()
var filePath = Path.Combine(Application.persistentDataPath, "largeJson.json");
var data = File.ReadAllText(filePath);
File.Delete(filePath);
void Start()
LoadLargeJsonLib_Init(Application.persistentDataPath, OnLoadCallback);
In that case, you’ll have to consider another method.
For example, after saving to a file on the JS side, load the file on the C# side.
// *.jslib
mergeInto(LibraryManager.library, {
$persistentDataPath: '',
$onLoadCallback: 0,
$txtEncoder: new TextEncoder(),
FileDandDLib_Init__deps: ['$persistentDataPath', '$onLoadCallback', '$txtEcoder'],
LoadLargeJsonLib_Init(basePath, onLoadCB) {
persistentDataPath = basePath;
onLoadCallback = onLoadCB;
window.loadLargeJson = function (jsonString) {
var filePath = persistentDataPath + '/largeJson.json';
var data = txtEncoder.encode(jsonString);
FS.writeFile(filePath, data);
dynCall_vi(loadFileCB);
using System;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;
public class LargeJsonLib : MonoBehaviour
[DllImport("__Internal")]
private static extern void LoadLargeJsonLib_Init(string persistentDataPath, Action OnloadCB);
[AOT.MonoPInvokeCallback(typeof(Action))]
private void OnLoadCallback()
var filePath = Path.Combine(Application.persistentDataPath, "largeJson.json");
var data = File.ReadAllText(filePath);
File.Delete(filePath);
void Start()
LoadLargeJsonLib_Init(Application.persistentDataPath, OnLoadCallback);
as i understand here we create file in JS lib and then load it in C#
this is not exactly what I need
function httpGetAsync(theUrl, callback)
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
callback(xmlHttp.responseText);
xmlHttp.open("GET", theUrl, true); // true for asynchronous
xmlHttp.send(null);
function onDataGet(data)
console.log(data);
var bufferSize = gameInstance.Module.lengthBytesUTF8(data) + 1;
var buffer = gameInstance.Module._malloc(bufferSize);
gameInstance.Module.stringToUTF8(data, buffer, bufferSize)
gameInstance.SendMessage('DataUpdateTest','SetPageData',buffer);
i have this 2 functions for download data from web and then i need to transfer it to gameclient
this code is in index.html page, and i need to do this there
as i understand here we create file in JS lib and then load it in C#
this is not exactly what I need
function httpGetAsync(theUrl, callback)
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
callback(xmlHttp.responseText);
xmlHttp.open("GET", theUrl, true); // true for asynchronous
xmlHttp.send(null);
function onDataGet(data)
console.log(data);
var bufferSize = gameInstance.Module.lengthBytesUTF8(data) + 1;
var buffer = gameInstance.Module._malloc(bufferSize);
gameInstance.Module.stringToUTF8(data, buffer, bufferSize)
gameInstance.SendMessage('DataUpdateTest','SetPageData',buffer);
i have this 2 functions for download data from web and then i need to transfer it to gameclient
this code is in index.html page, and i need to do this there
I have a question,
Why should I create and pass a pointer when I can pass a string to SendMessage?
I think that _malloc() uses heap memory for virtual environment created by emscripten. In that case, only the maximum size of HEAP8.byteLength (approximately 30MB) can be used.
I have a question,
Why should I create and pass a pointer when I can pass a string to SendMessage?
I think that _malloc() uses heap memory for virtual environment created by emscripten. In that case, only the maximum size of HEAP8.byteLength (approximately 30MB) can be used.
if i try pass JSON downloaded string via SendMessage i have an error
An error occurred running the Unity content on this page. See your browser JavaScript console for more info. The error was:
RuntimeError: index out of bounds
MemoryManager::Allocate(unsigned long, unsigned long, MemLabelId const&, AllocateOptions, char const*, int)@http://localhost:61041/Build/Build.wasm:wasm-function[17028]:0x854338
operator new(unsigned long)@http://localhost:61041/Build/Build.wasm:wasm-function[17033]:0x854e62
std::__2::allocator<char16_t>::allocate(unsigned long, void const*)@http://localhost:61041/Build/Build.wasm:wasm-function[59263]:0xf8a1ab
std::__2::basic_string<char16_t, std::__2::char_traits<char16_t>, std::__2::allocator<char16_t> >::reserve(unsigned long)@http://localhost:61041/Build/Build.wasm:wasm-function[17140]:0x85b14a
dynCall_vii@http://localhost:61041/Build/Build.wasm:wasm-function[59502]:0xf98782
unityFramework/createExportWrapper/<@http://localhost:61041/Build/Build.framework.js:1034:20
invoke_vii@http://localhost:61041/Build/Build.framework.js:14232:14
il2cpp::utils::StringUtils::Utf8ToUtf16(char const*, unsigned long)@http://localhost:61041/Build/Build.wasm:wasm-function[17129]:0x85a706
il2cpp::vm::String::NewLen(char const*, unsigned int)@http://localhost:61041/Build/Build.wasm:wasm-function[1757]:0xb5c5a
il2cpp::vm::String::New(char const*)@http://localhost:61041/Build/Build.wasm:wasm-function[1756]:0xb5c42
SendMessageString@http://localhost:61041/Build/Build.wasm:wasm-function[13626]:0x796741
unityFramework/createExportWrapper/<@http://localhost:61041/Build/Build.framework.js:1034:20
ccall@http://localhost:61041/Build/Build.framework.js:643:17
SendMessage@http://localhost:61041/Build/Build.framework.js:166:151
SendMessage@http://localhost:61041/Build/Build.loader.js:178:35
onDataGet@http://localhost:61041/:119:22
httpGetAsync/xmlHttp.onreadystatechange@http://localhost:61041/:107:21
EventHandlerNonNull*httpGetAsync@http://localhost:61041/:105:9
script.onload/</fullscreenButton.onclick@http://localhost:61041/:132:25
if i try pass JSON downloaded string via SendMessage i have an error
An error occurred running the Unity content on this page. See your browser JavaScript console for more info. The error was:
RuntimeError: index out of bounds
MemoryManager::Allocate(unsigned long, unsigned long, MemLabelId const&, AllocateOptions, char const*, int)@http://localhost:61041/Build/Build.wasm:wasm-function[17028]:0x854338
operator new(unsigned long)@http://localhost:61041/Build/Build.wasm:wasm-function[17033]:0x854e62
std::__2::allocator<char16_t>::allocate(unsigned long, void const*)@http://localhost:61041/Build/Build.wasm:wasm-function[59263]:0xf8a1ab
std::__2::basic_string<char16_t, std::__2::char_traits<char16_t>, std::__2::allocator<char16_t> >::reserve(unsigned long)@http://localhost:61041/Build/Build.wasm:wasm-function[17140]:0x85b14a
dynCall_vii@http://localhost:61041/Build/Build.wasm:wasm-function[59502]:0xf98782
unityFramework/createExportWrapper/<@http://localhost:61041/Build/Build.framework.js:1034:20
invoke_vii@http://localhost:61041/Build/Build.framework.js:14232:14
il2cpp::utils::StringUtils::Utf8ToUtf16(char const*, unsigned long)@http://localhost:61041/Build/Build.wasm:wasm-function[17129]:0x85a706
il2cpp::vm::String::NewLen(char const*, unsigned int)@http://localhost:61041/Build/Build.wasm:wasm-function[1757]:0xb5c5a
il2cpp::vm::String::New(char const*)@http://localhost:61041/Build/Build.wasm:wasm-function[1756]:0xb5c42
SendMessageString@http://localhost:61041/Build/Build.wasm:wasm-function[13626]:0x796741
unityFramework/createExportWrapper/<@http://localhost:61041/Build/Build.framework.js:1034:20
ccall@http://localhost:61041/Build/Build.framework.js:643:17
SendMessage@http://localhost:61041/Build/Build.framework.js:166:151
SendMessage@http://localhost:61041/Build/Build.loader.js:178:35
onDataGet@http://localhost:61041/:119:22
httpGetAsync/xmlHttp.onreadystatechange@http://localhost:61041/:107:21
EventHandlerNonNull*httpGetAsync@http://localhost:61041/:105:9
script.onload/</fullscreenButton.onclick@http://localhost:61041/:132:25
How big of a JSON are you actually trying to read?
If you get that error with SendMessage(), I think it’s impossible with SendMessage() because the heap size is exceeded.
Therefore, I think that there is only a way to save to a file → read a file.
By the way, WebGL uses a virtual file system built on IndexedDB, so it is not saved physically in a file, but saved in IndexDB, and the file is read from IndexedDB.