google-chrome - Chrome 打包应用程序与 SQLite?

标签 google-chrome google-chrome-extension google-chrome-app

我试图将 sql.js(基于 JS 的 SQLite https://github.com/kripken/sql.js/ )集成到我的 Chrome 应用程序中,但当我启动我的应用程序时,控制台显示以下错误:

Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "default-src 'self' chrome-extension-resource:". Note that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "default-src 'self' chrome-extension-resource:".

我的 list 文件如下所示:

{
  "manifest_version": 2,
  "name": "Chrome App",        
  "description": "This is the test app!!!",
  "version": "1",
  "icons": {
    "128": "icon_128.png"
  },
  "permissions": ["storage"],
  "app": {
    "background": {
      "scripts": ["background.js"]
    },
    "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
  },
  "minimum_chrome_version": "28"
}

最佳答案

@MarcRochkind 我想在您的书中添加一些集成知识 SQL.js在 Chrome 应用程序中。

只需很少的努力就可以实现这一点(考虑到政策和规则的遵守)。

为了集成任何使用eval的东西,您需要对脚本的特定部分进行沙箱处理。对于 SQL.js,它是整个库。

这可以通过需要在 main 中设置的 iframe 来完成 .html创建(或主)窗口所需的文档,例如chrome.app.window.create('index-app.html', { ..

主文档和 iframe 之间的通信基础将使用 postMessage用于发送和接收消息。

假设这个 iframe 的来源名为 /iframes/sqljs-sandboxed.html 。 在 manifest.json您需要指定 sqljs-sandboxed.html作为沙箱。指定的沙箱可以运行 evaleval类似的结构如 new Function .

{
  "manifest_version": 1,
  "name": "SQL.js Test",
  ..
  "sandbox": {
    "pages": [
      "iframes/sqljs-sandboxed.html",
    ]
  }
}

sqljs-sandboxed.html使用事件监听器对 message 类型的事件使用react。在这里,您可以简单地添加逻辑(为了简单起见,我使用了 switch 语句)来执行使用 SQL.js 构建的任何操作。

sqljs-sandboxed.html的内容举个例子:

<script src="/vendor/kripken/sql.js"></script>
<script>
  (function(window, undefined) {

    // a test database
    var db = new SQL.Database();
    // create a table with some test values
    sqlstr = "CREATE TABLE hello (a int, b char);";
    sqlstr += "INSERT INTO hello VALUES (0, 'hello');";
    sqlstr += "INSERT INTO hello VALUES (1, 'world');";
    // run the query without returning anything    
    db.run(sqlstr);

    // our event listener for message
    window.addEventListener('message', function(event) {
      var params = event.data.params,
          data = event.data.data,
          context = {};

        try {
          switch(params.cmd) {
            case '/do/hello':

              // process anything with sql.js
              var result = db.exec("SELECT * FROM hello");

              // set the response context
              context = {
                message: '/do/hello',
                hash: params.hash,
                response: result
              };

              // send a response to the source (parent document)
              event.source.postMessage(context, event.origin);

              // for simplicity, resend a response to see if event in 
              // 'index-app.html' gets triggered a second time (which it
              // shouldn't)
              setTimeout(function() {
                event.source.postMessage(context, event.origin);
              }, '1000');

              break;
          }
        } catch(err) {
          console.log(err);
        }
    });

  })(window);  
</script>

测试数据库仅创建一次,事件监听器使用简单的开关镜像 API。这意味着为了使用 SQL.js,您需要针对 API 进行编写。乍一看,这可能有点不舒服,但从普通意义上讲,这个想法与实现 REST 服务是等效的,在我看来,从长远来看,这是非常舒服的。

为了发送请求,index-app.html是发起者。需要指出的是,可以异步向 iframe 发出多个请求。为了防止交叉冲突,状态参数以唯一标识符的形式随每个请求一起发送(在我的示例中是 unique-ish)。同时在 message 上附加一个监听器。过滤掉所需响应并触发其指定回调的事件,如果触发,则将其从事件堆栈中删除。

为了快速演示,创建了一个对象,该对象自动连接和分离 message事件。最终listen函数最终应该过滤特定的字符串值,例如sandbox === 'sql.js' (本例中未实现)以加快对许多 message 的过滤器选择使用沙盒中的多个 iframe 时可能发生的事件(例如用于模板化的handlebars.js)。

var sqlRequest = function(request, data, callback) {

  // generate unique message id
  var hash = Math.random().toString(36).substr(2),
      // you can id the iframe as wished
      content_window = document.getElementById('sqljs-sandbox').contentWindow,
      listen = function(event) {

        // attach data to the callback to be used later
        this.data = event.data;
        // filter the correct response     
        if(hash === this.data.hash) {
          // remove listener
          window.removeEventListener('message', listen, false);
          // execute callback
          callback.call(this);
        }
      };

  // add listener
  window.addEventListener('message', listen, false);
  // post a request to the sqljs iframe
  content_window.postMessage({
    params: {
      cmd: request,
      hash: hash
    },
    data: data
  }, '*');
};

// wait for readiness to catch the iframes element
document.addEventListener('DOMContentLoaded', function() {
  // faking sqljs-sandboxed.html to be ready with a timeout
  setTimeout(function() {
    new sqlRequest('/do/hello', {
      allthedata: 'you need to pass'
    }, function() {
      console.log('response from sql.js');
      console.log(this.data);
    });
  }, '1000');

});

为了简单起见,我使用超时来防止在加载 iframe 之前发送请求。根据我的经验,最佳实践是让 iframe 向其父文档发布一条消息,表明 iframe 已加载,从这里开始您可以开始使用 SQL.js。

最后,在 index-app.html您指定 iframe

<iframe src="/iframes/sqljs-sandboxed.html" id="sqljs-sandbox"></iframe>

其中index-app.html的内容可能是

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <iframe src="/iframes/sqljs-sandboxed.html" id="sqljs-sandbox"></iframe>
  <h1>Hello, let's code with SQL.js!</h1>
  <script src="/assets/js/sqljs-request.js"></script>
</body>
</html>

关于google-chrome - Chrome 打包应用程序与 SQLite?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27126027/

相关文章:

Android:如何像 YouTube 在他的应用程序中那样创建 WebView

google-chrome - Chrome音频API未定义(Chrome操作系统应用)

google-chrome - 如何防止我的应用程序处于非事件状态?

javascript - 如何通过 JavaScript 重新加载我的 chrome 扩展?

javascript - 如何使用 chrome 应用程序文件系统将 FileEntry 转换为标准的 JavaScript 文件对象

google-chrome - chrome.exe 的通用路径

angularjs - 请求被重定向到 'https://..com/site/login?' ,这对于需要预检的跨源请求是不允许的

javascript - Chrome浏览器无法保存PDF

Javascript - 隐藏扩展

与 Chrome 的内容安全策略一起工作的 Javascript 模板引擎