1. 背景
最近在一个项目中使用 CefSharp 加载H5页面, 其中一些业务逻辑需要调用 Js 函数, 同时 Js 也会调用一些 native 函数:
这里我们使用官方的demo代码进行添加修改, 修改后的代码在此: DevWiki/CefSharp.MinimalExample - CefSharp.MinimalExample - DevWiki Gitea
2. Js调用 Native 函数
根据官方的说明, General Usage · cefsharp/CefSharp Wiki, 分为两步:
- 设置 启用 Js
- 注册一个 Class 给Js调用
//设置 启用 Js
Browser.BrowserSettings.Javascript = CefState.Enabled;
Browser.JavascriptObjectRepository.Settings.LegacyBindingEnabled = true;
//注册一个 Class 给Js调用
Browser.JavascriptObjectRepository.Register("script", new Script(), false, BindingOptions.DefaultBinder);
public class Script
{
public string GetWindowName()
{
return "MainWindow";
}
public void PrintLog(string log)
{
Console.WriteLine($"H5 log:{log}");
}
}
为了方便测试, 给 Browser 设置一下响应 F12 打开 DevTool:
Browser.WpfKeyboardHandler = new WebBrowserWpfKeyboardHandler(Browser);
public class WebBrowserWpfKeyboardHandler : WpfImeKeyboardHandler
{
public WebBrowserWpfKeyboardHandler(ChromiumWebBrowser owner) : base(owner)
{
}
public override void HandleKeyPress(KeyEventArgs e)
{
base.HandleKeyPress(e);
if (e.Key == Key.F12)
{
owner.ShowDevTools();
}
}
}
运行后 , 按 F12, 打开控制台输入: script.
看看提示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kwCxn2xc-1670731074318)(api/images/iGKYxVbEAHsw/202212102324686.png)]
可以看到 我们注册的函数, 这样Js就可以调用 native函数了.
还有一种方式是动态注册, 如下:
Browser.JavascriptObjectRepository.ResolveObject += JavascriptObjectRepositoryOnResolveObject;
private void JavascriptObjectRepositoryOnResolveObject(object sender, JavascriptBindingEventArgs e)
{
var repo = e.ObjectRepository;
if (e.ObjectName == "script")
{
repo.Register("script", new Script(), isAsync: true, options: BindingOptions.DefaultBinder);
}
}
3. WPF调用Js函数
一般的网页都有有 alert()
这个函数, 就是弹出一个对话窗口, 按 F12 打开 devtool 切换到控制台, 输入函数然后回车, 结果如下图:
也可以传入一个参数, 显示提示消息: alert("test")
:
那 如何在 项目中调用呢? 根据官方的文档: CefSharp中文帮助文档 · cefsharp/CefSharp Wiki
Browser.MainFrame.ExecuteJavaScriptAsync("alert()");
// 或者
Browser.ExecuteScriptAsync("alert()");
如果需要传入参数, 则可以直接使用字符串插值:
Browser.MainFrame.ExecuteJavaScriptAsync($"alert({message})");
// 或者
Browser.ExecuteScriptAsync($"alert({message})");
或者使用传入参数的方法:
object[] args = new object[2];
args[0] = JsArgs1Tb.Text;
args[1] = JsArgs2Tb.Text;
Browser.ExecuteScriptAsync("alert()", args);
如果你安装上述的代码调用带参数的Js 函数, 实际上无法按照你预想的执行!
如果你安装上述的代码调用带参数的Js 函数, 实际上无法按照你预想的执行!
如果你安装上述的代码调用带参数的Js 函数, 实际上无法按照你预想的执行!
重要的事情说三遍!
为何会出现上述问题呢? 这里需要看下 带参数的函数具体做了什么?
public static void ExecuteScriptAsync(
this IBrowser browser,
string methodName,
params object[] args)
{
string javascriptMethodWithArgs = WebBrowserExtensions.GetScriptForJavascriptMethodWithArgs(methodName, args);
browser.ExecuteScriptAsync(javascriptMethodWithArgs);
}
在这段代码中, 会先把 函数名称 和 函数参数进行拼接:
WebBrowserExtensions.GetScriptForJavascriptMethodWithArgs(methodName, args);
这里测试下 alert
函数与参数的拼接:
拼接后的结果会自动带上 ()
, 去除括号后再次测试:
弹窗如下:
在提示出现了我们的填写内容.
3. 总结
使用 Js 调用 native 函数:
- WebBrowser 设置启用 Js 功能
- 注册一个 class 给 Js 调用
使用 native 调用 js 函数:
- 如果是无参函数, 函数名需要带上: ()
- 如果是有参数函数, 要么调用时拼接好为完整的函数+参数, 要么调用时使用
WebBrowserExtensions.GetScriptForJavascriptMethodWithArgs
并且函数只写名称不带括号.
以上代码在: DevWiki/CefSharp.MinimalExample - CefSharp.MinimalExample - DevWiki Gitea