Utiliser la géolocalisation

Si vous souhaitez obtenir des informations de géolocalisation dans votre extension Chrome, utilisez la même API de plate-forme Web navigator.geolocation que n'importe quel site Web. Cet article existe, car les extensions Chrome gèrent différemment l'autorisation d'accès aux données sensibles de celle des sites Web. La géolocalisation est une donnée très sensible. Les navigateurs veillent donc à ce que les utilisateurs soient parfaitement au courant et puissent contrôler où et quand leur position exacte est partagée.

Utiliser la géolocalisation dans les extensions MV3

Sur le Web, les navigateurs protègent les utilisateurs les données de géolocalisation. Un modèle d'autorisation identique n'est pas toujours approprié pour les extensions.

<ph type="x-smartling-placeholder">
</ph> Capture d&#39;écran de l&#39;invite d&#39;autorisation qui s&#39;affiche lorsqu&#39;un site Web demande l&#39;accès à l&#39;API de géolocalisation
Invite d'autorisation de géolocalisation
.

Les autorisations ne sont pas la seule différence. Comme indiqué ci-dessus, navigator.geolocation est une API DOM, c'est-à-dire un élément qui fait partie des API qui composent les sites Web. Par conséquent, il n'est pas accessible dans les contextes de nœuds de calcul, comme le service worker d'extension qui est la colonne vertébrale des extensions Manifest V3. Toutefois, vous pouvez continuer à utiliser geolocation. Il existe des nuances quant à la façon et au lieu de l'utiliser.

Utiliser la géolocalisation dans les service workers

Les service workers ne contiennent aucun objet navigator. Elle n'est disponible que dans les contextes ayant accès à l'objet document d'une page. Pour obtenir un accès au sein d'un service worker, utilisez un Offscreen Document, qui permet d'accéder à un fichier HTML que vous pouvez associer à votre extension.

Pour commencer, ajoutez "offscreen" à la section "permissions" de votre fichier manifeste.

manifest.json:

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

Après avoir ajouté l'autorisation "offscreen", ajoutez un fichier HTML à votre extension qui inclut votre document hors écran. Dans le cas présent, le contenu de la page n'est pas utilisé. Il peut donc s'agir d'un fichier presque vide. Il suffit d'un petit fichier HTML chargé dans votre script.

offscreen.html:

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

Enregistrez ce fichier à la racine de votre projet sous le nom offscreen.html.

Comme indiqué précédemment, vous avez besoin d'un script appelé offscreen.js. Vous devez également l'associer à votre extension. Il s'agit de la source des informations de géolocalisation du service worker. Vous pouvez transmettre des messages entre celui-ci et votre 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)
    );
  });
}

Une fois que c'est fait, vous pouvez accéder au document hors écran dans le service worker.

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

Notez que lorsque vous accédez à un document hors écran, vous devez inclure un reason. Le motif geolocation n'était pas disponible à l'origine. Vous devez donc spécifier une valeur de remplacement pour DOM_SCRAPING et expliquer dans la section justification ce que fait réellement le code. Ces informations sont utilisées par le processus d'examen du Chrome Web Store pour s'assurer que les documents hors écran sont utilisés à des fins valides.

Une fois que vous disposez d'une référence au document hors écran, vous pouvez lui envoyer un message pour lui demander de vous fournir des informations de géolocalisation à jour.

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

Désormais, chaque fois que vous souhaitez obtenir la géolocalisation de votre service worker, il vous suffit d'appeler la commande suivante:

const location = await getGeolocation()

Utiliser la géolocalisation dans un pop-up ou un panneau latéral

L'utilisation de la géolocalisation dans un pop-up ou dans un panneau latéral est très simple. Les fenêtres pop-up et les panneaux latéraux ne sont que des documents Web et ont donc accès aux API DOM normales. Vous pouvez accéder directement à navigator.geolocation. La seule différence par rapport aux sites Web standards est que vous devez utiliser le champ manifest.json "permission" pour demander l'autorisation "geolocation". Si vous ne donnez pas cette autorisation, vous aurez toujours accès à navigator.geolocation. Cependant, toute tentative d'utilisation de ce paramètre entraînera une erreur immédiate, comme si l'utilisateur avait rejeté la requête. Vous pouvez le voir dans l'exemple de pop-up.

Utiliser la géolocalisation dans un script de contenu

Tout comme les fenêtres pop-up, un script de contenu dispose d'un accès complet à l'API DOM. les utilisateurs devront cependant suivre le flux normal d'autorisation de l'utilisateur. Cela signifie que l'ajout de "geolocation" à votre "permissions" ne vous donnera pas automatiquement accès aux des informations de géolocalisation. Vous pouvez le voir dans l'exemple de script de contenu.