【问题标题】:How to open a new window from a link in a webview in a chrome-packaged app如何从 chrome 打包应用程序中的 web 视图中的链接打开新窗口
【发布时间】:2013-08-25 11:49:15
【问题描述】:

为了显示来自横幅交换的广告,我正在加载一个包含链接到广告服务器的 iframe 的 web 视图。通过一些 javascript,我可以将广告链接目标设置为“_blank”,这样广告就会在单独的浏览器窗口中打开,否则它将在同一个小网页视图中打开。

但是它不起作用,我在控制台中得到了这个:

<webview>: A new window was blocked.

任何想法如何做到这一点?

【问题讨论】:

    标签: google-chrome-app


    【解决方案1】:

    问题是默认情况下,webview 不会让客人打开任意窗口。相反,它将发出一个“newwindow”事件,您可以拦截并决定如何处理它。在一个不那么可怕的形式中,这看起来像:

    chrome.app.runtime.onLaunched.addListener(function() {
      chrome.app.window.create(
        'main.html',
        { 'width': 1000, 'height': 1000 },
        function(win) {
          win.contentWindow.onload = function() {
            var webview = win.contentWindow.document.querySelector('#my_webview');
            webview.addEventListener('newwindow', function(e) {
              e.preventDefault();
              // e.targetUrl contains the target URL of the original link click
              // or window.open() call: use it to open your own window to it.
              // Something to keep in mind: window.open() called from the
              // app's event page is currently (Nov 2013) handicapped and buggy
              // (e.g. it doesn't have access to local storage, including cookie
              // store). You can try to use it here and below, but be prepare that
              // it may sometimes produce bad results.
              chrome.app.window.create(e.targetUrl, ...);
            });
          };
        }
      );
    });
    

    鉴于您所描述的条件,我认为这应该适合您。

    在更糟糕的情况下,某些网站可能会像这样打开新窗口/标签:

    function open(href) {
        var w = window.open('', '_blank');
        w.opener = null;
        w.document.write(
          '<META HTTP-EQUIV="refresh" content="0; url=' + href + '">');
        w.document.close();
    }
    

    如果这样的网站包含在 webview 中,一切都会变得更加困难:上面的 'newwindow' 处理程序中的 e.targetUrl 将包含“about:blank”,因此无需修改代码将打开一个空白窗口/选项卡。要拦截来自访客的后续重定向,应用程序还必须使用chrome.webRequest API(文档似乎仅用于扩展,但 API 已经可用于稳定通道中的打包应用程序):

    chrome.app.runtime.onLaunched.addListener(function() {
      chrome.app.window.create(
        'main.html',
        { 'width': 2000, 'height': 1000 },
        function(win) {
          win.contentWindow.onload = function() {
            var webview = win.contentWindow.document.querySelector('#webview');
            webview.addEventListener('newwindow', function(e) {
              e.preventDefault();
              if (e.targetUrl !== 'about:blank') {
                // Easy case where the original link or window.open()
                // already contains a target URL.
                newWindow_openInTab(e.targetUrl);
              } else {
                // Harder case where the guest first opens a blank
                // window and then redirects it via a
                // 'META HTTP-EQUIV="refresh"'.
                newWindow_openInTabAndInterceptRedirect(e.window);
            });
          };
        }
      );
    });
    
    function newWindow_openInTab(url) {
      chrome.app.window.create(url, ...);
    }
    
    function newWindow_openInTabAndInterceptRedirect(newWindow) {
      // Create an invisible proxy webview to listen to redirect
      // requests from |newWindow| (the window that the guest is
      // trying to open). NOTE: The proxy webview currently has to
      // live somewhere in the DOM, so we append it to the body.
      // This requirement is in the process of being eliminated.
      var proxyWebview = document.createElement('webview');
      document.body.appendChild(proxyWebview);
    
      // Listen to onBeforeRequest event (chrome.webRequest API)
      // on proxyWebview in order to intercept newWindow's redirects.
      var onBeforeRequestListener = function(e) {
        // Only consider top-level non-blank redirects.
        if (e.type === "main_frame" && e.url !== 'about:blank') {
          chrome.app.window.create(e.url, ...);
          // Don't need proxyWebview anymore.
          document.body.removeChild(proxyWebview);
          // Handled this redirect: cancel further processing.
          return { cancel: true };
        } else {
          // Ignored this redirect: proceed with default processing.
          return { cancel: false };
        }
      };
      proxyWebview.onBeforeRequest.addListener(
        onBeforeRequestListener,
        { urls: [ "*://*/*" ] },
        [ 'blocking' ]
      );
    
      // Attach |newWindow| to proxyWebview. From the original
      // webview guest's point of view, the window is now opened
      // and ready to be redirected: when it does so, the redirect
      // will be intercepted by |onBeforeRequestListener|.
      newWindow.attach(proxyWebview);
    }
    

    【讨论】:

    • 我对 newwindow 事件并不陌生,谢谢。第二种方法也是一个不错的技巧。
    • 我并不是说第二种方法是解决原始问题的方法。我想说一些网站,例如 Gmail,有时会使用这种技术来打开新标签并将它们定向到目标 URL。我将更新我的答案以使其更清晰,并为这种更困难的情况添加解决方案。
    • 我突然想到,我所说的一切都是基于您正在处理 target='_blank' 链接的假设,而实际上是您自己添加了 target='_blank'到链接。在这种情况下,您的问题可以通过直接在您的 webview 上使用的 webRequest API 来解决(因为它用于第二个示例中的代理 webview),因此根本不需要代理 webview 或收听“newwindow”。希望对您有所帮助。
    • 您需要在清单中为权限做些什么吗?您尝试打开的新窗口可能在应用程序外部,我收到“找不到此网页”Chrome 错误,如果我展开它,我看到该窗口正在尝试加载“chrome-extension:///url"
    • 啊,我想你只要做一个window.open(e.targetUrl); 就可以了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-26
    • 1970-01-01
    • 1970-01-01
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多