Coğrafi konumu kullan

Chrome uzantınızda coğrafi konum bilgilerini almak istiyorsanız herhangi bir web sitesinin normalde kullandığı navigator.geolocation Web platformu API'sini kullanın. Bu makale, Chrome uzantıları, hassas verilere erişim iznini web sitelerinden farklı şekilde işlemektedir. Coğrafi konum son derece hassas verilerdir. Bu nedenle tarayıcılar, kullanıcıların tam konumlarının ne zaman ve nerede paylaşıldığını tam olarak bilmesini ve bu verileri kontrol etmesini sağlar.

MV3 uzantılarında coğrafi konumu kullanma

Web'de tarayıcılar, kullanıcıların konumlarına belirli bir kaynağa erişim izni vermelerini isteyen bir istem göstererek coğrafi konum verilerini korur. Aynı izin modeli uzantılar için her zaman uygun değildir.

Bir web sitesi coğrafi konum API'sine erişim istediğinde gördüğünüz izin isteminin ekran görüntüsü
Coğrafi konum izni istemi

Aradaki tek fark izinler değildir. Yukarıda belirtildiği gibi navigator.geolocation, bir DOM API'sidir, diğer bir deyişle web sitelerini oluşturan API'lerin parçası olan bir öğedir. Bu nedenle, manifest v3 uzantılarının omurgası olan uzantı hizmeti çalışanı gibi çalışan bağlamlarının içinden erişilemez. Yine de geolocation kullanmaya devam edebilirsiniz. Yalnızca nasıl ve nerede kullandığınızla ilgili küçük ayrıntılar vardır.

Hizmet çalışanlarında coğrafi konumu kullanma

Service Worker'ların içinde navigator nesnesi yok. Yalnızca sayfanın document nesnesine erişimi olan bağlamlarda kullanılabilir. Hizmet çalışanı alanına erişmek için Offscreen Document kullanın. Bu özellik, uzantınızla paketleyebileceğiniz bir HTML dosyasına erişim sağlar.

Başlamak için "offscreen" öğesini manifest'inizin "permissions" bölümüne ekleyin.

manifest.json:

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

"offscreen" iznini ekledikten sonra, uzantınıza ekran dışı dokümanınızı içeren bir HTML dosyası ekleyin. Bu destek kaydı, sayfanın herhangi bir içeriğini kullanmadığından neredeyse boş bir dosya olabilir. Bunun, komut dosyanızda yüklenen küçük bir HTML dosyası olması yeterlidir.

offscreen.html:

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

Bu dosyayı projenizin kök dizinine offscreen.html olarak kaydedin.

Belirttiğimiz gibi, offscreen.js adında bir komut dosyanız olmalıdır. Ayrıca, bunu uzantınızla birlikte paket haline getirmeniz gerekir. Bu, hizmet çalışanının coğrafi konum bilgisi kaynağı olacaktır. Bu e-posta adresi ile hizmet çalışanınız arasında mesaj aktarabilirsiniz.

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

Bunu yaptıktan sonra, artık hizmet çalışanında Ekran Dışı Doküman'a erişmeye hazırsınız.

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

Ekran dışındaki bir dokümana eriştiğinizde reason eklemeniz gerektiğini unutmayın. geolocation nedeni başlangıçta mevcut değildi. Bu nedenle, DOM_SCRAPING yedeğini belirtin ve justification bölümünde kodun aslında ne yaptığını açıklayın. Bu bilgiler, ekran dışı dokümanların geçerli bir amaç doğrultusunda kullanıldığından emin olmak için Chrome Web Mağazası'nın inceleme sürecinde kullanılır.

Ekran Dışı Dokümana referansınız olduğunda, güncellenmiş coğrafi konum bilgilerini sağlaması için bu dokümana bir mesaj gönderebilirsiniz.

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

Dolayısıyla, artık hizmet çalışanınızdan coğrafi konum bilgisini almak istediğinizde yapmanız gereken tek şey şu işlemi yapmaktır:

const location = await getGeolocation()

Pop-up veya yan panelde coğrafi konumu kullanma

Bir pop-up içinde veya yan panelde coğrafi konumu kullanmak çok kolaydır. Pop-up'lar ve yan paneller yalnızca web dokümanlarıdır ve bu nedenle normal DOM API'lerine erişebilirler. navigator.geolocation platformuna doğrudan erişebilirsiniz. Standart web sitelerinden tek fark, "geolocation" izni istemek için manifest.json "permission" alanını kullanmanızın gerekmesidir. İzni eklemezseniz navigator.geolocation ürününe erişmeye devam edersiniz. Ancak bunu kullanmaya yönelik her türlü girişim, kullanıcının isteği reddetmesi gibi hemen bir hataya neden olur. Bunu pop-up örneğinde görebilirsiniz.

İçerik komut dosyasında coğrafi konumu kullanma

Tıpkı pop-up'larda olduğu gibi içerik komut dosyalarının da DOM API'sine tam erişimi vardır, ancak kullanıcılar normal kullanıcı izni akışından geçer. Başka bir deyişle, "permissions" cihazınıza "geolocation" eklediğinizde kullanıcıların coğrafi konum bilgilerine otomatik olarak erişemezsiniz. Bunu içerik komut dosyası örneğinde görebilirsiniz.