该页面翻译自 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);