Utilizza geolocalizzazione

Se vuoi ricevere informazioni di geolocalizzazione nell'estensione di Chrome, usa la stessa API della piattaforma web di navigator.geolocation utilizzata normalmente da qualsiasi sito web. Questo articolo esiste perché le estensioni di Chrome gestiscono l'autorizzazione ad accedere ai dati sensibili in modo diverso rispetto ai siti web. La geolocalizzazione è un dato molto sensibile, quindi i browser fanno in modo che gli utenti siano pienamente consapevoli e possano controllare quando e dove viene condivisa la loro esatta posizione.

Utilizza la geolocalizzazione nelle estensioni MV3

Sul Web, i browser proteggono i dati di geolocalizzazione degli utenti mostrando una richiesta di autorizzazione per l'accesso alla loro posizione all'origine specifica. Lo stesso modello di autorizzazione non è sempre appropriato per le estensioni.

Uno screenshot della richiesta di autorizzazione visualizzata quando un sito web richiede l'accesso all'API di geolocalizzazione.
La richiesta di autorizzazione di geolocalizzazione

Le autorizzazioni non sono l'unica differenza. Come accennato in precedenza, navigator.geolocation è un'API DOM, ovvero un componente delle API che compongono i siti web. Di conseguenza, non è accessibile all'interno dei contesti worker, come il service worker delle estensioni, che è la spina dorsale delle estensioni manifest v3. Tuttavia, puoi assolutamente utilizzare geolocation. Ci sono solo sfumature relative a come e dove utilizzarlo.

Utilizzo della geolocalizzazione nei service worker

Nessun oggetto navigator all'interno dei service worker. È disponibile solo all'interno di contesti che hanno accesso all'oggetto document di una pagina. Per ottenere l'accesso all'interno di un service worker, usa Offscreen Document, che consente di accedere a un file HTML che puoi raggruppare con l'estensione.

Per iniziare, aggiungi "offscreen" alla sezione "permissions" del tuo file manifest.

manifest.json:

{
  "name": "My extension",
    ...
  "permissions": [
    ...
   "offscreen"
  ],
  ...
}

Dopo aver aggiunto l'autorizzazione "offscreen", aggiungi un file HTML all'estensione che includa il documento fuori schermo. Questo caso non utilizza i contenuti della pagina, pertanto il file potrebbe essere quasi vuoto. Deve solo essere un piccolo file HTML che venga caricato nello script.

offscreen.html:

<!doctype html>
<title>offscreenDocument</title>
<script src="offscreen.js"></script>

Salva questo file nella directory principale del progetto con il nome offscreen.html.

Come accennato, è necessario uno script chiamato offscreen.js. Dovrai anche associarlo all'estensione. Sarà la fonte delle informazioni di geolocalizzazione del service worker. Puoi trasferire messaggi tra il dispositivo e il service worker.

offscreen.js:

chrome.runtime.onMessage.addListener(handleMessages);
function handleMessages(message, sender, sendResponse) {
  // Return early if this message isn't meant for the offscreen document.
  if (message.target !== 'offscreen') {
    return;
  }

  if (message.type !== 'get-geolocation') {
    console.warn(`Unexpected message type received: '${message.type}'.`);
    return;
  }

  // You can directly respond to the message from the service worker with the
  // provided `sendResponse()` callback. But in order to be able to send an async
  // response, you need to explicitly return `true` in the onMessage handler
  // As a result, you can't use async/await here. You'd implicitly return a Promise.
  getLocation().then((loc) => sendResponse(loc));

  return true;
}

// getCurrentPosition() returns a prototype-based object, so the properties
// end up being stripped off when sent to the service worker. To get
// around this, create a deep clone.
function clone(obj) {
  const copy = {};
  // Return the value of any non true object (typeof(null) is "object") directly.
  // null will throw an error if you try to for/in it. Just return
  // the value early.
  if (obj === null || !(obj instanceof Object)) {
    return obj;
  } else {
    for (const p in obj) {
      copy[p] = clone(obj[p]);
    }
  }
  return copy;
}

