"Sono stato bocciato a parecchi esami. Un mio amico invece, li ha passati tutti a pieni voti. Ora è ingegnere e lavora in Microsoft. Io sono il proprietario."  - Bill Gates  •  "Se riesco a fare qualcosa in 10 minuti, è perché ho passato anni a studiarlo."  - Bill Gates  •  "Il vostro lavoro riempirà gran parte della vostra vita, e l'unico modo per essere veramente soddisfatti è fare ciò che ritenete sia un grande lavoro."  - Steve Jobs  •  "Siate affamati. Siate folli."  - Steve Jobs  •  

cinque 

ZERO

Creare estensioni Chrome

home / miscellaneous /

Lucio Paolo Asciolla

Senior Full Stack Developer

Possiamo creare un'estensione Chrome con HTML, CSS e JavaScript.

Struttura di un estensione

Ogni estensione di Chrome ha una struttura specifica di file all’interno di una cartella:

  • Cartella/estensione
    • File manifest JSON /estensione/manifest.json
    • File html /estensione/popup.html
    • File css /estensione/style.css
    • File js /estensione/popup.js
    • File icon /estensione/icon.png
    • File service worker /estensione/service-worker.js

File manifest.json

Questo file descrive la tua estensione e contiene le informazioni essenziali per il browser

{
  "manifest_version": 3,
  "name": "La mia Estensione",
  "version": "1.0",
  "description": "Un'estensione Chrome di esempio.",
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  },
    "background": {
       "service_worker": "service-worker.js" 
  },
  "permissions": [
    "storage",
    "activeTab",
    "scripting"
  ]
}

File popup.html

Il popup è ciò che appare quando clicchi sull'icona della tua estensione. Rappresenta il corpo della tua estensione come se fosse la pagina index.html di un sito.

<!DOCTYPE html>
<html lang="it">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Estensione</title>
<!-- Collegamento del file CSS --> 
<link rel="stylesheet" href="styles.css">
</head>
<body>
  <h1>Benvenuto!</h1>
  <button id="actionButton">Esegui Azione</button>
<!-- Collegamento a un file JS chiamato 'script.js' --> 
<script src="script.js"></script>
</body>
</html>

File style.css

Crea un file style.css per definire lo stile dell'estensione. Come visibile nell’esempio qui sopra il file style e collegato all’interno del file html.

body {
  font-family: Arial, sans-serif;
  padding: 10px;
  width: 200px;
}
h1 {
  color: #4CAF50;
}
button {
  padding: 10px;
  background-color: #4CAF50;
  color: white;
  border: none;
  cursor: pointer;
}

File script.js

Infine, puoi scrivere la logica per l'interazione in un file script.js.

Anche nel caso del file script questo è collegato sempre manualmente all’interno del file html.

document.getElementById('actionButton').addEventListener('click', () => {
  alert('Azione eseguita!');
});

File icon.png

Sere per visualizzare l'icona della tua estensione nella barra degli strumenti.

File service-worker.js

Se vogliamo utilizzare un service worker per gestire il background (come richiesto da Manifest V3), specifichiamo il relativo file js nel campo background del del file manifest.json

Un service worker è uno script javascript eseguito su un thread separato rispetto a quello principlae che il browser esegue in background.
È una delle tecnologie chiave per le Progressive Web App (PWA), ma viene utilizzato anche nelle estensioni di Chrome (in particolare a partire da Manifest V3).
I service worker forniscono funzionalità avanzate come il caching, la sincronizzazione in background e la gestione delle notifiche push, anche quando la pagina o l'applicazione non è attiva.

Il service worker non ha accesso diretto al DOM della pagina e viene eseguito in un contesto separato in background. Questo significa che può essere utilizzato per eseguire attività come la gestione della cache o il recupero di dati dalla rete, anche quando la pagina non è aperta.

I service worker possono intercettare le richieste di rete della tua applicazione e rispondere con contenuti presi dalla cache o dalla rete stessa. Questo permette di creare esperienze offline o migliorare le performance caricando contenuti da una cache locale.

SW Event-driven (basato su eventi)

Il service worker reagisce a eventi come richieste di rete (fetch), messaggi in arrivo o sincronizzazioni in background.

Ecco alcuni eventi principali che un service worker può gestire:

  • install: Viene eseguito quando il service worker viene installato per la prima volta.
  • activate: Viene eseguito quando il service worker viene attivato.
  • fetch: Viene eseguito ogni volta che la pagina fa una richiesta di rete, permettendo di intercettare e rispondere con contenuti dalla cache o dalla rete.

