difference between chrome.runtime.onmessage and chrome.runtime.port onmessage event - google-chrome-extension

My below contentscript.js receives the message only to chrome.runtime.onMessage.addListener but not to port.onMessage.addListener
console.log("loaded");
var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
port.postMessage({answer: "Madame... Bovary"});
});
chrome.runtime.onMessage.addListener(function (msg, sender, response) {
console.log("cs:on message ");
});
I send the following message from my backgroundscript.js:
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log("message sent");
});
});
Why doesn't my port.onMessage.addListener not triggered though its initialized.

From https://developer.chrome.com/extensions/messaging :
In order to handle incoming connections, you need to set up a
runtime.onConnect event listener. This looks the same from a content
script or an extension page. When another part of your extension calls
"connect()", this event is fired, along with the runtime.Port object
you can use to send and receive messages through the connection.
Here's what it looks like to respond to incoming connections:
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.name == "knockknock");
port.onMessage.addListener(function(msg) {
if (msg.joke == "Knock knock")
port.postMessage({question: "Who's there?"});
else if (msg.answer == "Madame")
port.postMessage({question: "Madame who?"});
else if (msg.answer == "Madame... Bovary")
port.postMessage({question: "I don't get it."});
});
});
So this is how you would catch your message from the specific port:
chrome.runtime.onConnect.addListener(function(port) {
port.onMessage.addListener(function(msg) {
console.log(msg) // msg object will be your message
})
})

Related

Background script: Error: Could not establish connection. Receiving end does not exist

I am trying to send a message from background script to content script in my chrome extension. But it looks like the message gets send before the content script is loaded?
This is the error I get when I am using my extension normally:
Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.
This is my background script with the tabs.onUpdated function:
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.url) {
console.log(changeInfo.url, tabId)
chrome.tabs.sendMessage(tabId, {
url: changeInfo.url,
type: 'URL_CHANGE'
});
}
});
This is my content script receive function:
chrome.runtime.onMessage.addListener((obj, sender, response) => {
console.log('received', obj)
if (obj.type === 'URL_CHANGE') {
console.log('testestsetst')
getAuth()
getUrlType(obj.url)
} else if (obj.type === 'AUTH') {
getAuth()
} else if (obj.type === 'UN-AUTH') {
removeAuth()
}
});
Whenever I run the extension normally I don't see an output from my content script and I get the error as stated above. However, when I debug the background script and step through the code, I get no error and my content script prints everything correctly. Could this be due to the page needing to load? And if so, how do I solve this?
Solved it by checking for tab complete and sending the url through the tab parameter as follows:
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
chrome.tabs.sendMessage(tabId, {
url: tab.url,
type: 'URL_CHANGE'
});
}
});
background.js
chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == "install") {
chrome.tabs.create({ url: chrome.runtime.getURL(`onboard-page.html`) }, function (tab) {
chrome.tabs.onUpdated.addListener(function listener(tabId, changeInfo) {
if (tabId === tab.id && changeInfo.status == 'complete') {
chrome.tabs.onUpdated.removeListener(listener)
// Now the tab is ready!
chrome.tabs.sendMessage(tab.id, "hello")
}
});
});
} else if (details.reason == "update") {
}
});
content-script.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
console.log(message)
});

Unable to send message response back to content script in Chrome Extension using Manifest V3

I'm successfully launching a webauthflow to an social OAuth provider from a service worker background script (as per manifest v3 requirements, background scripts are now full blown service workers)
However I'm unable to send a message back to my content script in what should be the simplest scenario.
Here is my service worker (background.js)
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.message === "login") {
if (user_signed_in) {
console.log("already signed in");
} else {
chrome.identity.launchWebAuthFlow({
url: createOAuthEndpoint(),
interactive: true,
}, function (redirect_uri) {
if (chrome.runtime.lastError) {
sendResponse({
message: "fail"
});
} else {
if (redirect_uri.includes("error")) {
sendResponse({
message: "fail"
});
} else {
//we get here but this message is never sent
sendResponse({
message: "success",
profile: "blah"
});
}
}
});
}
}
return true;
});
And here is my content script...(popupsignin.js)
document.querySelector('#sign-in').addEventListener('click', () => {
chrome.runtime.sendMessage({ message: 'login' }, (response) => {
console.log('got the response'); //this log is never written
if (response.message === 'success'){
console.log(response.profile);
}
});
});
Turns out there was nothing wrong with code. There was(is) just nowhere for me to read the console.log(...) output in the callback method for some reason. I added an alert instead and it fired just fine.

"chrome.runtime.onMessage" : Send response before create new tab [duplicate]

