I’m new to extension creation and have a problem, which I’ve already been able to find various ways to solve, but which are all different from mine and/or fixed with manifest V2 instead of V3 which I need.
Also, some fixes found work on their end, but not on mine, so I really don’t understand the problem.
Here is my problem:
-
I want to make a chrome extension to take screenshots of my browser and apps
-
I found an online tutorial that seemed correct to me (by the way, the only tutorial that uses AND the screenshots AND the V3 manifest, so perfect!)
-
Following the tutorial, I got the following error: Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
-
I looked for various ways, but nothing worked, I ended up downloading the git code of the tutorial, but it does not change anything, the error is still present
-
From what I understand, the error is in the following line:
chrome.action.onClicked.addListener(function (tab) {
chrome.desktopCapture.chooseDesktopMedia(
["screen", "window", "tab"],
tab,
(streamId) => {
if (streamId && streamId.length) {
setTimeout(() => {
chrome.tabs.sendMessage(
tab.id,
{ name: "stream", streamId },
(response) => console.log("received user data", response) // error is here, response is undefined
);
}, 200);
}
}
);
});
I get undefined instead of the response, and I think it’s from there that it’s a problem, because it never goes on and therefore never activates the onMessage function, nor the content_script
Here is the full background.js code :
chrome.action.onClicked.addListener(function (tab) {
chrome.desktopCapture.chooseDesktopMedia(
["screen", "window", "tab"],
tab,
(streamId) => {
if (streamId && streamId.length) {
setTimeout(() => {
chrome.tabs.sendMessage(
tab.id,
{ name: "stream", streamId },
(response) => console.log("received user data", response)
);
}, 200);
}
}
);
});
chrome.runtime.onMessage.addListener((message, sender, senderResponse) => {
if (message.name === "download" && message.url) {
chrome.downloads.download(
{
filename: "screenshot.png",
url: message.url,
},
(downloadId) => {
senderResponse({ success: true });
}
);
return true;
}
});
Content_script
chrome.runtime.onMessage.addListener((message, sender, senderResponse) => {
if (message.name === 'stream' && message.streamId) {
let track, canvas
navigator.mediaDevices.getUserMedia({
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: message.streamId
},
}
}).then((stream) => {
track = stream.getVideoTracks()[0]
const imageCapture = new ImageCapture(track)
return imageCapture.grabFrame()
}).then((bitmap) => {
track.stop()
canvas = document.createElement('canvas');
canvas.width = bitmap.width; //if not set, the width will default to 200px
canvas.height = bitmap.height;//if not set, the height will default to 200px
let context = canvas.getContext('2d');
context.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height)
return canvas.toDataURL();
}).then((url) => {
chrome.runtime.sendMessage({name: 'download', url}, (response) => {
if (response.success) {
alert("Screenshot saved");
} else {
alert("Could not save screenshot")
}
canvas.remove()
senderResponse({success: true})
})
}).catch((err) => {
alert("Could not take screenshot")
senderResponse({success: false, message: err})
})
return true;
}
})
manifest v3
{
"name": "Screenshots",
"version": "0.0.1",
"description": "Take screenshots",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"permissions": ["desktopCapture", "downloads", "tabs", "nativeMessaging"],
"action": {
"default_title": "Take a Screenshot"
},
"icons": {
"16": "/assets/icon-16.png",
"32": "/assets/icon-32.png",
"48": "/assets/icon-48.png",
"128": "/assets/icon-128.png"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content_script.js"]
}
]
}
I tried several things after various research like
-
Disable my extensions (which makes no sense, but you never know)
-
Add a timeout for the response, I tried up to 20 seconds delay, but without success
-
Added breakpoints everywhere to see if it crosses the line or not
3
Answers
So, @Norio Yamamoto 's solution suits me perfectly, because I then need to make a popup to give a name and do other processing on my screen, so thanks to your help, I'm already moving on by starting to understand it HTML popups on extensions! Thanks !
For the problem itself, I was able to "fix" it in the end by reinstalling chrome, and it works as @Thomas Muller tells me... not sure why, maybe I had to break something with many tests, so the app was already working
But I noticed a problem on the version of the tutorial compared to the one with popup, the tutorial version does not work on: non-reload pages (thanks @wOxxOm for the tip by the way), nor on chrome home pages, nor on the extension page, so I really prefer the popup version, but I need to dig more to improve that
Thanks again !
Works for me, using Chromium 107.0.5304.121 (Official. Build) Arch Linux (64-Bit).
Here is an implementation without service worker and content scripts.
manifest.json
popup.html
popup.js
desktopCaptuer.html
desktopCaptuer.js