I SW sono persistenti tra sessioni. Anche se l'utente chiude il browser, il service worker può continuare a funzionare in background per compiti specifici, come le notifiche push o la sincronizzazione dei dati.

I service worker funzionano solo su connessioni sicure (HTTPS), poiché hanno il potere di intercettare tutto il traffico di rete della tua app

Esempio di un file service-worker.js

Ecco un esempio base di un service worker che cache alcune risorse durante l'installazione e le serve dalla cache durante le richieste di rete:

// Versione della cache
const CACHE_NAME = 'v1';
// Risorse da mettere in cache
const ASSETS_TO_CACHE = [
  '/',
  '/index.html',
  '/styles.css',
  '/script.js',
  '/icon.png'
];

// Evento di installazione
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      console.log('Aggiungo risorse alla cache');
      return cache.addAll(ASSETS_TO_CACHE);
    })
  );
});

// Evento di fetch (intercetta le richieste di rete)
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      // Se la risorsa è nella cache, la restituisco dalla cache
      return response || fetch(event.request);
    })
  );
});

// Evento di attivazione
self.addEventListener('activate', event => {
  // Rimuovo le vecchie cache
  const cacheWhitelist = [CACHE_NAME];
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (!cacheWhitelist.includes(cacheName)) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

Utilizzo SW in Chrome Extension e PWA

Un service worker in una PWA è utilizzato principalmente per il caching delle risorse, la sincronizzazione in background, e le notifiche push. Lavora con l'obiettivo di migliorare l'esperienza utente offline e la performance generale.

Un service worker in un'estensione Chrome (Manifest V3) viene utilizzato per eseguire attività in background come la gestione delle schede, l'interazione con il browser e altre funzioni definite dall'estensione. Non gestisce direttamente il caching delle risorse come nelle PWA.

Caricare un estensione

Di seguito i passaggi per caricare un'estensione chrome:

  1. Apri Chrome e vai su chrome://extensions
  2. Abilita la modalità Sviluppatore (Developer mode) in alto a destra.
  3. Clicca su Carica estensione non pacchettizzata (Load unpacked) e seleziona la cartella dove hai salvato i tuoi file.
  4. La tua estensione sarà ora attiva e pronta per essere testata

Content scripts e API Chrome

Le estensioni di Chrome non hanno accesso diretto agli elementi hardware del dispositivo, come il file system o le funzionalità di dispositivi mobili, allo stesso modo in cui una Progressive Web App (PWA) potrebbe fare.
Le PWA sono progettate per essere delle applicazioni web installabili con accesso a funzionalità native del dispositivo, come notifiche push, caching offline, accesso alla fotocamera, geolocalizzazione e altro, sfruttando le API web.

Estensioni Chrome vs PWA

Tuttavia, ci sono alcune API che possiamo utilizzare per ottenere un comportamento simile anche per le estensioni di Chrome, ma con delle limitazioni.

Funzionalità del dispositivo:

  • PWA
    Le Progressive Web Apps possono accedere a una vasta gamma di funzionalità hardware attraverso le API Web moderne, come:
  • Geolocalizzazione: per accedere alla posizione del dispositivo.
  • Fotocamera e Microfono: con l'API getUserMedia().
  • Notifiche push: per inviare notifiche anche quando l'app non è attiva.
  • Cache offline: con l'API Service Worker per funzionare offline.
  • Accesso ai file: tramite la File System Access API.
  • Condivisione dei dati: con la Web Share API.
  • Estensioni Chrome
    Le estensioni Chrome possono interagire principalmente con il browser, come la gestione delle schede, il controllo delle richieste di rete, e l'accesso a determinati permessi, ma non hanno accesso diretto all'hardware del dispositivo. Alcuni esempi di API disponibili nelle estensioni includono:
  • Notifiche: con chrome.notifications.create().
  • Storage: con l'API chrome.storage per memorizzare dati a lungo termine.
  • Schede e finestre: gestione delle schede e finestre con chrome.tabs e chrome.windows.
  • Download: gestire i download con chrome.downloads.

PWA Accesso agli elementi del dispositivo

Se desideri creare un'applicazione che possa accedere a elementi hardware del dispositivo, come fotocamera, microfono, o sistema di file, le PWA offrono un'ottima soluzione.

Ecco alcune funzionalità delle PWA con esempi di API:

  1. Accesso alla fotocamera e microfono Puoi usare l'API getUserMedia() per accedere alla fotocamera o al microfono:
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
  .then(stream => {
    // Mostra il video in un elemento video
    const video = document.querySelector('video');
    video.srcObject = stream;
  })
  .catch(error => {
    console.error('Errore nell'accesso alla fotocamera o microfono:', error);
  });
  1.  Accesso al file system La File System Access API permette di leggere e scrivere file locali:
async function openFile() {
  const [fileHandle] = await window.showOpenFilePicker();
  const file = await fileHandle.getFile();
  const contents = await file.text();
  console.log(contents);
}
  1. Geolocalizzazione Usando l'API di geolocalizzazione:
navigator.geolocation.getCurrentPosition(position => {
  console.log(`Latitudine: ${position.coords.latitude}, Longitudine: ${position.coords.longitude}`);
});
  1. Notifiche Push Le PWA possono inviare notifiche anche quando l'applicazione è chiusa o in background, usando i Service Worker
Notification.requestPermission().then(permission => {
  if (permission === 'granted') {
    new Notification('Notifica dalla tua PWA!');
  }
});
  1. Lavorare offline Le PWA possono funzionare offline utilizzando i Service Worker per cache delle risorse.

API Chrome

Le API di Chrome per le estensioni permettono agli sviluppatori di interagire con il browser in modo avanzato, estendendone le funzionalità. Le estensioni di Chrome possono sfruttare queste API per interagire con le schede, modificare l’interfaccia utente, gestire la memoria, salvare dati localmente, comunicare con server remoti e molto altro.

Ecco una panoramica delle principali API offerte da Chrome per le estensioni.

1. chrome.runtime

L'API chrome.runtime è il cuore delle estensioni di Chrome. Gestisce il ciclo di vita dell'estensione e fornisce metodi per monitorare lo stato, comunicare tra componenti dell'estensione e ricevere informazioni sul contesto in cui è in esecuzione.

  • Funzioni principali:
  • chrome.runtime.onInstalled: Evento scatenato quando l'estensione viene installata o aggiornata.
  • chrome.runtime.getManifest(): Restituisce il file manifest.json dell’estensione.
  • chrome.runtime.sendMessage(): Invia messaggi ad altri componenti dell'estensione.
  • chrome.runtime.onMessage: Ascolta i messaggi inviati da altri componenti.

2. chrome.tabs

L'API chrome.tabs permette all'estensione di interagire con le schede del browser, come crearne di nuove, chiuderle, modificarle e ottenere informazioni sulle schede attualmente aperte.

  • Funzioni principali:
  • chrome.tabs.create(): Crea una nuova scheda.
  • chrome.tabs.query(): Ottiene informazioni sulle schede aperte.
  • chrome.tabs.update(): Modifica le proprietà di una scheda (come l’URL).
  • chrome.tabs.onUpdated: Evento che viene lanciato quando una scheda viene aggiornata (ad esempio, caricando una nuova pagina).

3. chrome.storage

L'API chrome.storage consente di salvare e recuperare dati localmente o in modo sincronizzato tra dispositivi. È utilizzata per memorizzare le preferenze dell'utente, dati di configurazione, o altri tipi di informazioni.

  • Tipi di archiviazione:
  • chrome.storage.local: Salva i dati localmente sul dispositivo.
  • chrome.storage.sync: Sincronizza i dati tra i dispositivi utilizzando l'account di Google dell'utente.
  • Funzioni principali:
  • chrome.storage.local.set(): Salva i dati in locale.
  • chrome.storage.local.get(): Recupera i dati locali.
  • chrome.storage.sync.set(): Salva dati sincronizzati.
  • chrome.storage.sync.get(): Recupera dati sincronizzati.

4. chrome.bookmarks

L'API chrome.bookmarks permette all'estensione di interagire con i segnalibri del browser, come creare, eliminare, modificare o recuperare i segnalibri.

  • Funzioni principali:
  • chrome.bookmarks.create(): Crea un nuovo segnalibro.
  • chrome.bookmarks.remove(): Rimuove un segnalibro.
  • chrome.bookmarks.get(): Recupera informazioni sui segnalibri.

5. chrome.history

L'API chrome.history permette di interagire con la cronologia di navigazione dell'utente. Puoi cercare elementi nella cronologia, recuperare dettagli delle visite e rimuovere voci specifiche.

  • Funzioni principali:
  • chrome.history.search(): Cerca elementi nella cronologia.
  • chrome.history.deleteUrl(): Elimina una voce specifica dalla cronologia.
  • chrome.history.addUrl(): Aggiunge una voce alla cronologia di navigazione.

6. chrome.notifications

L'API chrome.notifications consente all'estensione di mostrare notifiche all'utente. Puoi creare notifiche personalizzate con testo, immagini e pulsanti, e gestire eventi associati a tali notifiche.

  • Funzioni principali:
  • chrome.notifications.create(): Crea una nuova notifica.
  • chrome.notifications.clear(): Cancella una notifica.
  • chrome.notifications.onClicked: Evento che si verifica quando l'utente fa clic su una notifica.

7. chrome.alarms

L'API chrome.alarms permette di creare allarmi che eseguono determinate azioni a intervalli specifici o in un momento definito. Questo è utile per eseguire funzioni periodiche o per programmare attività a tempo.

  • Funzioni principali:
  • chrome.alarms.create(): Crea un nuovo allarme.
  • chrome.alarms.onAlarm: Ascolta quando un allarme viene attivato.

8. chrome.contextMenus

L'API chrome.contextMenus consente di aggiungere voci personalizzate al menu contestuale (il menu che appare quando si fa clic con il tasto destro su una pagina o un elemento).

  • Funzioni principali:
  • chrome.contextMenus.create(): Aggiunge una voce al menu contestuale.
  • chrome.contextMenus.remove(): Rimuove una voce dal menu.
  • chrome.contextMenus.onClicked: Evento che si verifica quando una voce del menu viene cliccata.

9. chrome.webRequest

L'API chrome.webRequest permette di osservare, analizzare e potenzialmente modificare le richieste di rete che partono dal browser, come quelle per caricare una pagina o recuperare risorse.

  • Funzioni principali:
  • chrome.webRequest.onBeforeRequest: Intercetta le richieste prima che vengano effettuate.
  • chrome.webRequest.onCompleted: Viene eseguito quando una richiesta è completata.

10. chrome.identity

L'API chrome.identity gestisce l'autenticazione degli utenti con l'account di Google. Può essere utilizzata per ottenere il token di accesso OAuth2 o per identificare l'utente.

  • Funzioni principali:
  • chrome.identity.getAuthToken(): Ottiene il token OAuth2 per l'utente.
  • chrome.identity.getProfileUserInfo(): Recupera informazioni di base sull'utente.

11. chrome.scripting

L'API chrome.scripting (nuova in Manifest V3) è utilizzata per iniettare script nelle pagine web che vengono visualizzate nel browser. Permette di eseguire codice JavaScript in schede o finestre specifiche.

  • Funzioni principali:
  • chrome.scripting.executeScript(): Inietta ed esegue uno script JavaScript in una scheda.

12. chrome.permissions

L'API chrome.permissions permette di richiedere o revocare autorizzazioni specifiche durante il funzionamento dell'estensione.

  • Funzioni principali:
  • chrome.permissions.request(): Richiede una nuova autorizzazione.
  • chrome.permissions.remove(): Revoca un'autorizzazione concessa.

13. chrome.declarativeNetRequest (Manifest V3)

Questa API è stata introdotta con Manifest V3 per la gestione delle regole di rete e il blocco degli URL. Viene utilizzata per definire regole in modo dichiarativo per il blocco o il reindirizzamento di richieste di rete.

  • Funzioni principali:
  • chrome.declarativeNetRequest.updateDynamicRules(): Aggiunge o rimuove regole di blocco/reindirizzamento.

14. chrome.cookies

L'API chrome.cookies permette all'estensione di leggere, creare o rimuovere cookie dal browser.

  • Funzioni principali:
  • chrome.cookies.get(): Recupera informazioni su un cookie specifico.
  • chrome.cookies.set(): Crea un cookie.
  • chrome.cookies.remove(): Rimuove un cookie.

15. chrome.devtools

L'API chrome.devtools permette di interagire con gli strumenti di sviluppo di Chrome (DevTools). Le estensioni possono aggiungere pannelli, sidebar e altre interfacce all'interno degli strumenti di sviluppo.

Content scripts

I Content Scripts sono file JavaScript che vengono eseguiti in un contesto isolato in una pagina web. Possono manipolare il DOM della pagina, leggere il contenuto della pagina e interagire con essa, ma non possono accedere direttamente agli oggetti JavaScript nativi della pagina (come window, document o variabili globali). Hanno, invece, accesso a un ambiente sicuro che consente loro di operare senza interferire con lo script della pagina.

Funzionalità principali dei Content Scripts:

  1. Manipolazione del DOM: Puoi utilizzare i Content Scripts per modificare dinamicamente il contenuto della pagina, aggiungendo o rimuovendo elementi HTML, cambiando il testo, le immagini o qualsiasi altro contenuto DOM.
  2. Iniezione di codice CSS e JS: Puoi aggiungere stili CSS o script aggiuntivi per personalizzare ulteriormente l'aspetto o il comportamento della pagina web su cui l'estensione è attiva.
  3. Lettura del contenuto della pagina: I Content Scripts possono leggere il contenuto della pagina in cui sono iniettati, il che è utile per estensioni che analizzano o estraggono dati dalla pagina.
  4. Comunicazione con altre parti dell’estensione: Anche se i Content Scripts sono isolati dal contesto della pagina web, possono comunicare con altre parti dell'estensione (ad esempio, il background script o il popup) tramite messaggi.

Iniezione dei Content Scripts

I file content script possono essere iniettati automaticamente mediante il file manifest.json o manualmente mediante API Chrome

Iniezione con manifest.json

Nell’esempio che segue il Content Script content.js viene eseguito automaticamente su tutte le pagine il cui URL corrisponde al dominio example.com.

Possiamo anche specificare file CSS che verranno iniettati per modificare l’aspetto della pagina (styles.css).

{
  "name": "Example Extension",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": ["tabs"],
  "content_scripts": [
    {
      "matches": ["https://*.example.com/*"],
      "js": ["content.js"],
      "css": ["styles.css"]
    }
  ]
}

Iniezione manuale tramite API Chrome

I Content Scripts possono anche essere iniettati manualmente tramite API Chrome. Questo è utile quando vuoi iniettare il Content Script in risposta a un evento o un'azione specifica.

chrome.scripting.executeScript({
  target: {tabId: tabId},
  files: ['content.js']
});

Isolamento e comunicazione dei Content Scripts

I Content Scripts vengono eseguiti in un ambiente isolato. Questo significa che:

  • I Content Scripts non possono accedere direttamente al contesto JavaScript della pagina (variabili, funzioni globali, ecc.). Tuttavia, possono accedere e manipolare il DOM della pagina.
  • La comunicazione tra il Content Script e la pagina può essere realizzata tramite messaggi o iniezione diretta di script nel contesto della pagina.

Esempio di come un Content Script può iniettare uno script nel contesto della pagina:

let script = document.createElement('script');
script.src = chrome.runtime.getURL('injected-script.js');
(document.head || document.documentElement).appendChild(script);

I Content Scripts non possono direttamente accedere agli altri script dell'estensione (ad esempio, il background script o popup), ma possono comunicare con essi utilizzando un sistema di messaggistica della API Chrome.

Esempio di invio di un messaggio dal Content Script al background script:

file content.js

chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response.farewell);
});

