我设法构建了Ripple Emulator开源。
我按照说明(Jakebuild)构建了该文件,该文件创建了Chrome扩展目标,使我可以按照通过构建的Chrome扩展程序测试自己的网络应用/master/doc/chrome_extension.md。
我已成功将解压后的扩展程序加载到chrome上,但是启用该功能后,什么都没有发生,尽管页面重新加载该扩展程序无法正常工作,但出现了2个错误:
未捕获的ReferenceError:未定义webkitNotifications
webkitNotifications.createHTMLNotification('/views/update.html').show();
运行tabs.executeScript时未选中的runtime.lastError:无法访问chrome:// URL
chrome.tabs.executeScript(tabId, {
我该如何解决这个问题?
完整的background.js:
if (!window.tinyHippos) { window.tinyHippos = {}; } tinyHippos.Background = (function () { var _wasJustInstalled = false, _self; function isLocalRequest(uri) { return !!uri.match(/^https?:\/\/(127\.0\.0\.1|localhost)|^file:\/\//); } function initialize() { // check version info for showing welcome/update views var version = window.localStorage["ripple-version"], xhr = new window.XMLHttpRequest(), userAgent, requestUri = chrome.extension.getURL("manifest.json"); _self.bindContextMenu(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { var manifest = JSON.parse(xhr.responseText), currentVersion = manifest.version; if (!version) { _wasJustInstalled = true; } if (version !== currentVersion) { webkitNotifications.createHTMLNotification('/views/update.html').show(); } window.localStorage["ripple-version"] = currentVersion; } }; xhr.open("GET", requestUri, true); xhr.send(); chrome.extension.onRequest.addListener(function (request, sender, sendResponse) { switch (request.action) { case "isEnabled": console.log("isEnabled? ==> " + request.tabURL); sendResponse({"enabled": tinyHippos.Background.isEnabled(request.tabURL)}); break; case "enable": console.log("enabling ==> " + request.tabURL); tinyHippos.Background.enable(); sendResponse(); break; case "version": sendResponse({"version": version}); break; case "xhr": var xhr = new XMLHttpRequest(), postData = new FormData(), data = JSON.parse(request.data); console.log("xhr ==> " + data.url); $.ajax({ type: data.method, url: data.url, async: true, data: data.data, success: function (data, status) { sendResponse({ code: 200, data: data }); }, error: function (xhr, status, errorMessage) { sendResponse({ code: xhr.status, data: status }); } }); break; case "userAgent": case "lag": case "network": // methods to be implemented at a later date break; default: throw {name: "MethodNotImplemented", message: "Requested action is not supported!"}; break; }; }); chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { if (tinyHippos.Background.isEnabled(tab.url)) { chrome.tabs.executeScript(tabId, { code: "rippleExtensionId = '" + chrome.extension.getURL('') + "';", allFrames: false }, function () { chrome.tabs.executeScript(tabId, { file: "bootstrap.js", allFrames: false }); }); } }); } function _getEnabledURIs() { var parsed = localStorage["tinyhippos-enabled-uri"]; return parsed ? JSON.parse(parsed) : {}; } function _persistEnabled(url) { var jsonObject = _getEnabledURIs(); jsonObject[url.replace(/.[^\/]*$/, "")] = "widget"; localStorage["tinyhippos-enabled-uri"] = JSON.stringify(jsonObject); } _self = { metaData: function () { return { justInstalled: _wasJustInstalled, version: window.localStorage["ripple-version"] }; }, bindContextMenu: function () { var id = chrome.contextMenus.create({ "type": "normal", "title": "Emulator" }); // TODO: hack for now (since opened tab is assumed to be page context was called from // eventually will be able to pass in data.pageUrl to enable/disable when persistence refactor is done chrome.contextMenus.create({ "type": "normal", "title": "Enable", "contexts": ["page"], "parentId": id, "onclick": function (data) { _self.enable(); } }); chrome.contextMenus.create({ "type": "normal", "title": "Disable", "contexts": ["page"], "parentId": id, "onclick": function (data) { _self.disable(); } }); }, enable: function () { chrome.tabs.getSelected(null, function (tab) { console.log("enable ==> " + tab.url); _persistEnabled(tab.url); chrome.tabs.sendRequest(tab.id, {"action": "enable", "mode": "widget", "tabURL": tab.url }); }); }, disable: function () { chrome.tabs.getSelected(null, function (tab) { console.log("disable ==> " + tab.url); var jsonObject = _getEnabledURIs(), url = tab.url; while (url && url.length > 0) { url = url.replace(/.[^\/]*$/, ""); if (jsonObject[url]) { delete jsonObject[url]; break; } } localStorage["tinyhippos-enabled-uri"] = JSON.stringify(jsonObject); chrome.tabs.sendRequest(tab.id, {"action": "disable", "tabURL": tab.url }); }); }, isEnabled: function (url, enabledURIs) { if (url.match(/enableripple=/i)) { _persistEnabled(url); return true; } // HACK: I'm sure there's a WAY better way to do this regex if ((url.match(/^file:\/\/\//) && url.match(/\/+$/)) || url.match(/(.*?)\. (jpg|jpeg|png|gif|css|js)$/)) { return false; } enabledURIs = enabledURIs || _getEnabledURIs(); if (url.length === 0) { return false; } else if (enabledURIs[url]) { return true; } return tinyHippos.Background.isEnabled(url.replace(/.[^\/]*$/, ""), enabledURIs); } }; initialize(); return _self; }());
完整manifest.json:
{ "version": "1", "manifest_version": 2, "name": "Ripple Emulator (Beta)", "background": { "page": "views/background.html" }, "web_accessible_resources": [], "icons":{ "16":"images/Icon_16x16.png", "128":"images/Icon_128x128.png", "48":"images/Icon_48x48.png" }, "browser_action":{ "default_popup":"views/popup.html", "default_icon":"images/Icon_48x48.png", "default_title":"Ripple" }, "content_scripts":[{ "run_at": "document_start", "js": ["controllers/Insertion.js"], "matches": ["http://*/*","https://*/*","file://*"] }, { "run_at": "document_start", "js": ["controllers/frame.js"], "matches": ["http://*/*","https://*/*","file://*"], "all_frames": true }], "permissions": ["tabs", "unlimitedStorage", "notifications", "contextMenus", "webRequest", "<all_urls>"], "description": "A browser based html5 mobile application development and testing tool" }
runtime.lastError通过在回调中“读取”它来“检查” 。
runtime.lastError
码
chrome.tabs.executeScript(tabId, { //.. }, _=>chrome.runtime.lastError /* "check" error */)
例如
通过显示它。
chrome.tabs.executeScript(tabId, { //.. }, _=>{ let e = chrome.runtime.lastError; if(e !== undefined){ console.log(tabId, _, e); } });