提问人:user3678429 提问时间:9/9/2023 最后编辑:user3678429 更新时间:9/9/2023 访问量:66
iOS WKWebView:PostMessage/EvaluateJavascript 中断文件输入
iOS WKWebView: PostMessage/EvaluateJavascript breaks file input
问:
我正在开发一个 Xamarin 移动应用程序,其中 iOS 版本使用 WKWebView 作为其 UI。我们的用户输入处理工作原理是在 Web 视图中的应用和框架之间传递 JSON 序列化消息。为了将消息从应用发送到帧,我们使用 EvaluateJavascript 来执行帧中的侦听器可以响应的函数。为了将消息从框架发送到应用程序,我们在框架中设置了一个消息端口,并使用 postMessage API——以这种方式发送的消息由 WKWebView 的 didReceiveScriptMessage 处理程序接收。
这是错误。我们应用程序的一个页面包含一个文件输入元素,即:
<input type="file"/>
这应该会打开一个文件选取器菜单或对话框,供用户从其设备中选择文件。我们发现,在大多数情况下(桌面 Safari/Chrome、移动 Safari/Chrome 和 Android 版本的 Xamarin 应用)可按预期工作,但在 iOS 应用中则不然。似乎发生的事情是,在 iOS 应用程序中,文件输入一直有效,直到我们从 webview 中启动消息循环。之后,任何文件输入元素都将停止响应点击。刷新或导航到另一个页面也无法解决问题 - 此时您似乎必须重置应用程序。
以下是简短的片段。
设置消息端口 (C#):
// add a script message handler when initializing the webview
var config = new WKWebViewConfiguration();
config.UserContentController.AddScriptMessageHandler(new HybridScriptMessageHandler(logger), "AppMessageChannel");
var wkWebView = new WKWebView(UIScreen.MainScreen.Bounds, config);
public void EvaluateJavascript(string script)
{
MainThread.BeginInvokeOnMainThread(() =>
{
Exception handlerEx = null;
base.EvaluateJavaScript(script, (res, err) =>
{
if (err != null)
{
handlerEx = new Exception(err.Domain);
}
});
});
}
// evaluate javascript to configure the message port within the webview frame
var script = @"
(function () {
const loadedHandler = function () {
const event = new CustomEvent('MessagePortReady', { detail: window.webkit.messageHandlers['AppMessageChannel'] });
window.dispatchEvent(event);
};
loadedHandler();
window.addEventListener('DOMContentLoaded', loadedHandler, { once: true });
})();";
EvaluateJavascript(script);
在框架中,添加使用消息端口 (js) 的侦听器和函数:
window.addEventListener("MessagePortReady", function (e) {
// set designated message port
MESSAGE_PORT = e.detail;
window.addEventListener("WebViewMessage", function (e) {
const message = JSON.parse(e.data);
// handle the message
});
});
function postMessageToApp(message) {
const messageJson = JSON.stringify(message);
MESSAGE_PORT.postMessage(messageJson);
}
当从框架中调用函数时,它会在应用中接收,如下所示 (C#):postMessageToApp
public override void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
Task.Run(() =>
{
// dispatch an event to the pertinent UI handler
OnMessage?.Invoke(this, new MessageEventArgs((NSString)msg.Body));
});
}
处理完消息后(这可能涉及从设备存储中检索数据、发出 HTTP 请求等),我们再次将响应发布回帧 (C#):EvaluateJavascript
public void PostMessageToUI(string data)
{
// assume that data is some JSON-serialized response object
var script = $@"
(function () {
const msgEvent = new MessageEvent('WebViewMessage', { 'data': '{data}' });
window.dispatchEvent(msgEvent);
})();";
EvaluateJavascript(script);
}
我试图使这些摘录简明扼要,但如果需要,可以详细说明。谢谢!
答: 暂无答案
评论