覆盖 javascript 全局变量的可靠方法

Reliable way to override javascript globals

我试图通过注入 MockDate 并将其设置为每个其他脚本 运行 之前的某个固定日期来模拟 CefSharp 浏览器上的日期。每个 window 对象,在任何帧上,在任何时间,都应该只能访问模拟日期,所以理想的是在内部重新定义 JavaScript Date 对象,但我不不认为 CefSharp 或什至 Chromium 有这个选项。我还将模拟一些其他功能,如 setTimeoutMath.rand,以防止浏览器产生任何副作用(这是一个更大项目的一部分,其目标是能够 record/replay 浏览 activity), 所以浪费 OS 的时间是解决不了的。

我考虑过使用 RegisterJsObject 因为它实际上可以覆盖现有的全局变量,但我认为没有办法传递 JavaScript 构造函数。

到目前为止我尝试过的是处理 FrameLoadStart 事件:

private static string Inject = File.ReadAllText("Inject.js");

private void ChromeBrowser_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
{
    e.Frame.ExecuteJavaScriptAsync(Inject);
}

其中 "Inject.js" 包含模拟日期代码。但我注意到,随机地,有时它会起作用,有时它不会。我猜是因为该函数是异步的,并且有时未创建 javascript 上下文,因为根据文档,您不应该在此处 运行 脚本。该文档建议改为处理 OnContextCreated,但它只针对主框架处理 运行,这不会让我在任何 iframe 上注入代码。所以我想知道我是否有其他选择。

如果您可以编辑 HTML 个入口点,那么您只需在任何其他脚本之前添加 window.Date = MockDate。例如:

<html>
<body>
<script src="mockdate.js"></script>
<script>
    window.Date = MockDate
</script>
<script src="myscript.js"></script>
</body>
</html>

所以您可以在 HTML 中调整脚本加载顺序。它可以在任何浏览器中完成。

如果您不能或不想编辑 HTML 那就麻烦多了。您可以在 CEF C++ 中使用 CefLoadHandler 或在 CefSharp 中使用它的替代方法。

更新 实际上我不确定 CefLoadHandler。可靠的方法是实现自己的 CefRenderProcessHandler But you already mentioned it. If it doesn't work then it's a bug in CefSharp or CEF C++ itself. In that case it would be better to write about it on http://magpcss.org/ceforum/

万一其他人需要这个,解决方案是通过在 CefAppUnmanagedWrapper::OnContextCreated:

的末尾添加一行来修改实际的 C++ CefSharp 代码
frame->ExecuteJavaScript(CodeToInject, "something://something", 1);

如果在 C# 端注入,这将不起作用,我相信因为这些调用是异步的,所以您注入它可能为时已晚,在页面上的脚本已经 运行 之后。