भौगोलिक स्थान का इस्तेमाल करें

अगर आपको अपने Chrome एक्सटेंशन में जियोलोकेशन की जानकारी चाहिए, तो उसी navigator.geolocation वेब प्लैटफ़ॉर्म एपीआई का इस्तेमाल करें जिसे किसी भी वेबसाइट पर आम तौर पर इस्तेमाल किया जाता है. यह लेख इसलिए दिया गया है, क्योंकि Chrome एक्सटेंशन, वेबसाइटों की तुलना में संवेदनशील जानकारी को ऐक्सेस करने की अनुमति को अलग तरीके से मैनेज करते हैं. जियोलोकेशन बहुत संवेदनशील डेटा होता है. इसलिए, ब्राउज़र यह पक्का करते हैं कि उपयोगकर्ताओं को इसकी पूरी जानकारी हो. साथ ही, वे यह भी कंट्रोल कर सकें कि उनकी जगह की सटीक जानकारी कब और कहां शेयर की जाए.

MV3 एक्सटेंशन में जियोलोकेशन का इस्तेमाल करना

वेब पर, ब्राउज़र उपयोगकर्ताओं की किसी खास ऑरिजिन को अपनी जगह की जानकारी का ऐक्सेस देने का प्रॉम्प्ट दिखाकर जियोलोकेशन डेटा का ऐक्सेस देना. एक्सटेंशन के लिए, अनुमति का एक ही मॉडल हमेशा सही नहीं होता.

जब कोई वेबसाइट जियोलोकेशन एपीआई के ऐक्सेस का अनुरोध करती है, तो आपको दिखने वाले अनुमति के अनुरोध का स्क्रीनशॉट
जियोलोकेशन की अनुमति का अनुरोध

सिर्फ़ अनुमतियों में अंतर नहीं है. जैसा कि ऊपर बताया गया है, navigator.geolocation एक DOM एपीआई है. इसका मतलब है कि यह उन एपीआई का हिस्सा है जो वेबसाइटें बनाती हैं. इस वजह से, यह वर्कर कॉन्टेक्स्ट में ऐक्सेस नहीं हो सकता. जैसे, एक्सटेंशन सर्विस वर्कर, जो मेनिफ़ेस्ट v3 एक्सटेंशन का मुख्य हिस्सा है. हालांकि, आप अब भी geolocation का इस्तेमाल कर सकते हैं. इसका इस्तेमाल कैसे और कहां किया जाता है, इसमें कुछ अंतर हैं.

सर्विस वर्कर में भौगोलिक स्थान का उपयोग करें

सर्विस वर्कर के अंदर कोई navigator ऑब्जेक्ट नहीं है. यह सिर्फ़ उन कॉन्टेक्स्ट के लिए उपलब्ध होता है जिनके पास पेज के document ऑब्जेक्ट का ऐक्सेस होता है. सर्विस वर्कर के अंदर का ऐक्सेस पाने के लिए, Offscreen Document का इस्तेमाल करें. इससे, ऐसी एचटीएमएल फ़ाइल का ऐक्सेस मिलता है जिसे आपके एक्सटेंशन के साथ बंडल किया जा सकता है.

शुरू करने के लिए, अपने मेनिफ़ेस्ट के "permissions" सेक्शन में "offscreen" जोड़ें.

manifest.json:

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

"offscreen" अनुमति जोड़ने के बाद, अपने एक्सटेंशन में वह एचटीएमएल फ़ाइल जोड़ें जिसमें आपका ऑफ़स्क्रीन दस्तावेज़ शामिल हो. यह मामला पेज के किसी भी कॉन्टेंट का इस्तेमाल नहीं कर रहा है, इसलिए यह फ़ाइल करीब-करीब खाली हो सकती है. इसके लिए, ज़रूरी है कि यह एक छोटी एचटीएमएल फ़ाइल हो, जो आपकी स्क्रिप्ट में लोड हो.

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

पॉप-अप या साइड पैनल में जियोलोकेशन का इस्तेमाल करना

किसी पॉप-अप या साइड पैनल में जियोलोकेशन का इस्तेमाल करना बहुत आसान है. पॉप-अप और साइड पैनल, सिर्फ़ वेब दस्तावेज़ हैं. इसलिए, इनके पास सामान्य डीओएम एपीआई का ऐक्सेस होता है. navigator.geolocation को सीधे ऐक्सेस किया जा सकता है. स्टैंडर्ड वेबसाइटों में सिर्फ़ यह अंतर होता है कि आपको "geolocation" की अनुमति का अनुरोध करने के लिए, manifest.json "permission" फ़ील्ड का इस्तेमाल करना होगा. अगर आप अनुमति नहीं देते हैं, तो आपके पास अब भी navigator.geolocation का ऐक्सेस होगा. हालांकि, इस सुविधा का इस्तेमाल करने की कोशिश करने पर तुरंत गड़बड़ी हो सकती है. यह ठीक उसी तरह है जैसे उपयोगकर्ता ने अनुरोध को अस्वीकार कर दिया हो. आप इसे पॉप-अप सैंपल में देख सकते हैं.

कॉन्टेंट स्क्रिप्ट में जियोलोकेशन का इस्तेमाल करना

पॉप-अप की तरह, कॉन्टेंट स्क्रिप्ट के पास DOM API का पूरा ऐक्सेस होता है; हालांकि, उपयोगकर्ताओं को सामान्य उपयोगकर्ता अनुमति फ़्लो से गुज़रना होगा. इसका मतलब है कि "geolocation" को अपने "permissions" में जोड़ने से, आपको उपयोगकर्ताओं की सेवाओं का ऐक्सेस अपने-आप नहीं मिलेगा भौगोलिक स्थान की जानकारी. इसे देखने के लिए, कॉन्टेंट स्क्रिप्ट सैंपल में जाएं.