1

I need to check when the extension is installed and change my React state accordingly. I use chrome.runtime.onInstalled on my background.js where I sendMessage to my react code - which is the content script of my extension.

background.js

 async function getCurrentTab() {
  let queryOptions = { active: true, currentWindow: true };
  let [tab] = await chrome.tabs.query(queryOptions);
  return tab;
}
chrome.runtime.onInstalled.addListener((details) => {
  if (details?.reason === 'install') {
    console.log('installed backgroundjs')

    const tab = await getCurrentTab()
   chrome.tabs.sendMessage(tab.id, { target: 'onInstall' })
    openNewTab()
   }
 })

In my react Component - Dashboard.js

useEffect(() => {
    if (extensionApiObject?.runtime) {
      chrome.runtime.sendMessage({ target: 'background', message: 'check_installation', })

      console.log('extension')
      chrome.runtime.onMessage.addListener(handleMessage)
    }


    return () => {
      if (extensionApiObject?.runtime) {
        chrome.runtime.onMessage.removeListener(handleMessage)
      }
    }
  })

function handleMessage(msg) {
    console.log('handle messag func', msg)

    if (msg.target === 'onInstall') {
      console.log('extension on Install')
      setShowWelcomeMessage(true)
    }
  }

What confuse me is that I already have a similar implementation for a different message that works without problem but in there I listen to chrome.runtime.onMessage() not chrome.runtime.onInstalled()

I wonder if I misunderstand how onInstalled method work and I cannot sendMessage from it?

UPDATE: I change my code as suggested by @wOxxOm, I used chrome.tabs.sendMessage but still no luck.

chrome.runtime.onInstalled doesn't take as argument req, sender, sendResponse like other listener and I wonder if that means it will not be able to send a message from there :/

Giorgia Sambrotta
  • 1,133
  • 1
  • 15
  • 45
  • chrome.runtime.sendMessage sends to extension's own pages. To send to a web page you need chrome.tabs.sendMessage with a tab id. The id can be obtained via chrome.tabs.query. – wOxxOm Sep 23 '21 at 11:04
  • Thank you for your answer @wOxxOm! Ah wait, I think I messed up in the explanation. I'm indeed communicating with my extension, not an external web app. So I'm sending from backgrodun.js to content script. Everything in the context of the same extension. – Giorgia Sambrotta Sep 23 '21 at 11:09
  • Content scripts run in web pages so my comment still applies. – wOxxOm Sep 23 '21 at 11:11
  • thank you! Awesome, i will try with tabs and let you know :) – Giorgia Sambrotta Sep 23 '21 at 11:15
  • @wOxxOm still not working :( I edited my question, if you want to have a look :) – Giorgia Sambrotta Sep 23 '21 at 18:25
  • Also, I'm still wondering.. I can use chrome.runtime.sendMessage from my backgroundjs, but just in chrome.runtime.onMessage.addListener, after I have fire it, sending a message from my content script! :/ – Giorgia Sambrotta Sep 23 '21 at 18:37
  • Right after the extension is installed the content scripts won't run until you reload the tab(s) or reinject the content scripts explicitly, see [this topic](https://stackoverflow.com/questions/10994324/chrome-extension-content-script-re-injection-after-upgrade-or-install). – wOxxOm Sep 23 '21 at 18:55
  • ahhh! Thanks, that make sense – Giorgia Sambrotta Sep 23 '21 at 19:00
  • @wOxxOm some stuff I'm still wonrdering after your suggestions: 1. chrom.runtime.sednMessage works from backgroundjs to content-script, if used inside chrome.runtime.onMessage 2. i think my content script run after the extension is installed, I have some console log in my React app and I can see them. Also they re-run everytime a component state gets update. So the problem is the onInstall in it self. – Giorgia Sambrotta Sep 24 '21 at 10:59
  • In the SO topic you linked me, they suggest to reinject content script like so: chrome.manifest.content_scripts[0].js; but I do not have my content script in the manifest.json since is a react app that gets call in – Giorgia Sambrotta Sep 24 '21 at 10:59
  • If you don't have a content script then this entire method won't work. To be able to send a message from the background script to the web page you need a content script. The content script's onMessage will receive sendMessage from the background script and then send a standard DOM event to the react app. You can inject a content script from onInstalled by using chrome.tabs.executeScript (MV2) or chrome.scripting.executeScript (MV3). – wOxxOm Sep 24 '21 at 11:07
  • mhmm my understanding is that content script is a way to communicate with an external webpage. In the doc https://developer.chrome.com/docs/extensions/mv3/content_scripts/#static-declarative under matches: [] there is an array of urls where the content script is allow to be injected. I have no urls to add there, because the script should run in my extension code. If you think is more easy to have a look at the full code, here is the link: https://github.com/ElliotForWater/elliot-dashboard – Giorgia Sambrotta Sep 24 '21 at 13:50
  • I probably confuse you when I re-wrote the title saying content-script. Sorry, I'm new to extension development and all the terminology is new to me. I actually mean I need to send the message to my own extension code. No idea how this is call in technical term – Giorgia Sambrotta Sep 24 '21 at 13:54
  • I don't understand what you want to do. A web page is a web page, it can't be external. If you don't need to run scripts in web pages then you don't need a content script so you should remove `content_scripts`. Note that without actual URLs in `matches` this section was meaningless anyway. If your react app is inside your extension page then it will be able to run only when the extension is installed, obviously, so there's no need for onInstalled. – wOxxOm Sep 24 '21 at 13:54
  • I try again: I have an extension with react app (injected in index.html) and background.js. I need to show a UI to user just on first installation of the extension. All the other time the user use the extension, will not see this UI. I therefor thought to use onInstall to send a message to the react-extension code, to update the UI in react. – Giorgia Sambrotta Sep 24 '21 at 13:57
  • There's no need for messages. Simply open this page inside onInstalled: chrome.tabs.create({url: 'onboarding.html'}) - note that there's no injection here, injection is only for content scripts, here's just an extension page with react app inside. – wOxxOm Sep 24 '21 at 13:59
  • I don't have a simple html page. I have a single page app in react. I don't have routers. I need to update my component state from isFirstTimeInstalled = false to true. So i can do something like {isFirstTimeInstalled ? (
    hello!
    ) : (
    Welcome back
    )} in my react component render function. That's why I thought about sending a message
    – Giorgia Sambrotta Sep 24 '21 at 14:03
  • Use a parameter in the url: chrome.tabs.create({url: 'index.html?install'}) and check it inside the app. – wOxxOm Sep 24 '21 at 14:05
  • Ahhh that worked!! thank you very much for your time and patience @wOxxOm!! If you want to write a proper answer, I will approve it as correct and you get the points :) – Giorgia Sambrotta Sep 24 '21 at 15:55

1 Answers1

1

After @wOxxOm suggestions, I ended up removing the sendMessage solution and simply add an extra parameter to the url whenever I open a new tab after installation:

background.js

function openNewTab(param) {
  chrome.tabs.create({
    url:  param ? `chrome://newtab?${param}` : 'chrome://newtab',
  })
}

chrome.runtime.onInstalled.addListener((details) => {
  if (details?.reason === 'install') {
   chrome.tabs.sendMessage(tab.id, { target: 'onInstall' })
    openNewTab('installed')
   }
 })

on my web app I just need to check the param and I can decide which UI to show

Giorgia Sambrotta
  • 1,133
  • 1
  • 15
  • 45