async function getLocation() {
  // Use a raw Promise here so you can pass `resolve` and `reject` into the
  // callbacks for getCurrentPosition().
  return new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(
      (loc) => resolve(clone(loc)),
      // in case the user doesnt have/is blocking `geolocation`
      (err) => reject(err)
    );
  });
}

Una volta impostato, puoi accedere al documento Offscreen nel Service worker.

chrome.offscreen.createDocument({
  url: 'offscreen.html',
  reasons: [chrome.offscreen.Reason.GEOLOCATION || chrome.offscreen.Reason.DOM_SCRAPING],
  justification: 'geolocation access',
});

Tieni presente che quando accedi a un documento fuori schermo, devi includere un reason. Il motivo geolocation non era disponibile in origine, quindi specifica un valore di riserva di DOM_SCRAPING e spiega nella sezione justification cosa sta facendo effettivamente il codice. Queste informazioni vengono utilizzate dalla procedura di revisione del Chrome Web Store per garantire che i documenti fuori schermo vengano utilizzati per uno scopo valido.

Una volta ottenuto un riferimento al documento fuori schermo, puoi inviargli un messaggio per chiedergli di fornirti informazioni di geolocalizzazione aggiornate.

.

service_worker.js:

const OFFSCREEN_DOCUMENT_PATH = '/offscreen.html';
let creating; // A global promise to avoid concurrency issues

chrome.runtime.onMessage.addListener(handleMessages);

async function getGeolocation() {
  await setupOffscreenDocument(OFFSCREEN_DOCUMENT_PATH);
  const geolocation = await chrome.runtime.sendMessage({
    type: 'get-geolocation',
    target: 'offscreen'
  });
  await closeOffscreenDocument();
  return geolocation;
}

async function hasDocument() {
  // Check all windows controlled by the service worker to see if one
  // of them is the offscreen document with the given path
  const offscreenUrl = chrome.runtime.getURL(OFFSCREEN_DOCUMENT_PATH);
  const matchedClients = await clients.matchAll();

  return matchedClients.some(c => c.url === offscreenUrl)
}

async function setupOffscreenDocument(path) {
  //if we do not have a document, we are already setup and can skip
  if (!(await hasDocument())) {
    // create offscreen document
    if (creating) {
      await creating;
    } else {
      creating = chrome.offscreen.createDocument({
        url: path,
        reasons: [chrome.offscreen.Reason.GEOLOCATION || chrome.offscreen.Reason.DOM_SCRAPING],
        justification: 'add justification for geolocation use here',
      });

      await creating;
      creating = null;
    }
  }
}

async function closeOffscreenDocument() {
  if (!(await hasDocument())) {
    return;
  }
  await chrome.offscreen.closeDocument();
}

Ogni volta che vuoi ottenere la geolocalizzazione dal tuo service worker, devi semplicemente chiamare:

const location = await getGeolocation()

Usa la geolocalizzazione in un popup o in un riquadro laterale

L'uso della geolocalizzazione in un popup o in un riquadro laterale è molto semplice. I popup e i riquadri laterali sono solo documenti web e pertanto hanno accesso alle normali API DOM. Puoi accedere direttamente a navigator.geolocation. L'unica differenza rispetto ai siti web standard è che devi utilizzare il campo manifest.json "permission" per richiedere l'autorizzazione "geolocation". Se non includi l'autorizzazione, avrai comunque accesso a navigator.geolocation. Tuttavia, qualsiasi tentativo di utilizzo causerà un errore immediato, come se l'utente avesse rifiutato la richiesta. Puoi verificarlo nell'esempio popup.

Utilizzare la geolocalizzazione in uno script di contenuti

Proprio come un popup, uno script di contenuti ha accesso completo all'API DOM; tuttavia, gli utenti seguiranno il normale flusso di autorizzazioni utente. Ciò significa che l'aggiunta di "geolocation" a "permissions" non ti consente di accedere automaticamente alle informazioni di geolocalizzazione degli utenti. Puoi trovare queste informazioni nell'esempio di script dei contenuti.