از موقعیت جغرافیایی استفاده کنید

اگر می‌خواهید اطلاعات موقعیت جغرافیایی را در برنامه افزودنی Chrome خود دریافت کنید، از همان API پلتفرم وب navigator.geolocation استفاده کنید که معمولاً هر وب‌سایتی استفاده می‌کند. این مقاله به این دلیل وجود دارد که برنامه‌های افزودنی Chrome مجوز دسترسی به داده‌های حساس را متفاوت از وب‌سایت‌ها مدیریت می‌کنند. موقعیت جغرافیایی داده‌های بسیار حساسی است، بنابراین مرورگرها اطمینان حاصل می‌کنند که کاربران کاملاً از زمان و مکان اشتراک‌گذاری مکان دقیق آن‌ها آگاه هستند و کنترل دارند.

از موقعیت جغرافیایی در پسوندهای MV3 استفاده کنید

در وب، مرورگرها از داده‌های موقعیت جغرافیایی کاربران با نشان دادن درخواستی که از آن‌ها می‌خواهد اجازه دسترسی به آن مبدأ خاص را به مکانشان بدهند، محافظت می‌کنند. یک مدل مجوز همیشه برای برنامه های افزودنی مناسب نیست.

تصویری از درخواست مجوز که وقتی وب سایت درخواست دسترسی به api موقعیت جغرافیایی را می دهد، مشاهده می کنید
درخواست مجوز موقعیت جغرافیایی

مجوزها تنها تفاوت نیستند. همانطور که در بالا ذکر شد، navigator.geolocation یک API DOM است، یعنی چیزی که بخشی از API هایی است که وب سایت ها را تشکیل می دهند. در نتیجه، در داخل زمینه‌های کارگر قابل دسترسی نیست، مانند کارگر سرویس توسعه که ستون فقرات برنامه‌های افزودنی manifest v3 است. با این حال، هنوز هم می‌توانید geolocation استفاده کنید. فقط تفاوت های ظریف در نحوه و مکان استفاده از آن وجود دارد.

از موقعیت جغرافیایی در کارگران خدماتی استفاده کنید

هیچ شی navigator در داخل سرویسکاران وجود ندارد. این فقط در داخل زمینه هایی موجود است که به شی document یک صفحه دسترسی دارند. برای دسترسی به داخل یک سرویس‌کار، از یک Offscreen Document استفاده کنید، که دسترسی به فایل HTML را که می‌توانید با برنامه افزودنی خود بسته‌بندی کنید، فراهم می‌کند.

برای شروع، "offscreen" به بخش "permissions" مانیفست خود اضافه کنید.

manifest.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 برای اطمینان از استفاده از اسناد خارج از صفحه برای یک هدف معتبر استفاده می‌شود.

هنگامی که به سند خارج از صفحه ارجاع دادید، می توانید برای آن پیامی ارسال کنید تا از آن درخواست کنید تا اطلاعات موقعیت جغرافیایی به روز را به شما ارائه دهد.

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

بنابراین اکنون هر زمان که می‌خواهید موقعیت جغرافیایی را از کارمند خدمات خود دریافت کنید، فقط باید تماس بگیرید:

const location = await getGeolocation()

از موقعیت جغرافیایی در یک پنجره بازشو یا پانل جانبی استفاده کنید

استفاده از موقعیت جغرافیایی در یک پنجره بازشو یا پانل جانبی بسیار ساده است. پاپ آپ ها و پانل های جانبی فقط اسناد وب هستند و بنابراین به API های معمولی DOM دسترسی دارند. می توانید مستقیماً navigator.geolocation دسترسی داشته باشید. تنها تفاوت با وب‌سایت‌های استاندارد این است که باید از فیلد "permission" manifest.json برای درخواست مجوز "geolocation" استفاده کنید. اگر مجوز را وارد نکنید، همچنان به navigator.geolocation دسترسی خواهید داشت. با این حال، هر گونه تلاش برای استفاده از آن باعث بروز خطای فوری می شود، مانند اینکه کاربر درخواست را رد کرده باشد. شما می توانید این را در نمونه پاپ آپ مشاهده کنید.

استفاده از موقعیت جغرافیایی در اسکریپت محتوا

درست مانند یک پنجره بازشو، یک اسکریپت محتوا به DOM API دسترسی کامل دارد. با این حال، کاربران از طریق جریان مجوز کاربر عادی عبور خواهند کرد. این بدان معناست که افزودن "geolocation" به "permissions" شما به طور خودکار به شما امکان دسترسی به اطلاعات موقعیت جغرافیایی کاربران را نمی دهد. می توانید این را در نمونه اسکریپت محتوا مشاهده کنید.