Unity3D WebGL 如何将JS中web3异步调用结果返回至Unity端
问题根因
你的推测完全正确,web3.eth.call属于异步网络请求操作,回调函数会在网络响应返回后才执行,而js函数的return语句会在发起请求后立即执行,此时balance还是初始的默认值,所以Unity侧同步接收的返回值永远不会是实际查询结果。
解决方案
Unity WebGL提供了JS侧主动调用C#方法的能力,你可以在异步请求拿到结果后,通过SendMessage接口主动把结果回传给Unity侧的指定方法,不需要通过同步返回值的方式获取结果。
1. 修改.jslib侧代码
web3 = new Web3(new Web3.providers.HttpProvider("xxxx")); GetBalance: function (str) { var addr = (Pointer_stringify(str)); var contractAddr = ('xxxx'); var tknAddress = (addr).substring(2); var contractData = ('0x70a08231000000000000000000000000' + tknAddress); web3.eth.call({ to: contractAddr, data: contractData }, function(err, result) { if (result) { var tokens = web3.utils.toBN(result).toString(); var balance = web3.utils.fromWei(tokens, 'kwei'); console.log('Tokens Owned: ' + balance); // 回传结果给Unity,三个参数分别是:接收消息的GameObject名、回调方法名、传递的参数 Module.SendMessage('WalletManager', 'OnBalanceFetched', balance); } else { console.log(err); // 可选:错误信息也可以回传给Unity做提示 Module.SendMessage('WalletManager', 'OnBalanceFetchError', err.message); } }); }
说明:
SendMessage的第一个参数必须和Unity场景中挂载回调脚本的GameObject名称完全一致,大小写敏感。如果Module.SendMessage调用失败,可以在WebGL构建产物的index.html中,createUnityInstance的成功回调里添加window.unityInstance = unityInstance;,之后用window.unityInstance.SendMessage调用即可。
2. 修改Unity侧C#代码
using UnityEngine; using UnityEngine.UI; using System.Runtime.InteropServices; public class WalletManager : MonoBehaviour // 这个脚本要挂载在名为WalletManager的GameObject上 { public Text ButtonText; [DllImport("__Internal")] private static extern void GetBalance(string s); // 改为无返回值,异步接收结果 public void Start() { string s = WalletAddress(); GetBalance(s); // 发起异步查询,不需要同步等返回 } // JS侧会主动调用这个方法接收余额结果 public void OnBalanceFetched(string balance) { // 直接更新UI或存储变量即可,调用自动在Unity主线程执行,不需要额外处理线程安全 ButtonText.text = balance; } // 可选:接收错误信息的回调 public void OnBalanceFetchError(string errorMsg) { Debug.LogError($"查询余额失败:{errorMsg}"); ButtonText.text = "查询失败"; } // 你的原有获取钱包地址的方法 private string WalletAddress() { // 原有逻辑 return ""; } }
注意事项
- 如果需要传递复杂结构体,可以先在JS侧序列化为JSON字符串,C#侧收到后再反序列化即可
- 回调方法必须是挂载在目标GameObject上的public实例方法,不能是静态方法、私有方法
- 不要在异步回调里调用JS的内存释放相关方法处理传入的字符串参数,Unity会自动管理这部分内存
内容的提问来源于stack exchange,提问作者kyntyn
相关产品推荐
相关产品推荐

