覆盖 javascript 全局变量的可靠方法
Reliable way to override javascript globals
我试图通过注入 MockDate 并将其设置为每个其他脚本 运行 之前的某个固定日期来模拟 CefSharp 浏览器上的日期。每个 window
对象,在任何帧上,在任何时间,都应该只能访问模拟日期,所以理想的是在内部重新定义 JavaScript Date
对象,但我不不认为 CefSharp 或什至 Chromium 有这个选项。我还将模拟一些其他功能,如 setTimeout
和 Math.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# 端注入,这将不起作用,我相信因为这些调用是异步的,所以您注入它可能为时已晚,在页面上的脚本已经 运行 之后。
我试图通过注入 MockDate 并将其设置为每个其他脚本 运行 之前的某个固定日期来模拟 CefSharp 浏览器上的日期。每个 window
对象,在任何帧上,在任何时间,都应该只能访问模拟日期,所以理想的是在内部重新定义 JavaScript Date
对象,但我不不认为 CefSharp 或什至 Chromium 有这个选项。我还将模拟一些其他功能,如 setTimeout
和 Math.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
:
frame->ExecuteJavaScript(CodeToInject, "something://something", 1);
如果在 C# 端注入,这将不起作用,我相信因为这些调用是异步的,所以您注入它可能为时已晚,在页面上的脚本已经 运行 之后。