This question already has answers here:
Chrome Extension Message passing: response not sent
(3 answers)
Closed 7 years ago.
I have problem with sending response in chrome.notifications.onClicked.addListener.
content_scripts
chrome.runtime.sendMessage({action:'openlink', url:'http://stackoverflow.com'}, function(response) {
console.log(response);
});
background
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if(request && request.action === 'openlink') {
chrome.notifications.create('MyUniqueID',{
type: 'basic',
title: 'Open link',
message: request.url,
iconUrl: 'icon.jpg'
});
chrome.notifications.onClicked.addListener(function('MyUniqueID') {
sendResponse({action:'notification-clicked'}); // <--- This
chrome.tabs.create({url:request.url});
});
}
});
So I was wondering what I did wrong ?
The sendResponse must be used immediately after received the message as a way to reply to the sender: ok I received your message and it's OK, so you continue with your code.
When you need to send a message like in your situation you need to call again the function:
chrome.tabs.sendMessage
This means to have the chrome.runtime.onMessage.addListener in the background and content.
For reference see: Chrome Extension Message Passing
Nah, Just add return true after
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if(request && request.action === 'openlink') {
chrome.notifications.create('MyUniqueID',{
type: 'basic',
title: 'Open link',
message: request.url,
iconUrl: 'icon.jpg'
});
chrome.notifications.onClicked.addListener(function('MyUniqueID') {
sendResponse({action:'notification-clicked'}); // <--- This
chrome.tabs.create({url:request.url});
});
return true;
}
});

Azure Push Notifications with iOS Badges on Cordova/Phonegap

I've got the following code that can send push notifications using Azure Notification Hubs. When a new item is inserted into the database, this code sends a push notification to the devices registered with the tag.
I'm using Ionic/Phonegap for the iOS app and the ngCordova Push Plugin. I want to add badge counts for iOS devices, but I can't seem to find a way to do this. I've tried using the push.apns.send function, but can't get it to work.
Azure Mobile Services
function insert(item, user, request) {
// Execute the request and send notifications.
request.execute({
success: function() {
// Create a template-based payload.
var payload = '{ "message" : "This is my message" }';
push.send("My Tag", payload, {
success: function(pushResponse){
// Send the default response.
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
// Send the an error response.
request.respond(500, { error: pushResponse });
}
});
}
});
}
Phonegap
var iosConfig = {
"badge": true,
"sound": true,
"alert": true
};
$cordovaPush.register(iosConfig).then(function (deviceToken) {
var hub = new NotificationHub(mobileClient);
// This is a template registration.
var template = "{\"aps\":{\"alert\":\"$(message)\"}}";
// Register for notifications.
// (deviceId, ["tag1","tag2"], templateName, templateBody, expiration)
hub.apns.register(deviceToken, myTags, "myTemplate", template, null).done(function () {
// Registered with hub!
}).fail(function (error) {
alert("Failed registering with hub: " + error);
});
}, function (err) {
alert("Registration error: " + err)
});
I've searched through dozens of articles/tutorials and none of them work. Any help would be greatly appreciated.
I finally figured it out. The issue was that the template registration needed to include the badge. Here's what works:
Azure Mobile Services
function insert(item, user, request) {
// Execute the request and send notifications.
request.execute({
success: function() {
// Create a template-based payload.
var payload = '{ "message" : "' + originalMessage + '", "badge" : "100" }';
push.send("My Tag", payload, {
success: function(pushResponse){
// Send the default response.
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
// Send the an error response.
request.respond(500, { error: pushResponse });
}
});
}
});
}
Phonegap
var iosConfig = {
"badge": true,
"sound": true,
"alert": true
};
$cordovaPush.register(iosConfig).then(function (deviceToken) {
var hub = new NotificationHub(mobileClient);
// This is a template registration.
var template = "{\"aps\":{\"alert\":\"$(message)\",\"badge\":\"#(badge)\" }}";
// Register for notifications.
// (deviceId, ["tag1","tag2"], templateName, templateBody, expiration)
hub.apns.register(deviceToken, myTags, "myTemplate", template, null).done(function () {
// Registered with hub!
}).fail(function (error) {
alert("Failed registering with hub: " + error);
});
}, function (err) {
alert("Registration error: " + err)
});

How to send responses from onMessageExternal Listener?

I am sending a message from a content script to my extension using chrome.runtime.sendMessage.
Content Script:
chrome.runtime.sendMessage(extensionId, {
"some" : "request"
}
},
function(response) {
alert("got response");
}
);
The receiving part in the background script looks like that:
Background Script A
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
console.log("send response");
sendResponse({
"some" : "response"
});
});
This works well: send response is logged to the console of the background page and I receive the alert got response from the content script.
I then introduced some asynchronous JavaScript to the listener:
Background Script B
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
window.crypto.subtle.generateKey({
name: "RSASSA-PKCS1-v1_5",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: {
name: "SHA-256"
}
}, false, ["sign"]).then(function(keyPair) {
console.log("send response");
sendResponse({
"some" : "response"
});
});
});
here the callback is called regularly (meaning, send response is logged to the console of the background page after completion. The content script however never receives the response (i.e. there is no got response alert).
What am I doing wrong here? Why is the responseCallback called in A but not in B? That's exactly what the callback chain is made for or isn't it?
This seems to be a bug/feature in chrome. Apparently you need to return true, otherwise the message channel will be closed:
https://developer.chrome.com/extensions/runtime.html#event-onMessageExternal
This function becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until sendResponse is called).
Adding return true; to the background script like this solves the issue:
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
window.crypto.subtle.generateKey({
name: "RSASSA-PKCS1-v1_5",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: {
name: "SHA-256"
}
}, false, ["sign"]).then(function(keyPair) {
console.log("send response");
sendResponse({
"some" : "response"
});
});
return true;
});

Resources