{"id":21479350,"url":"https://github.com/bambooom/crx-intro-demo","last_synced_at":"2025-07-15T11:31:41.042Z","repository":{"id":118775233,"uuid":"93921260","full_name":"bambooom/crx-intro-demo","owner":"bambooom","description":"a little tutorial about the first chrome extension","archived":false,"fork":false,"pushed_at":"2017-06-10T06:48:54.000Z","size":12,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-09T03:25:14.376Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bambooom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-06-10T06:47:51.000Z","updated_at":"2023-02-06T07:35:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"ff7f5a54-7462-4aa8-96d2-139e6dbe76d7","html_url":"https://github.com/bambooom/crx-intro-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bambooom/crx-intro-demo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bambooom%2Fcrx-intro-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bambooom%2Fcrx-intro-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bambooom%2Fcrx-intro-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bambooom%2Fcrx-intro-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bambooom","download_url":"https://codeload.github.com/bambooom/crx-intro-demo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bambooom%2Fcrx-intro-demo/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265431653,"owners_count":23764031,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-23T11:24:47.722Z","updated_at":"2025-07-15T11:31:41.027Z","avatar_url":"https://github.com/bambooom.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# crx-intro-demo\n- 大致翻译自 [Getting Started: Building a Chrome Extension - Google Chrome](https://developer.chrome.com/extensions/getstarted)\n- 最简单的功能: 点击插件 icon, 会有个小弹窗, 显示当前 tab 的 property\n    - PS: 原本官方文档中的 demo 使用的 google image search API 已经停用, 所以去掉了搜索图片的功能\n\n## 目录\n```\n|____icon.png       # 图标, 显示在 chrome 上可点击按钮\n|____manifest.json  # 配置文件, 告诉 chrome 如何使用/加载相关文件\n|____popup.html     # 点击 icon 后出现的弹窗, 本质上也是 HTML 页面\n|____popup.js       # popup.html 中需要执行的脚本 popup.js\n|____README.md\n```\n\n## 什么是 `manifest.json`\n- 它是 chrome 插件中的一个配置文件\n- crx 最重要理解如何配置 `manifest.json`\n- 因为这个配置文件告诉了 chrome 如何使用加载你的代码/资源\n- [官方文档](https://developer.chrome.com/extensions/manifest)中完整可配置示例\n- 阅读文档才能明白 chrome 提供哪些接口, 你可以通过这些接口做什么\n- [附录](#%E9%99%84%E5%BD%95-manifestjson-%E8%AF%A6%E8%A7%A3)有详细说明每个可配置项的大致意义, 初次了解可以先跳过\n\n## 创建 `manifest.json`\n- 这个小教程中使用的配置文件\n\n```json\n{\n    \"manifest_version\": 2,\n    \"name\": \"Chrome Extension Getting Started Example\",\n    \"description\": \"This extension shows the current page info\",\n    \"version\": \"1.0\",\n    \"browser_action\": {\n        \"default_icon\": \"icon.png\",\n        \"default_popup\": \"popup.html\"\n    },\n    \"permissions\": [\n        \"activeTab\"\n    ]\n}\n```\n\n- 这个小 demo 中使用的是 `browser_action`, 即适用于大部分网页, 不局限于某一部分网页\n- `permissions` 中需要声明是插件可以访问到打开的 tab\n- 另外, 为 `browser_action` 定义了默认的 icon - icon.png, 以及弹框所需展示的页面 - popup.html\n\n## 创建弹窗页面\n\n```html\n\u003c!doctype html\u003e\n\u003c!--\n This page is shown when the extension button is clicked, because the\n \"browser_action\" field in manifest.json contains the \"default_popup\" key with\n value \"popup.html\".\n --\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eGetting Started Extension's Popup\u003c/title\u003e\n    \u003cstyle\u003e\n      body {\n        font-family: \"Segoe UI\", \"Lucida Grande\", Tahoma, sans-serif;\n        font-size: 100%;\n      }\n      #status {\n        /* avoid an excessively wide status text */\n        white-space: pre;\n        text-overflow: ellipsis;\n        overflow: hidden;\n        max-width: 400px;\n      }\n    \u003c/style\u003e\n\n    \u003c!--\n      - JavaScript and HTML must be in separate files: see our Content Security\n      - Policy documentation[1] for details and explanation.\n      -\n      - [1]: https://developer.chrome.com/extensions/contentSecurityPolicy\n     --\u003e\n    \u003cscript src=\"popup.js\"\u003e\u003c/script\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cdiv id=\"status\"\u003e\u003c/div\u003e\n    \u003cul id=\"tab-prop\"\u003e\u003c/ul\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n- 一个非常简单的弹窗页面, 也就是在点击插件 icon 时会跳出来的页面, 是标准 HTML 页面而已\n- 当然仔细看的话, 会发现实际 body 中并没有内容, 因为实际逻辑是通过执行 `popup.js` 文件实现的\n- `popup.js` 长这样:\n\n```js\n// Copyright (c) 2014 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * Get the current active Tab.\n *\n * @param {function(object)} callback - called when the current tab\n *   is found.\n */\nfunction getCurrentTab(callback) {\n    // Query filter to be passed to chrome.tabs.query - see\n    // https://developer.chrome.com/extensions/tabs#method-query\n    var queryInfo = {\n        active: true,\n        currentWindow: true\n    };\n\n    chrome.tabs.query(queryInfo, function(tabs) {\n        // chrome.tabs.query invokes the callback with a list of tabs that match the\n        // query. When the popup is opened, there is certainly a window and at least\n        // one tab, so we can safely assume that |tabs| is a non-empty array.\n        // A window can only have one active tab at a time, so the array consists of\n        // exactly one tab.\n        var tab = tabs[0];\n\n        // A tab is a plain object that provides information about the tab.\n        // See https://developer.chrome.com/extensions/tabs#type-Tab\n        var url = tab.url;\n\n        // tab.url is only available if the \"activeTab\" permission is declared.\n        // If you want to see the URL of other tabs (e.g. after removing active:true\n        // from |queryInfo|), then the \"tabs\" permission is required to see their\n        // \"url\" properties.\n        console.assert(typeof url == 'string', 'tab.url should be a string');\n\n        callback(tab);\n    });\n\n    // Most methods of the Chrome extension APIs are asynchronous. This means that\n    // you CANNOT do something like this:\n    //\n    // var url;\n    // chrome.tabs.query(queryInfo, function(tabs) {\n    //   url = tabs[0].url;\n    // });\n    // alert(url); // Shows \"undefined\", because chrome.tabs.query is async.\n}\n\n/**\n * 原 demo 中 google search 的 API 已经关闭\n * 新版的 API 配置更严格, 并不能简单调用, 所以先去掉这个功能啦~\n */\n// function getImageUrl(searchTerm, callback, errorCallback) {\n// }\n\nfunction renderTabInfo(tab) {\n    var infoHTML = '';\n    Object.keys(tab).map(key =\u003e {\n        infoHTML += `\u003cli\u003e ${key}: ${tab[key]}\u003c/li\u003e`;\n    });\n    document.getElementById('tab-prop').innerHTML = infoHTML;\n}\n\nfunction renderStatus(statusText) {\n    document.getElementById('status').textContent = statusText;\n}\n\ndocument.addEventListener('DOMContentLoaded', function() {\n    getCurrentTab(function(tab) {\n        renderStatus('Current tab\\'s url is ' + tab.url);\n        renderTabInfo(tab);\n    });\n});\n\n```\n\n- 如果熟悉 JavaScript 的话, 这是非常清晰明了的\n- 脚本主要流程是这样的:\n    - 在弹窗页面加载 DOM 完成时, 添加事件监听器\n    - 这个监听器, 首先获取当前窗口的当前 active 标签页 (`getCurrentTab`)\n        - 因为 `chrome.tabs.query` 是一个异步的方法, 所以使用 callback\n    - ~~获取到 url 之后, 在 popup 页面上显示当前状态 (`renderStatus`)~~\n    - ~~并开始使用 google 图片搜索的 api 搜索图片 (`getImageUrl`)~~\n        - ~~当获取到图片信息后, 显示图片 (`image-result`)~~\n        - ~~如果获取不到, 则显示错误信息即可~~\n    - 上面删掉的部分是原 demo 中的流程, 现在简化为获取当前标签页后, 显示标签对象的属性列表即可 (`renderTabInfo`)\n\n\n## 加载插件到 Chrome 中\n- 准备好了这些文件后, 就是把它们加到 chrome 里测试一下是否能正常运行呢\n- 操作很简单:\n    - chrome 中打开 `chrome://extensions`, 也就是管理插件的页面, 也可以从最右边的菜单 icon 里点击 More Tools -\u003e Extensions 打开\n    - 右上角会有一个 `Developer Mode` 的 checkbox, 一定要勾选\n    - 点击 `Load unpacked extension…` 按钮就会出来文件选择的对话框\n    - 选择上面创建的文件的目录即可加载\n- 加载成功就会在页面上显示这个插件啦~ chrome 右上角也会出现插件的 icon 了~✨\n    - 加载不成功的话, chrome 会提示你哪里出了问题, 改一下再重新加载吧\n- 现在可以点击一下 icon 来试一试插件是否正常运行了\n- 加载之后, 也仍然会经常修改代码看看效果, 此时只需要点击 `Reload (⌘R)` 或者快捷键 F5/Ctrl-R/Command-R 重新加载, 即可使新修改的代码生效\n\n## 如何 Debug Chrome Extension\n\n### 打开 Chrome Dev Tools\n- 用惯了 Chrome Dev Tools 的话, 自然也会希望能在插件开发中使用调试代码/样式\n- 如果插件有弹窗 popup, 则可以对插件 icon 右键, 选择选项 `Inspect Popup`, 即可以打开对于 `popup.html` 页面的 Dev Tools 面板\n- 其他和普通的页面调试一样操作即可, 修改样式/断点调试等\n- Dev Tools 面板和弹窗页面是保持同时打开状态, 关闭某一个, 另一个也会关闭\n- 如果希望保持打开的状态重新加载插件, 可以在 console 中键入命令 `location.reload(true)` 回车即可\n\n### 另一种 technique\n- 前面这种方法适用于有 popup 的插件, 想要和普通网页一样一直打开调试面板, 或者插件并没有 popup, 可以考虑这样做:\n- 在 `chrome://extensions` 页面中, 每个插件都有一个唯一的 ID, 从本地加载的也有 ID, 是一个临时的 ID\n- 可以直接在地址栏键入 `chrome-extension://\u003cextensionId\u003e/\u003cfilename\u003e` 打开你的插件中的任意文件\n- 例如上面的例子中, 可以打开 `chrome-extension://\u003cextensionId\u003e/popup.html`, 然后一样右键 `Inspect` 或者 `Command+Shift+I` 打开 Dev Tools 面板即可\n- 当然, 因为此 demo 中是想要获取 tab 对象信息, 所以此处打开的 popup 页面永远都是返回相同结果, 意义并不大\n- 所以每个不同的插件想要正确调试需要注意不同场景下的使用\n- 另外, 也可以利用这个页面来完成插件的某些功能, 例如非常有用的 [OneTab](https://chrome.google.com/webstore/detail/onetab/chphlpgkkbolifaimnlloiipkdnihall?hl=en) 插件, \n它就是将所有保存的 tab 展示在了 `chrome-extension://chphlpgkkbolifaimnlloiipkdnihall/onetab.html` 这样一个页面上, 并可对保存的 tab 进行交互操作\n\n\n## 再进一步的话?\n- 尝试多几个 example 了解插件都可以做到什么 \n    - [官方提供 example](https://developer.chrome.com/extensions/samples)\n    - [还找到了一些](https://chromium.googlesource.com/chromium/src/+/master/chrome/common/extensions/docs/examples/extensions/)\n- 如果对 Dev Tools 的使用不太熟, 还可以从[这里](https://developers.google.com/web/tools/chrome-devtools/)了解\n- 看太多, 不如马上动手开始写, 不会的再继续查文档吧~ 🖖\n\n\n### 附录: `manifest.json` 详解\n```js\n{\n  // Required 必须要求部分\n  \"manifest_version\": 2,  // manifest 版本从 chrome 18 之后都应该是 2, 此处不需要变化 \n  \"name\": \"My Extension\", // 名字是插件主要的 identifier\n  \"version\": \"1.0.3\", \n    // 插件版本号, string, 最多为4个以 dot 分开的 interger, e.g. \"3.1.2.4567\"\n    // 版本号不能随意乱写, chrome 的自动更新系统会根据版本号判断是否需要将插件更新至新的版本\n\n\n  // Recommended\n  \"default_locale\": \"en\",\n    // 如果需要指定不同 locale 使用不同的资源文件, 例如在中国显示中文, 在日本显示为日语等\n    // 则会在根目录中添加 `_locale` 文件夹;\n    // 若没有 `_locale` 文件夹, 则不能出现该项配置\n  \"description\": \"A plain text description\", \n    // 描述插件是干啥的, 描述需要适合在 chrome web store 上显示\n  \"icons\": {\n      \"16\": \"icon16.png\",\n      \"48\": \"icon48.png\",\n      \"128\": \"icon128.png\"\n  },\n    // 图标可以是1个, 或者多个\n    // 一般来说最好的方案是提供3个: \n    // - 128x128: 在从 chrome web store 安装的过程中需要使用, Required\n    // - 48x48: chrome://extensions 插件管理页面中使用\n    // - 16x16: 插件页面当做 favicon 使用\n\n\n  // Pick one (or none) - browser_action / page_action\n  \"browser_action\": {\n      \"default_icon\": {                    // optional\n        \"16\": \"images/icon16.png\",           // optional\n        \"24\": \"images/icon24.png\",           // optional\n        \"32\": \"images/icon32.png\"            // optional\n      },\n        // icon 是随意提供多少个, chrome 选取最接近的尺寸, 为了适配不同屏幕, 提供多种尺寸是很实用的\n      \"default_title\": \"Google Mail\",      // optional; shown in tooltip\n        // tooltip, 光标停留在 icon 上时显示\n      \"default_popup\": \"popup.html\"        // optional\n        // 如果有 popup 的页面, 则用户点击图标就会渲染此 HTML 页面\n  },\n    // 参考 https://developer.chrome.com/extensions/browserAction\n    // 如果有 browser_action, 即在 chrome toolbar 的右边添加了一个 icon\n  \n  \"page_action\": {...},\n    // 如果并不是对每个网站页面都需要使用插件, 可以使用 page_action 而不是 browser_action\n    // browser_action 应用更加广泛\n    // 如果 page_action 并不应用在当前页面, 会显示灰色\n\n\n\n  // Optional\n  \"author\": ...,\n  \"automation\": ...,\n  \"background\": {\n    \"scripts\": [\"background.js\"],\n    // \"page\": \"background.html\", // 如果有必要, 也可以指定 background HTML\n    \"persistent\": false // Recommended\n        // 此处设定为 false 为如果这个 process 并没有在运行, 即释放内存和系统资源\n  },\n    // 参考: https://developer.chrome.com/extensions/background_pages\n    // 如字面意思, background 即插件后台 process, 一般不需要 html, 只需要一个 js 文件, 类似一个监听器\n    // 如果在 browser_action 或者其他情况下 state 变化, 就会告诉 background 来更新 view\n  \"background_page\": ...,\n  \"chrome_settings_overrides\": {\n    \"homepage\": \"http://www.homepage.com\",\n    \"search_provider\": {\n        \"name\": \"name.__MSG_url_domain__\",\n        \"keyword\": \"keyword.__MSG_url_domain__\",\n        \"search_url\": \"http://www.foo.__MSG_url_domain__/s?q={searchTerms}\",\n        \"favicon_url\": \"http://www.foo.__MSG_url_domain__/favicon.ico\",\n        \"suggest_url\": \"http://www.foo.__MSG_url_domain__/suggest?q={searchTerms}\",\n        \"instant_url\": \"http://www.foo.__MSG_url_domain__/instant?q={searchTerms}\",\n        \"image_url\": \"http://www.foo.__MSG_url_domain__/image?q={searchTerms}\",\n        \"search_url_post_params\": \"search_lang=__MSG_url_domain__\",\n        \"suggest_url_post_params\": \"suggest_lang=__MSG_url_domain__\",\n        \"instant_url_post_params\": \"instant_lang=__MSG_url_domain__\",\n        \"image_url_post_params\": \"image_lang=__MSG_url_domain__\",\n        \"alternate_urls\": [\n          \"http://www.moo.__MSG_url_domain__/s?q={searchTerms}\",\n          \"http://www.noo.__MSG_url_domain__/s?q={searchTerms}\"\n        ],\n        \"encoding\": \"UTF-8\",\n        \"is_default\": true\n    },\n    \"startup_pages\": [\"http://www.startup.com\"]\n  }, // 覆盖 chrome 设定, Homepage, Search Provider, and Startup Pages\n  \"chrome_ui_overrides\": {\n    \"bookmarks_ui\": {\n      \"remove_bookmark_shortcut\": true, // 去掉添加书签的快捷键, \n      \"remove_button\": true // 去掉了地址栏右边的 star button, 可以将 browser_action 的 icon 放在此处\n    }\n  }, // 覆盖 bookmark ui 设置, 需要 Chrome Dev Release, 较新的 api 吧\n  \"chrome_url_overrides\": {\n    \"pageToOverride\": \"myPage.html\"\n      // 替换页面 HTML/CSS/JS, 可以替换的页面: \n      // - 书签管理页面 chrome://bookmarks\n      // - 浏览历史页: chrome://history\n      // - 新标签页: chrome://newtab \n  },\n  \"commands\": {\n      // commands API 用来添加快捷键\n      // 需要在 background page 上添加监听器绑定 handler\n    \"toggle-feature-foo\": {\n      \"suggested_key\": {\n        \"default\": \"Ctrl+Shift+Y\",\n        \"mac\": \"Command+Shift+Y\"\n      },\n      \"description\": \"Toggle feature foo\",\n      \"global\": true\n        // 当 chrome 没有 focus 时也可以生效的快捷键\n        // 仅限 Ctrl+Shift+[0..9]\n    },\n    \"_execute_browser_action\": {\n      \"suggested_key\": {\n        \"windows\": \"Ctrl+Shift+Y\",\n        \"mac\": \"Command+Shift+Y\",\n        \"chromeos\": \"Ctrl+Shift+U\",\n        \"linux\": \"Ctrl+Shift+J\"\n      }\n    },\n    \"_execute_page_action\": {\n      \"suggested_key\": {\n        \"default\": \"Ctrl+Shift+E\",\n        \"windows\": \"Alt+Shift+P\",\n        \"mac\": \"Alt+Shift+P\"\n      }\n    },\n    ...\n  },\n  \"content_capabilities\": ...,\n    // content_scripts 是在当前网页中插入并执行的脚本, 可以对网页进行各种操作\n    // content_scripts 中可以监听插件发来的 message, 并进行某些操作\n    // 可以选择是否永远插入, 或者只在一部分网页中 inject\n    // content_scripts 执行环境称为 isolated world, 和正常页面中的 JS 不在相同环境中\n    //  保证不同 script 不会冲突, 也不会和网页本身冲突\n    //  也说明互相无法访问或使用其中的变量或函数\n  \"content_scripts\": [\n    {\n      \"matches\": [\"http://www.google.com/*\"],\n        // 指定那些页面需要 inject \n      \"css\": [\"mystyles.css\"], // 按照顺序 inject\n      \"js\": [\"jquery.js\", \"myscript.js\"], // 按照顺序 inject\n      \"run_at\": \"document_idle\", // 什么时候 inject js,  \"document_start\", \"document_end\", or \"document_idle\".\n    }\n  ],\n  \"content_security_policy\": \"policyString\",\n    // https://developer.chrome.com/extensions/contentSecurityPolicy\n  \"converted_from_user_script\": ...,\n  \"current_locale\": ...,\n  \"devtools_page\": \"devtools.html\",\n    // 对 DevTools 的扩展, 例如 React, Redux develop tools\n  \"event_rules\": [{...}],\n    // 添加规则将某些 JS 事件转为 manifest (?)\n  \"externally_connectable\": {\n    // 指定哪些插件/ app/ 网站可以连接到你的插件上\n    // 此处 ids 指允许连接的其他插件 id\n    // 注意: 如果不写, 则认为所有其他插件都不能连接\n    \"ids\": [\n      \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n      \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n      ...\n      // 使用 wildcard \"*\" 允许所有其他插件连接\n      \"*\"\n    ],\n    \"matches\": [\"*://*.example.com/*\"]\n  },\n  \"file_browser_handlers\": [...], // 仅能在 Chrome OS 上使用, 对文件的操作\n  \"file_system_provider_capabilities\": {\n    // 仅能在 Chrome OS 上使用, 对文件的操作\n    \"configurable\": true,\n    \"multiple_mounts\": true,\n    \"source\": \"network\"\n  },\n  \"homepage_url\": \"http://path/to/homepage\",\n  \"import\": [{\"id\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}],\n    // 如果有 shared module, 在提供 shared module 的 extension 中则会有 \"export\" 项\n  \"incognito\": \"spanning, split, or not_allowed\",\n    // 隐身模式下, \"spanning\" -\u003e chrome app, \"split\" -\u003e ext\n  \"input_components\": ...,\n  \"key\": \"publicKey\", // 不怎么需要用到了\n  \"minimum_chrome_version\": \"versionString\", // 与 version 相同\n  \"nacl_modules\": [{\n    \"path\": \"OpenOfficeViewer.nmf\",\n    \"mime_type\": \"application/vnd.oasis.opendocument.spreadsheet\"\n  }], // 使用 Native Client Module 对网络上某种 MIME 类似资源进行操作, 但貌似 deprecated 了, 往 WebAssembly发展了 \n  \"oauth2\": ...,\n  \"offline_enabled\": true,\n  \"omnibox\": {\n    \"keyword\": \"aString\"\n    // 注册一个 keyword显示在 address bar 的前面\n    // 当用户在 address bar 中输入 keyword 后, 用户就是和插件在交互了\n  },\n  \"optional_permissions\": [\"tabs\"], // 其他需要的 permission, 在使用 chrome.permissions API 时用到, 并非安装插件时需要\n  \"options_page\": \"options.html\",\n    // 允许用户进行某些配置来定制插件功能, 并使用 chrome.storage.sync api 来保存设置 \n  \"options_ui\": {\n    \"chrome_style\": true, //默认使用 Chrome user agent stylesheet\n    \"page\": \"options.html\",\n    \"open_in_tab\": false // 不建议打开新 tab, 以后会删除此项\n  }, // 新版配置功能 api, 支持 chrome40 以上, 打开 dialogue, 使用 chrome.runtime.openOptionsPage api 打开 option 页面\n  \"permissions\": [\"tabs\"],\n    //-\u003e https://developer.chrome.com/extensions/declare_permissions\n    // 有很多选择, 书签/右键菜单/剪贴板/cookie/下载/.... 等\n  \"platforms\": ...,\n  \"plugins\": [...],\n  \"requirements\": {\n    \"3D\": {\n      \"features\": [\"webgl\"]\n    }\n  }, // 要求某些可能需要用户安装某些额外的 tech, 例如 webGL\n  \"sandbox\": [...], // chrome 57 以上不再允许外部 web 内容\n  \"short_name\": \"Short Name\", // 插件名字简写\n  \"signature\": ...,\n  \"spellcheck\": ...,\n  \"storage\": {\n    \"managed_schema\": \"schema.json\"\n  }, //  使用 storage.managed api 的话, 需要一个 schema 文件指定存储字段类型等, 类似定义数据库表的 column\n  \"system_indicator\": ...,\n  \"tts_engine\": {\n    \"voices\": [\n      {\n        \"voice_name\": \"Alice\",\n        \"lang\": \"en-US\",\n        \"gender\": \"female\",\n        \"event_types\": [\"start\", \"marker\", \"end\"]\n      },\n      {\n        \"voice_name\": \"Pat\",\n        \"lang\": \"en-US\",\n        \"event_types\": [\"end\"]\n      }\n    ]\n  }, // text-to-speech(TTS) engine, permission 需要加上 ttsEngine\n  \"update_url\": \"http://path/to/updateInfo.xml\", // 如果不是通过 chrome web store 自动更新插件\n  \"version_name\": \"aString\", // 版本号名称, 如 \"1.0 beta\", 只是为了展示, 更加描述性\n  \"web_accessible_resources\": [...] \n    // 提供插件pkg中某些资源是当前 web page 可以使用的\n    // 默认插件中的资源对于网页是 blocked, 需要说明哪些是要使用的 图片/图标/css/js 等 \n}\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbambooom%2Fcrx-intro-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbambooom%2Fcrx-intro-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbambooom%2Fcrx-intro-demo/lists"}