Unchecked runtime.lastError while running tabs.executeScript?
Asked Answered
M

2

5

I managed to build Ripple Emulator open source (https://github.com/apache/incubator-ripple).

I built it per the instructions (Jake build), which create the Chrome Extension Target that allows me to test my web apps via a chrome extension of my built, as per https://github.com/apache/incubator-ripple/blob/master/doc/chrome_extension.md.

I successfully loaded the unpacked extension onto chrome, but when I enable it nothing happens, though the page reloads the extension does not work, instead I get 2 errors:

  1. Uncaught ReferenceError: webkitNotifications is not defined

    webkitNotifications.createHTMLNotification('/views/update.html').show();
    
  2. Unchecked runtime.lastError while running tabs.executeScript: Cannot access a chrome:// URL

    chrome.tabs.executeScript(tabId, {
    

How do I solve this problem?


Full 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;
}());

Full 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"
}
Manson answered 22/10, 2014 at 22:10 Comment(0)
G
15

"Check" runtime.lastError by "reading" it in the callback.


Code

chrome.tabs.executeScript(tabId, {
  //..
}, _=>chrome.runtime.lastError /* "check" error */)

Eg

Show it via..

chrome.tabs.executeScript(tabId, {
  //..
}, _=>{
  let e = chrome.runtime.lastError;
  if(e !== undefined){
    console.log(tabId, _, e);
  }
});
Gilletta answered 10/8, 2017 at 3:22 Comment(3)
As of Chrome 74.0.3729.169 5/26/2019, assigning chrome.runtime.lastError to a var, w or w/o logging it does NOT prevent the red-text Errors button from showing on the Extensions tab. I know my extension won't work in the Chrome web store or on Chrome internal pages, and I'm ok with that (can't be helped anyway), but that display makes it look to users like the extension is broken. I haven't found any way to prevent that from happening. Has anyone?Khosrow
@Khosrow I have a similar issue - have you found any solution?Milson
@camelBack, sorry no, I've moved on, not working on this at all any more. Good luck!Khosrow
D
2

Both of these errors explain the problem well:

"webkitNotifications is not defined" - this is because webkitNotifications has been removed. I found Chrome webkitNotification not found : api missing which explains what is going on.

"Cannot access a chrome:// URL" - you must be trying to execute the script on a chrome:// URL (like chrome://settings, chrome://extensions) which is illegal. To avoid the error printing like that, you can either - check chrome.runtime.lastError - make sure not to inject onto chrome:// pages.

Disembroil answered 22/10, 2014 at 22:30 Comment(1)
thank you, @Disembroil it makes sense, though i have been executing it on my index files from my homepage, for some reason i cannot enable the extension.Manson

© 2022 - 2024 — McMap. All rights reserved.