Delphi FMX Android:如何即时获取evaluateJavascript调用结果?
在FMX/Android中同步获取WebView JS执行结果或HTML元素值
核心问题说明
evaluateJavascript是异步API,Android WebView的设计逻辑就是让回调在WebView专属线程触发,不会阻塞主线程。FMX/Android环境下无法使用VCL的Application.ProcessMessages,因为两者的消息循环机制完全不同。
可行解决方案
1. 用信号量实现同步等待
借助跨平台信号量TEvent,可以暂时阻塞主线程直到回调触发,以此实现"即时获取"的效果:
var JSResult: string; WaitEvent: TEvent; begin WaitEvent := TEvent.Create(nil, True, False, ''); try // 替换成你需要执行的JS代码,比如获取指定元素值 LWebView.evaluateJavascript(StringToJString('document.getElementById("yourElementId").value'), procedure(Value: JSValue) begin JSResult := Value.ToString; WaitEvent.SetEvent; // 触发信号量,结束等待 end); // 设置超时(建议5秒内),避免主线程长时间阻塞导致ANR if WaitEvent.WaitFor(5000) = wrSignaled then ShowMessage('获取结果:' + JSResult) else ShowMessage('获取超时'); finally WaitEvent.Free; end; end;
2. 直接操作DOM(若FMX封装支持)
部分FMX版本的WebView封装了直接操作DOM的方法,可跳过JS执行直接获取元素值:
var ElementValue: string; begin // 假设WebView提供GetElementById方法 ElementValue := LWebView.GetElementById('yourElementId').GetAttribute('value'); ShowMessage(ElementValue); end;
如果FMX没有封装这类方法,只能通过JS间接获取,再用上面的信号量等待方式拿到结果。
3. 提前注入JS缓存逻辑
在WebView页面加载完成后,提前注入一段JS代码缓存需要的元素值,后续调用时直接读取缓存:
// 页面加载完成时注入缓存逻辑 LWebView.evaluateJavascript(StringToJString( 'window.elementCache = {};' + 'function cacheElementVal(id) {' + ' window.elementCache[id] = document.getElementById(id).value;' + '}' ), nil); // 后续获取值时 var JSResult: string; WaitEvent: TEvent; begin WaitEvent := TEvent.Create(nil, True, False, ''); try LWebView.evaluateJavascript(StringToJString('cacheElementVal("yourElementId"); window.elementCache["yourElementId"]'), procedure(Value: JSValue) begin JSResult := Value.ToString; WaitEvent.SetEvent; end); WaitEvent.WaitFor(3000); ShowMessage(JSResult); finally WaitEvent.Free; end; end;
关键注意事项
- 主线程阻塞必须设置超时,超时时间建议控制在5秒内,否则Android系统会判定应用无响应(ANR)。
- 所有JS操作必须在WebView页面加载完成后执行,否则会出现找不到元素的错误。
- 复杂DOM操作建议放在JS中完成,只返回最终结果,减少跨线程交互的开销。
内容的提问来源于stack exchange,提问作者sn00py
相关产品推荐
相关产品推荐

