Gebruik geolocatie

Als u geolocatie-informatie in uw Chrome-extensie wilt ontvangen, gebruikt u dezelfde navigator.geolocation webplatform-API die elke website normaal gesproken zou gebruiken. Dit artikel bestaat omdat Chrome-extensies anders omgaan met toestemming voor toegang tot gevoelige gegevens dan websites. Geolocatie is zeer gevoelige gegevens, dus browsers zorgen ervoor dat gebruikers volledig op de hoogte zijn en controle hebben over wanneer en waar hun exacte locatie wordt gedeeld.

Gebruik geolocatie in MV3-extensies

Op internet beveiligen browsers de geolocatiegegevens van gebruikers door een prompt weer te geven waarin hen wordt gevraagd die specifieke herkomst toegang tot hun locatie te verlenen. Hetzelfde toestemmingsmodel is niet altijd geschikt voor extensies.

Een screenshot van de toestemmingsprompt die u ziet wanneer een website toegang vraagt ​​tot de geolocatie-API
De toestemmingsprompt voor geolocatie

Machtigingen zijn niet het enige verschil. Zoals hierboven vermeld, is navigator.geolocation een DOM API, dat wil zeggen iets dat deel uitmaakt van de API's waaruit websites bestaan. Als gevolg hiervan is het niet toegankelijk binnen werkcontexten, zoals de uitbreidingsservicewerknemer die de ruggengraat vormt van manifest v3-extensies. Je kunt echter absoluut nog steeds gebruik maken van geolocation . Er zijn slechts nuances met hoe en waar u het gebruikt.

Gebruik geolocatie bij servicemedewerkers

Er bevindt zich geen navigator in servicemedewerkers. Het is alleen beschikbaar binnen contexten die toegang hebben tot het document van een pagina. Om toegang te krijgen tot een servicemedewerker, gebruikt u een Offscreen Document , dat toegang biedt tot een HTML-bestand dat u kunt bundelen met uw extensie.

Om aan de slag te gaan, voegt u "offscreen" toe aan de sectie "permissions" van uw manifest.

manifest.json:

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

Nadat u de machtiging "offscreen" hebt toegevoegd, voegt u een HTML-bestand toe aan uw extensie dat uw offscreen-document bevat. In dit geval wordt niets van de inhoud van de pagina gebruikt, dus dit kan een vrijwel leeg bestand zijn. Het hoeft alleen maar een klein HTML-bestand te zijn dat in uw script wordt geladen.

offscreen.html:

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

Sla dit bestand op in de hoofdmap van uw project als offscreen.html .

Zoals gezegd heb je een script nodig met de naam offscreen.js . U moet dit ook bundelen met uw extensie. Het zal de bron van geolocatie-informatie voor de servicemedewerker zijn. U kunt berichten doorgeven aan uw servicemedewerker.

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)
    );
  });
}

Nu dat is gebeurd, bent u nu klaar om toegang te krijgen tot het Offscreen-document in de servicemedewerker.

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

Houd er rekening mee dat wanneer u een document buiten het scherm opent, u een reason moet opgeven. De geolocation was oorspronkelijk niet beschikbaar, dus specificeer een fallback van DOM_SCRAPING en leg in de justification uit wat de code feitelijk doet. Deze informatie wordt gebruikt door het beoordelingsproces van de Chrome Web Store om ervoor te zorgen dat documenten buiten het scherm voor een geldig doel worden gebruikt.

Zodra u een verwijzing naar het Offscreen-document heeft, kunt u het een bericht sturen om u te vragen om bijgewerkte geolocatie-informatie.

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();
}

Dus wanneer u nu de geolocatie van uw servicemedewerker wilt krijgen, hoeft u alleen maar te bellen:

const location = await getGeolocation()

Gebruik geolocatie in een pop-up of zijpaneel

Het gebruik van geolocatie binnen een pop-up of zijpaneel is heel eenvoudig. Pop-ups en zijpanelen zijn slechts webdocumenten en hebben daarom toegang tot de normale DOM API's. U heeft rechtstreeks toegang tot navigator.geolocation . Het enige verschil met standaardwebsites is dat u het manifest.json veld "permission" moet gebruiken om de toestemming "geolocation" aan te vragen. Als u de toestemming niet opneemt, heeft u nog steeds toegang tot navigator.geolocation . Elke poging om het te gebruiken zal echter een onmiddellijke fout veroorzaken, net alsof de gebruiker het verzoek heeft afgewezen. U kunt dit zien in het pop-upvoorbeeld .

Geolocatie gebruiken in een inhoudsscript

Net als een pop-up heeft een inhoudsscript volledige toegang tot de DOM API; Gebruikers doorlopen echter de normale gebruikersmachtigingsstroom. Dat betekent dat het toevoegen van "geolocation" aan uw "permissions" u niet automatisch toegang geeft tot de geolocatie-informatie van de gebruikers. U kunt dit zien in het inhoudsscriptvoorbeeld .