该页面翻译自 Google Chrome Extensions 与 Google Chrome Apps。除非特别说明,该页面的内容遵循 Creative Commons Attribution 3.0 License,代码示例遵循 BSD License。
Chrome 应用的安全模型不允许
iframe 中的外部内容,也不允许使用内嵌脚本与
eval()
。您可以覆盖这些限制,但是您的外部内容必须与应用程序隔离。
隔离的内容不能直接访问应用程序的数据或任何 API,但可以使用跨站 XMLHttpRequest 及消息传递在事件页面和经过沙盒屏蔽的内容间通信,并间接访问 API。
API 示例:想试试这些代码吗?请参见 sandbox 示例。
应用使用的内容安全策略不允许多种类型的远程
URL,所以您不能从应用页面中直接引用外部图像、样式表或字体。相反,您可以使用跨站
XMLHttpRequest 获取这些资源,并通过 blob:
URL 来使用它们。
为了能够发出跨来源 XMLHttpRequest 请求,您需要为远程 URL 的主机添加权限:
"permissions": [ "...", "https://supersweetdomainbutnotcspfriendly.com/" ]
将远程 URL 获取进应用并通过
blob:
URL
来使用它的内容:
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.webkitURL.createObjectURL(this.response); document.body.appendChild(img); }; xhr.send();
您可能希望在本地保存这些资源,这样它们在离线状态下也可以使用。
API 示例:想试试这些代码吗?请参见 browser 示例。
webview
标签允许您在您的应用中嵌入外部网络内容,例如一个网页。它替换了指向远程 URL
的 iframe,在 Chrome 应用内这是禁用的。与 iframe 不同,webview
标签运行在单独的进程中,这意味着它内部的攻击仍然会被隔离开来,不能获得提升的权限。此外,由于它的存储区(Cookie 等)与应用隔离,没有办法让网络内容访问应用的任何数据。
您的 webview 元素必须包含来源内容的 URL 并指定大小。
<webview src="http://news.google.com/" width="640" height="480"></webview>
要动态更改 webview
标签的 src
、width
和 height
属性,您既可以直接在 JavaScript
对象上设置这些属性,也可以使用 DOM 函数 setAttribute
。
document.querySelector('#mywebview').src = 'http://blog.chromium.org/'; // 或 document.querySelector('#mywebview').setAttribute( 'src', 'http://blog.chromium.org/');
沙盒功能允许指定页面在经过沙盒屏蔽的唯一来源中运行,这些页面就不受内容安全策略的限制。经过沙盒屏蔽的页面可以使用 iframe、内嵌脚本以及
eval()
。请查阅 sandbox
清单文件字段的描述。
不过这也是一个权衡的问题:经过沙盒屏蔽的页面不能使用 chrome.*
API。如果您需要做一些类似于 eval()
的事情,请使用这种方法免受
CSP(内容安全策略)的限制,但是您也不能使用一些很棒的新功能。
如下是一个经过沙盒屏蔽的页面示例,使用了内嵌脚本与
eval()
:
<html> <body> <h1>Woot</h1> <script> document.write('这是内嵌脚本。<br>'); eval('document.write(\'这是使用了 eval 的内嵌脚本。\');'); </script> </body> </html>
您需要在清单文件中包含 sandbox
字段,并列出需要在沙盒中运行的应用页面:
"sandbox": { "pages": ["sandboxed.html"] }
就像其他应用页面一样,您可以创建一个窗口,打开经过沙盒屏蔽的页面。如下是一个示例,它创建了两个窗口,一个用于应用主窗口,不经过沙盒屏蔽,另一个用于经过沙河屏蔽的页面:
注意:使用经过沙盒屏蔽的页面创建窗口时会遇到问题 154662,开发者控制台中会输出错误“Uncaught TypeError: Cannot call method 'initializeAppWindow' of undefined”,而且 app.window.create 不会调用回调函数,并传递窗口对象。但还是会创建新窗口,打开经过沙盒屏蔽的页面。
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('只是打个招呼。', '*'); }); });
一般从网页的角度来说,您希望指定消息发送方的准确来源。Chrome 应用无法访问经过沙盒屏蔽的内容的唯一来源,所以您只能将所有来源添加到可接受来源的白名单中('*')。在接收端,您通常希望检查来源,但是由于 Chrome 应用的内容是受限的,这没有必要。要想了解更多内容,请参见 window.postMessage。
如下是消息接收端的示例,可以添加到经过沙盒屏蔽的页面中去:
var messageHandler = function(e) { console.log('后台脚本打了个招呼。', e.data); }; window.addEventListener('message', messageHandler);