-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to inject custom javascript to new windows requested by window.open? #2491
Comments
Maybe it's worth revising the doc, as it currently says:
Which would imply that the setting for |
@psmulovics, sorry for confusion. We have further |
Not related to the documentation, rather to make it more foolproof - could it give a warning in debug if you set it at the wrong time? |
Most interesting information, this enabled me to remove an ugly workaround where our integration actually had to reload ininitially loaded content for window.open to make all hooks and injected scripts work. |
Hi @vbryh-msft, private async void CoreWebView2_NewWindowRequested(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NewWindowRequestedEventArgs e)
{
try
{
var deferral = e.GetDeferral();
Window window = new Window();
var newWebView = new WebView2();
window.Content = newWebView;
window.Show();
await newWebView.EnsureCoreWebView2Async();
e.NewWindow = newWebView.CoreWebView2;
await newWebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("alert('hello')");
e.Handled = true;
deferral.Complete();
}
catch (Exception ex)
{
}
} and this is the code which triggers the new window request: <button onclick="window.open('https://www.google.com')">click me</button> With this event handler most of the time the popup window is just blank (i.e.: not even google.com is displayed), but sometimes - mostly when I put a breakpoint at Also if I put a Am I doing something wrong or there's a synchronization issue in WV2? |
tagging @liminzhu for tracking |
For our Win32 integration I avoid extensive processing in the event handler. Instead I get the deferral and use PostMessage to create window and integrate with new WebView2 instance from the message pump. |
Hi @pontusn, Hi @vbryh-msft, |
Use the deferral and avoid lengthly processing in the event handler. |
Hi @ztanczos - I was able to repro the issue in .Net, but was unable to quickly solve it - created a bug for somebody to have more time to look into it. |
@ztanczos - I have tried your sample one more time - do you need to have |
@vbryh-msft - I don't need Consider this sample HTML: <html>
<head>
<title>test</title>
<script type="text/javascript">
var openedWindow;
console.log(window['TESTDATA'])
function openWindow() {
openedWindow = window.open('https://www.google.com')
console.log('window opened')
console.log(openedWindow['TESTDATA'])
}
</script>
</head>
<body>
<h1>hello world</h1>
<button onclick="openWindow()">click me</button>
</body>
</html> And in .NET I'm trying to inject the following JS: public async Task InitializeAsync()
{
await webView.EnsureCoreWebView2Async();
webView.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
await webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window['TESTDATA'] = 'this works'");
} private async void CoreWebView2_NewWindowRequested(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NewWindowRequestedEventArgs e)
{
try
{
_deferral = e.GetDeferral();
Window window = new Window();
var newWebView = new WebView2();
window.Content = newWebView;
window.Show();
await newWebView.EnsureCoreWebView2Async();
e.NewWindow = newWebView.CoreWebView2;
await newWebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window['TESTDATA'] = 'this doesn't work'");
e.Handled = true;
_deferral.Complete();
}
catch (Exception ex)
{
Debug.Fail(ex.ToString());
}
} When I click on the button Not sure if this makes sense, let me know if you have further questions. |
@ztanczos There are could be two issues with your example:
|
@vbryh-msft thanks, I didn't notice the apostrophe.. 🤦 |
What exactly is the purpose of calling |
Hi @ztanczos - you should use This is how you would use deferral particularly in new window requested(c++ code) Is injecting JS script works in new window as expected? |
What I observe when using the Deferral in the NewWindowRequested event handler is that once I set Injecting JS works although not as expected. What we're trying to achieve is to inject custom Javascript into the new window before the window object is returned to the caller. The reason for this is that we provide a large set of custom functionalities for hosted web applications via JS bindings which should be available to child windows as well. With the current behavior there's a timing issue: JS bindings will be available at some point but we have no control over when exactly, so code which relies on JS objects being available in child windows as soon as the window object is ready would break. |
Hi @ztanczos, I have tried some tests based on public async Task InitializeAsync()
{
await webView.EnsureCoreWebView2Async();
webView.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
//await webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window['TESTDATA'] = 'this works'");
}
private async void CoreWebView2_NewWindowRequested(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NewWindowRequestedEventArgs e)
{
var _deferral = e.GetDeferral();
Window window = new Window();
var newWebView = new WebView2();
window.Content = newWebView;
window.Show();
await newWebView.EnsureCoreWebView2Async();
e.NewWindow = newWebView.CoreWebView2;
await newWebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window['TESTDATA'] = 'this does work'; alert('hello')");
await newWebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("function square(x) { return x * x; }");
e.Handled = true;
_deferral.Complete();
} You will get the |
Hi @plantree1995 , |
Same for me. |
Hi @ztanczos @psmulovics, I followed this project, and all source code is posted below: namespace WPFSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
webView.NavigationStarting += EnsureHttps;
InitializeAsync();
}
async void InitializeAsync()
{
await webView.EnsureCoreWebView2Async(null);
webView.CoreWebView2.WebMessageReceived += UpdateAddressBar;
webView.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
await webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.chrome.webview.postMessage(window.document.URL);");
await webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.chrome.webview.addEventListener(\'message\', event => alert(event.data));");
}
void UpdateAddressBar(object sender, CoreWebView2WebMessageReceivedEventArgs args)
{
String uri = args.TryGetWebMessageAsString();
addressBar.Text = uri;
webView.CoreWebView2.PostWebMessageAsString(uri);
}
private async void CoreWebView2_NewWindowRequested(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NewWindowRequestedEventArgs e)
{
var _deferral = e.GetDeferral();
Window window = new Window();
var newWebView = new WebView2();
window.Content = newWebView;
window.Show();
await newWebView.EnsureCoreWebView2Async();
e.NewWindow = newWebView.CoreWebView2;
await newWebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window['TESTDATA'] = 'this does work'; alert('hello')");
await newWebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("function square(x) { return x * x; }");
e.Handled = true;
_deferral.Complete();
}
void EnsureHttps(object sender, CoreWebView2NavigationStartingEventArgs args)
{
String uri = args.Uri;
if (!uri.StartsWith("https://"))
{
webView.CoreWebView2.ExecuteScriptAsync($"alert('{uri} is not safe, try an https link')");
args.Cancel = true;
}
}
private void ButtonGo_Click(object sender, RoutedEventArgs e)
{
if (webView != null && webView.CoreWebView2 != null)
{
webView.CoreWebView2.Navigate(addressBar.Text);
}
}
}
} Compile and run it in debug mode, open any links in new window, I would get the |
Hi @plantree1995,
When I open this HTML with the sample code from WPF_GettingStarted I see the main page rendered correctly but when I click on the |
Hi @ztanczos, I tried this way. private async void CoreWebView2_NewWindowRequested(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NewWindowRequestedEventArgs e)
{
try
{
var _deferral = e.GetDeferral();
Window window = new Window();
var newWebView = new WebView2();
window.Content = newWebView;
window.Show();
await newWebView.EnsureCoreWebView2Async();
e.NewWindow = newWebView.CoreWebView2;
await newWebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("function square(x) { return x * x; }; function cube(x) { return x * x * x; }");
e.Handled = true;
_deferral.Complete();
}
catch (Exception )
{
}
} and the html just like this: <html>
<head>
<title>test</title>
<script type="text/javascript">
var openedWindow;
console.log(window['TESTDATA'])
function openWindow() {
openedWindow = window.open('http://bing.com', 'hello')
}
</script>
</head>
<body>
<h1>hello world</h1>
<button onclick="openWindow()">click me</button>
</body>
</html> When you click on the button to open a new window, you could use |
Hi @plantree1995, Our use-case: we're hosting web applications in our container which provides rich functionality for these web applications via JS + interop objects. This functionality is required in windows opened by these web applications too without timing issues. In the past we could achieve the same with CEF + CefSharp by using V8Extensions but now we're struggling with WebView2. |
Hi @ztanczos, |
Hi @gkerenyi, Thanks for your professional reply! According to your description, the result should be as expected. According to the MDN, using To help better understand your need, could you provide the scenario where you need to inject scripts to all opened window? |
Hi @plantree,
We are building a generic browser where we inject a custom script to each page for various purposes (e.g. analyzing content, showing overlays on some elements, etc.). Script injection should work in all pages regardless of the way they were opened, otherwise the script's functionalities would depend on whether the page was opened directly or in a new tab/window.
With all due respect, this sounds like an assumption. I don't understand why script injection would not be allowed with |
Hi @gkerenyi, Thanks for your professional and patient analysis! As for your concern, it might be a problem, and I'll keep track of this and try to fix if it is possible. Any progress will be synchronized with you in time. If you have any other questions, please feel free to let me know. |
Hi @gkerenyi, After some investigations, I have found an easy way to make it work. If you're available, please have a try. Do a navigate at the end of handling private async void CoreWebView2_NewWindowRequested(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NewWindowRequestedEventArgs e)
{
var deferral = e.GetDeferral();
Window window = new Window();
var newWebView = new WebView2();
window.Content = newWebView;
window.Show();
await newWebView.EnsureCoreWebView2Async();
await newWebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("alert('hello')");
newWebView.CoreWebView2.NavigationStarting += (s, ev) =>
{
Debug.WriteLine("-------------New WebView2 NavigationStarting: " + ev.Uri);
};
e.NewWindow = newWebView.CoreWebView2;
e.Handled = true;
deferral.Complete();
// Will work in `noopener` mode
newWebView.CoreWebView2.Navigate(e.Uri);
} I will still keep focus on this and try to find an easier and more elegant way. Any feedbacks will be welcome. Thanks! |
Hi @plantree, Thank you for your suggestion, but unfortunately it is not satisfactory, because it doesn't work with POST requests (the POST data is lost after re-navigating). In fact, this kind of re-navigation is the current workaround we are using to mitigate the original timing problem of script injection in the stable version of WebView2, and it is a major issue for us that POST requests in new windows are failing with this workaround. To give you background, many sites (e.g., banking sites) open new windows using POST navigation. We need script injection to work in such a situation and we need the navigation to get the POST data through. To summarize:
Thank you for your continued focus on this problem! |
Hi @gkerenyi, Thanks for your patience and meticulous analysis! If you're available, could you provide a simple test demo, which has a complete coverage of the scenes you need. That might be very helpful while we are investigating this issue :) . |
Hi @plantree, I forked a demo project previously used in this thread and simplified it to demonstrate the relevant test cases: Please see the README file for details on the actual and expected behaviors. |
Hi @gkerenyi, Thanks for your well-prepared demo project! I'll check that and any progress will be synchronized to you ASAP. |
@plantree , what's the status of this? Is there an ETA for a fix? |
Hi @MarkIngramUK, Thanks for you attention! We have already prepared a fix solution, which is under review internally. I will try to get back with the ETA a few days later. Thanks for your patience. |
Hi @MarkIngramUK, Apologies for my delayed response. I needed to ensure that I was up-to-date with the latest developments. The fix patch has been included in the most recent Canary release, such as version cc. @novac42 |
Hi @psmulovics and @ztanczos, Thanks for your interest. Fortunately, this alteration takes place during runtime, eliminating the need for a NuGet update. Simply utilize the latest Canary version and verify its effects. Your feedbacks will be greatly appreciated. Thanks! |
Hi @plantree, Thanks for the notification about the fix. I have tested the solution and so far it is looking good. |
Hi @gkerenyi, Thank you for sharing your feedback! Feel free to reach out whenever you have questions. Have a nice day. |
I've tried latest Canary 118.* and there are still something strange happening related to first navigation via window.open. When we actually get correct script injection the mechanism behind WebMessage fails, breaking both our custom integrations and general support for COM. |
Hi @pontusn, Thanks for your feedback! To help better understand your issue, could you provide a simple demo for reproduction? Thanks. |
Hi @plantree & @victorhuangwq, We found a timing problem similar to script injection, but this time with web resource request handling, and it can be reproduced both with the The essence of the issue is the following:
I created a small repro app, please find it here with additional information in the readme: https://github.com/gkerenyi/CdpVsNewWindow Either it should be possible to set up both types of event handlers before setting Since the |
We have seen same problem. Our workaround is to detect failed initial navigation and retry. |
@yildirimcagri-msft looks like there's regression on something that was previously addressed - could you take a look? |
@pontusn As discussed before in relation to script injection, re-navigation is not an option, because it loses POST data. |
Agree, but for our usage retry works. |
@nishitha-burman as discussed, I've created a new issue (#4181) as the discussion in this bug report has deviated from the original issue (script injection). |
Apparently this original issue was fixed back in runtime versions 114+. Closing as completed. |
Hi,
I'm trying to ensure that custom JavaScript is always injected to new windows which are requested by e.g.: window.open. For this I'm subscribing to NewWindowRequested event handler the following way:
What I'm experiencing is that the new window pops up fine but the custom script is never executed.
How can I ensure that custom JavaScript is always executed when a new window is requested by window.open before the window object is returned to the JavaScript caller?
Thank you,
Zoltan
AB#43367417
The text was updated successfully, but these errors were encountered: