外部内容

Chrome 应用安全模型不允许在 iframe 中使用外部内容以及使用内嵌脚本和 eval()。您可以替换这些限制,但您的外部内容必须与应用隔离开来。

被隔离的内容无法直接访问应用的数据或任何 API。使用跨源 XMLHttpRequests 和后消息传递在事件页面和沙盒化内容之间进行通信,并间接访问 API。

引用外部资源

应用使用的内容安全政策不允许使用多种远程网址,因此您无法在应用页面中直接引用外部图片、样式表或字体。您可以改为使用跨源 XMLHttpRequests 获取这些资源,然后通过 blob: 网址传送这些资源。

清单要求

为了能够执行跨源 XMLHttpRequests,您需要为远程网址的主机添加权限:

"permissions": [
    "...",
    "https://supersweetdomainbutnotcspfriendly.com/"
  ]

跨域 XMLHttpRequest

将远程网址提取到应用中,并将其内容作为 blob: 网址提供:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://supersweetdomainbutnotcspfriendly.com/image.png', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
  var img = document.createElement('img');
  img.src = window.URL.createObjectURL(this.response);
  document.body.appendChild(img);
};

xhr.send();

您可能需要在本地保存这些资源,以便离线使用。

嵌入外部网页

利用 webview 标记,您可以在应用中嵌入外部 Web 内容,例如网页。它取代了指向远程网址的 iframe,远程网址在 Chrome 应用中处于停用状态。与 iframe 不同,webview 标记在单独的进程中运行。这意味着,内部利用的漏洞仍会被隔离,并且无法获取提升的权限。此外,由于其存储(Cookie 等)与应用是隔离开来的,因此 Web 内容无法访问应用的任何数据。

添加 WebView 元素

您的 webview 元素必须包含源内容的网址,并指定其尺寸。

<webview src="http://news.google.com/" width="640" height="480"></webview>

更新媒体资源

如需动态更改 webview 标记的 srcwidthheight 属性,您可以直接在 JavaScript 对象上设置这些属性,也可以使用 setAttribute DOM 函数。

document.querySelector('#mywebview').src =
    'http://blog.chromium.org/';
// or
document.querySelector('#mywebview').setAttribute(
    'src', 'http://blog.chromium.org/');

沙盒本地内容

沙盒环境允许在沙盒化的唯一来源中提供指定的页面。然后,这些网页将不受其内容安全政策的约束。沙盒化页面可以使用 iframe、内嵌脚本和 eval()。请查看sandbox的清单字段说明。

不过,需要权衡操作:沙盒化页面无法使用 Chrome。*API。如果您需要执行 eval() 等操作,请通过此路由豁免 CSP,但您将无法使用炫酷的新功能。

在沙盒中使用内嵌脚本

下面是一个使用内嵌脚本和 eval() 的沙盒化网页示例:

<html>
  <body>
    <h1>Woot</h1>
    <script>
      eval('console.log(\'I am an eval-ed inline script.\')');
    </script>
  </body>
</html>

在清单中包含沙盒

您需要在清单中添加 sandbox 字段,并列出要在沙盒中提供的应用页面:

"sandbox": {
  "pages": ["sandboxed.html"]
}

在窗口中打开沙盒化页面

与任何其他应用页面一样,您也可以创建一个窗口,以便在其中打开沙盒化页面。以下示例会创建两个窗口,一个用于未沙盒化的主应用窗口,另一个用于沙盒化页面:

chrome.app.runtime.onLaunched.addListener(function() {
  chrome.app.window.create('window.html', {
    'bounds': {
      'width': 400,
      'height': 400,
      'left': 0,
      'top': 0
    }
  });

  chrome.app.window.create('sandboxed.html', {
    'bounds': {
      'width': 400,
      'height': 400,
      'left': 400,
      'top': 0
    }
  });
});

在应用页面中嵌入沙盒化页面

您也可以使用 iframe 将沙盒化页面嵌入到其他应用页面中:

<!DOCTYPE html>
<html>
<head>
</head>
  <body>
    <p>I am normal app window.</p>

    <iframe src="sandboxed.html" width="300" height="200"></iframe>
  </body>
</html>

向沙盒化页面发送消息

发送消息的过程分为两个部分:您需要从发送者页面/窗口发布消息,并在接收页面/窗口中监听消息。

发布消息

您可以使用 postMessage 在您的应用与沙盒化内容之间进行通信。下面的后台脚本示例会将消息发布到所打开的沙盒化页面:

var myWin = null;

chrome.app.runtime.onLaunched.addListener(function() {
  chrome.app.window.create('sandboxed.html', {
    'bounds': {
      'width': 400,
      'height': 400
    }
  }, function(win) {
       myWin = win;
       myWin.contentWindow.postMessage('Just wanted to say hey.', '*');
     });
});

一般来说,在网络上,您需要指定邮件发送的确切来源。 Chrome 应用无权访问沙盒化内容的唯一来源,因此您只能将所有来源添加为可接受的来源(“*”)。在接收端,您通常需要检查来源;但由于 Chrome 应用内容已包含,因此没有必要这样做。如需了解详情,请参阅 window.postMessage

收听消息和回复

以下是添加到沙盒化网页的消息接收器示例:

var messageHandler = function(event) {
  console.log('Background script says hello.', event.data);

  // Send a reply
  event.source.postMessage(
      {'reply': 'Sandbox received: ' + event.data}, event.origin);
};

window.addEventListener('message', messageHandler);

如需了解详情,请查看sandbox示例。