Если вы хотите получить информацию о геолокации в своем расширении Chrome, используйте тот же API веб-платформы navigator.geolocation
, который обычно используется на любом веб-сайте. Эта статья существует, поскольку расширения Chrome обрабатывают разрешения на доступ к конфиденциальным данным иначе, чем веб-сайты. Геолокация — это очень конфиденциальные данные, поэтому браузеры гарантируют, что пользователи полностью осведомлены и контролируют, когда и где передается их точное местоположение.
Используйте геолокацию в расширениях MV3
В Интернете браузеры защищают данные о геолокации пользователей, показывая запрос на предоставление этому конкретному источнику доступа к их местоположению. Одна и та же модель разрешений не всегда подходит для расширений.

Разрешения — не единственное отличие. Как упоминалось выше, navigator.geolocation
— это DOM API, то есть часть API, из которых состоят веб-сайты. В результате он недоступен внутри рабочих контекстов, например , рабочий процесс службы расширений , который является основой расширений манифеста v3. Однако вы все равно можете использовать geolocation
. Просто есть нюансы с тем, как и где его использовать.
Используйте геолокацию в сервис-воркерах
Внутри сервис-воркеров нет объекта navigator
. Он доступен только внутри контекстов, имеющих доступ к объекту document
страницы. Чтобы получить доступ внутри сервис-воркера, используйте Offscreen Document
, который предоставляет доступ к HTML-файлу, который вы можете связать с вашим расширением.
Для начала добавьте "offscreen"
в раздел "permissions"
манифеста.
манифест.json:
{ "name": "My extension", ... "permissions": [ ... "offscreen" ], ... }
После добавления разрешения "offscreen"
добавьте в расширение HTML-файл, содержащий ваш закадровый документ. В этом случае не используется содержимое страницы, поэтому это может быть почти пустой файл. Это просто должен быть небольшой HTML-файл, который загружается в ваш скрипт.
offscreen.html:
<!doctype html> <title>offscreenDocument</title> <script src="offscreen.js"></script>
Сохраните этот файл в корне вашего проекта как offscreen.html
.
Как уже упоминалось, вам понадобится скрипт offscreen.js
. Вам также необходимо связать это с вашим расширением. Это будет источник информации о геолокации для сервисного работника. Вы можете передавать сообщения между ним и вашим сервис-воркером.
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) ); }); }
Теперь вы готовы получить доступ к закадровому документу в сервис-воркере.
chrome.offscreen.createDocument({ url: 'offscreen.html', reasons: [chrome.offscreen.Reason.GEOLOCATION || chrome.offscreen.Reason.DOM_SCRAPING], justification: 'geolocation access', });
Обратите внимание: при доступе к закадровому документу вам необходимо указать reason
. Причина geolocation
изначально не была доступна, поэтому укажите запасной вариант DOM_SCRAPING
и объясните в разделе justification
, что на самом деле делает код. Эта информация используется в процессе проверки Интернет-магазина Chrome, чтобы гарантировать, что закадровые документы используются в законных целях.
Получив ссылку на внеэкранный документ, вы можете отправить ему сообщение с просьбой предоставить вам обновленную информацию о геолокации.
сервис_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(); }
Итак, теперь, когда вы захотите получить геолокацию от своего сервис-воркера, вам просто нужно позвонить:
const location = await getGeolocation()
Используйте геолокацию во всплывающем окне или на боковой панели
Использовать геолокацию во всплывающем окне или боковой панели очень просто. Всплывающие окна и боковые панели — это просто веб-документы, поэтому они имеют доступ к обычным API-интерфейсам DOM. Вы можете получить прямой доступ к navigator.geolocation
. Единственное отличие от стандартных веб-сайтов заключается в том, что вам необходимо использовать поле "permission"
в файле manifest.json
для запроса разрешения "geolocation"
. Если вы не включите разрешение, у вас все равно будет доступ к navigator.geolocation
. Однако любая попытка его использования приведет к немедленной ошибке, как если бы пользователь отклонил запрос. Вы можете увидеть это в образце всплывающего окна .
Использование геолокации в скрипте контента
Как и всплывающее окно, сценарий контента имеет полный доступ к DOM API; однако пользователи будут проходить обычный процесс получения разрешений пользователя. Это означает, что добавление "geolocation"
к вашим "permissions"
не предоставит вам автоматически доступ к информации о геолокации пользователей. Вы можете увидеть это в примере сценария контента .