file service-worker.js

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.greeting === "hello") {
sendResponse({farewell: "goodbye"});
}
});

Accesso limitato all’API di Chrome: I Content Scripts hanno accesso a un sottoinsieme ristretto delle API di Chrome. Non possono, ad esempio, usare API che richiedono permessi di alto livello, come chrome.tabs o chrome.windows

Pratica

All’atto pratico dovremo avere questi file con qualcosa del genere all’interno:

Un file index.html con collegati un file script.js e un style.css
Il file script.js si occupa di gestire le interazioni con l’interfaccia dell’estensione stessa.
Quindi i click su eventuali bottoni ecc.

Un file manifest.json dove dichiariamo un service-worker e un content-script.

Ora, il compito di comunicare con una pagina che stiamo visualizzando, di fatto,  è  del content-script.js
Il nostro obiettivo è far dialogare script.js con content-script.js. in seguito a delle azioni sull’interfaccia dell’estensione.

Il content-script è l'unico che può eseguire delle azioni con la pagina corrente.
Possiamo comandarlo mediante uno scampio di messaggi tra script.js e lo stesso.

Il service-worker.js allo stato attuale lo utilizzeremo per far iniettare il content-script seppur potrebbe indurre errori in quanto in content-script nell’esempio che forniremo è già collegato mediante il file manifest.

Web scraping

https://www.qapla.it/blog/customer-experience/web-scraping/#:~:text=Letteralmente%20%E2%80%9Cscraping%E2%80%9D%20significa%20%E2%80%9Cgrattare,spesso%20simulano%20la%20navigazione%20umana