javascript - पृष्ठभूमि के संदर्भ में स्क्रिप्ट के बीच संवाद(पृष्ठभूमि स्क्रिप्ट, ब्राउज़र कार्रवाई, पृष्ठ कार्रवाई, विकल्प पृष्ठ, आदि)



iframe google-chrome-extension (1)

मैं अपने pageAction स्क्रिप्ट के लिए अपनी पृष्ठभूमि स्क्रिप्ट से डेटा भेजने वाले मुद्दे में भाग रहा pageAction । मेरी सामग्री स्क्रिप्ट में <iframe /> और JavaScript <iframe /> जोड़ता है, मेरी पृष्ठभूमि स्क्रिप्ट से डेटा प्राप्त कर रहा है, लेकिन यह मेरे pageAction में पुनर्प्राप्त नहीं होता है।

मेरी पृष्ठभूमि स्क्रिप्ट में मेरे पास कुछ इस तरह है:

chrome.tabs.sendMessage(senderTab.tab.id, 
{
   foo:bar
}); 

जहाँ पर senderTab.tab.id भेजने onMessage श्रोता मेरी पृष्ठभूमि स्क्रिप्ट में onMessage "प्रेषक" है।

मेरी सामग्री स्क्रिप्ट द्वारा इंजेक्ट <iframe /> द्वारा लोड किए गए जावास्क्रिप्ट में मेरे पास कुछ इस तरह है:

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
      console.log("received in iframe:", request);
    }   
});

<iframe /> संदेश ठीक उसी प्रकार प्राप्त करता है, जैसा अपेक्षित है।

मैंने अपने page_action.js में वही जावास्क्रिप्ट रखा है, लेकिन यह पृष्ठभूमि स्क्रिप्ट से कोई डेटा प्राप्त नहीं करता है। पेजएक्शन chrome.pageAction.show(senderTab.tab.id); साथ सक्रिय है chrome.pageAction.show(senderTab.tab.id); इससे पहले कि मैं chrome.tabs.sendMessage(senderTab.tab.id ...

क्या HTML पेज मेरे पेज से जुड़ा है। उसी टैब का हिस्सा नहीं है? चूंकि इस tabId ने मुझे आइकन को सक्रिय / "दिखाने" के लिए सक्षम किया है, मुझे लगता है कि पेजएक्शन के लिए जावास्क्रिप्ट में श्रोता को chrome.tabs.sendMessage(senderTab.tab.id ... से भी प्राप्त करना चाहिए chrome.tabs.sendMessage(senderTab.tab.id ...

अपनी सामग्री स्क्रिप्ट में मैं पृष्ठभूमि स्क्रिप्ट में डेटा भेजने के लिए निम्नलिखित का उपयोग करता हूं:

chrome.runtime.sendMessage({
  foo: bar
});  

जब सामग्री स्क्रिप्ट उपरोक्त संदेश भेजती है, तो पेजएक्शन जावास्क्रिप्ट इसे उठा रहा है।

मुझे अपने पृष्ठ पर डेटा भेजने के लिए पृष्ठभूमि स्क्रिप्ट कैसे मिलेगी? मैं पेजएक्शन रिक्वेस्ट / पोल नहीं करना चाहता, इसके बजाय मैं चाहता हूं कि पेजएक्शन सिर्फ सुनने और प्राप्त करने के लिए हो। उदाहरण के लिए, यदि पेजएक्शन एचटीएमएल ने दिखाया है, तो यह वास्तविक समय में अपडेट करने में सक्षम होना चाहिए क्योंकि पृष्ठभूमि पृष्ठ परिवर्तन करता है।


पृष्ठभूमि संदर्भ में एक पृष्ठ के साथ संवाद

पृष्ठ जो पृष्ठभूमि के संदर्भ में खुले हैं, उनमें शामिल हैं:

tabs.sendMessage() ( MDN ) का उपयोग करना tabs.sendMessage() से किसी को भी संदेश नहीं भेजेगा। आपको उन्हें संदेश भेजने के लिए runtime.sendMessage() ( MDN ) का उपयोग करने की आवश्यकता होगी। पृष्ठभूमि पृष्ठों और घटना पृष्ठों को छोड़कर, उनमें से किसी के लिए गुंजाइश केवल तब मौजूद होती है जब इसे प्रदर्शित किया जा रहा हो। जाहिर है, आप कोड के साथ संवाद नहीं कर सकते जब यह मौजूद नहीं है। जब गुंजाइश मौजूद है, तो आप उनमें से किसी का उपयोग करके संवाद कर सकते हैं:

  • सीधे
    पृष्ठभूमि के संदर्भ से, आप सीधे किसी अन्य पृष्ठ में परिवर्तनशील चर या कॉल फ़ंक्शन को बदल सकते हैं, जो कि पृष्ठभूमि के संदर्भ में भी है (अर्थात सामग्री स्क्रिप्ट नहीं), इसके वैश्विक स्कोप का संदर्भ प्राप्त करने के बाद, इसकी Window , extension.getViews() का उपयोग करके extension.getViews() ( MDN ) , extension.getBackgroundPage() ( MDN ) , या अन्य विधि ( MDN )
    उदाहरण के लिए, आप function myFunction के साथ बनाए गए function myFunction को पहले लौटे दृश्य के पृष्ठ में कुछ इस तरह से उपयोग कर सकते हैं:

    winViews = chrome.extension.getViews();
    winViews[0].myFunction(foo); 

    यह ध्यान दिया जाना चाहिए कि tabs.create() ( MDN ) या windows.create() ( MDN ) से आपके कॉलबैक में नए खुले टैब या विंडो के लिए दृश्य शायद अभी तक मौजूद नहीं है। दृश्य के अस्तित्व के लिए प्रतीक्षा करने के लिए आपको कुछ पद्धति का उपयोग करने की आवश्यकता होगी। 2 नए खुले टैब या खिड़कियों के साथ संवाद करने के अनुशंसित तरीकों के लिए नीचे देखें।

    सीधे दूसरे पृष्ठ के दायरे में मूल्यों में हेरफेर करने से आप अपनी इच्छा के अनुसार किसी भी प्रकार के डेटा का संचार कर सकते हैं।

  • संदेश
    chrome.runtime.onMessage ( MDN ) , 3 का उपयोग करके संदेश प्राप्त करें जो runtime.sendMessage() ( MDN ) के साथ भेजे गए थे। हर बार जब आप sendResponse में एक संदेश प्राप्त करते हैं। संदेश श्रोता, तीसरे तर्क के रूप में एक sendResponse फ़ंक्शन प्रदान किया जाएगा जो आपको सीधे संदेश का जवाब देने की अनुमति देता है। यदि मूल प्रेषक ने chrome.runtime.sendMessage() को अपनी कॉल में ऐसी प्रतिक्रिया प्राप्त करने के लिए कॉलबैक की आपूर्ति नहीं की है, तो प्रतिक्रिया खो जाती है। अगर Promises (जैसे browser.runtime.sendMessage() फ़ायरफ़ॉक्स में) का उपयोग कर रहे हैं, तो प्रतिक्रिया एक तर्क के रूप में पारित की जाती है जब वादा पूरा होता है। यदि आप प्रतिक्रिया को अतुल्यकालिक रूप से भेजना चाहते हैं, तो आपको return true; होगा return true; अपने runtime.onMessage श्रोता से।

    बंदरगाहों
    आप लंबी अवधि के संदेश के लिए chrome.runtime.connect() ( MDN ) और chrome.runtime.onConnect ( MDN ) का उपयोग करके भी पोर्ट कनेक्ट कर सकते हैं।

    सामग्री स्क्रिप्ट भेजने के लिए chrome.tabs.sendMessage() का उपयोग करें
    यदि आप किसी सामग्री स्क्रिप्ट के लिए पृष्ठभूमि संदर्भ (जैसे पृष्ठभूमि स्क्रिप्ट या पॉपअप) से भेजना चाहते हैं, तो आप chrome.tabs.sendMessage() / chrome.runtime.onMessage उपयोग करें, या chrome.tabs.connect() ) का उपयोग करके पोर्ट (ओं) को कनेक्ट करें chrome.tabs.connect() ( MDN ) / chrome.runtime.onConnect

    JSON-serializable डेटा केवल
    मैसेजिंग का उपयोग करके, आप केवल डेटा पास कर सकते हैं जो JSON-serializable है।

    संदेश प्रेषक को छोड़कर, सभी लिपियों को पृष्ठभूमि में प्राप्त होते हैं
    पृष्ठभूमि के संदर्भ में भेजे गए संदेश पृष्ठभूमि के संदर्भ में सभी स्क्रिप्टों द्वारा प्राप्त किए जाते हैं जिन्होंने एक श्रोता को पंजीकृत किया है, जो उस स्क्रिप्ट को छोड़कर जिसने इसे भेजा था। 3 यह निर्दिष्ट करने का कोई तरीका नहीं है कि यह केवल एक विशिष्ट स्क्रिप्ट द्वारा प्राप्त किया जाना है। इस प्रकार, यदि आपके पास कई संभावित प्राप्तकर्ता हैं, तो आपको यह सुनिश्चित करने का एक तरीका बनाना होगा कि प्राप्त संदेश उस स्क्रिप्ट के लिए अभिप्रेत था। ऐसा करने के तरीके आमतौर पर संदेश में मौजूद विशिष्ट गुणों पर निर्भर होते हैं (उदाहरण के लिए destination या recipient संपत्ति का उपयोग करके यह इंगित करने के लिए कि इसे प्राप्त करने के लिए स्क्रिप्ट क्या है, या परिभाषित करें कि कुछ type के संदेश हमेशा एक प्राप्तकर्ता या किसी अन्य के लिए होते हैं), या अंतर करने के लिए। संदेश हैंडलर को भेजे गए sender ( MDN ) के आधार पर (उदाहरण के लिए यदि एक प्रेषक के संदेश हमेशा एक विशिष्ट प्राप्तकर्ता के लिए ही होते हैं)। ऐसा करने का कोई निर्धारित तरीका नहीं है, आपको इसे अपने एक्सटेंशन में उपयोग करने के लिए एक तरीका चुनना / बनाना होगा।

    इस मुद्दे की अधिक विस्तृत चर्चा के लिए, कृपया देखें: पृष्ठभूमि संदर्भ में एक स्क्रिप्ट के लिए इच्छित संदेश सभी को प्राप्त होते हैं

  • एक StorageArea में डेटा
    एक StorageArea ( MDN ) में डेटा स्टोर करें और StorageArea ( MDN ) का उपयोग करके अन्य लिपियों में परिवर्तन के बारे में सूचित करें। storage.onChanged घटना पृष्ठभूमि संदर्भ और सामग्री स्क्रिप्ट दोनों में सुनी जा सकती है।

    आप केवल डेटा स्टोर कर सकते हैं जो कि JSON-serializable एक StorageArea में है।

किसी विशेष स्थिति में उपयोग करने के लिए कौन सी विधि सबसे अच्छी है, यह इस बात पर निर्भर करेगा कि आप किस प्रकार का संचार करना चाहते हैं (डेटा का प्रकार, राज्य परिवर्तन, आदि), और आपके विस्तार के किस भाग, या भाग से आप संवाद करना चाहते हैं और । उदाहरण के लिए, यदि आप ऐसी जानकारी को संप्रेषित करना चाहते हैं जो JSON-serializable नहीं है, तो आपको सीधे ऐसा करने की आवश्यकता होगी (यानी मैसेजिंग या StorageArea का उपयोग नहीं करना)। आप एक ही एक्सटेंशन में कई तरीकों का उपयोग कर सकते हैं।

पॉपअप पर अधिक

कोई भी पॉपअप (जैसे ब्राउज़र एक्शन, या पेज एक्शन) सीधे सक्रिय टैब से संबद्ध नहीं है। प्रति टैब एक साझा या अलग उदाहरण की कोई अवधारणा नहीं है। हालाँकि, उपयोगकर्ता प्रत्येक Chrome विंडो में एक पॉपअप खोल सकता है। यदि एक से अधिक पॉपअप खुला है (क्रोम विंडो के प्रति अधिकतम एक), तो प्रत्येक अलग उदाहरण (अलग गुंजाइश; अपनी खिड़की है) में है, लेकिन एक ही संदर्भ में हैं। जब कोई पॉपअप वास्तव में दिखाई देता है, तो यह पृष्ठभूमि के संदर्भ में मौजूद होता है।

Chrome विंडो में एक समय में केवल एक पृष्ठ कार्रवाई या ब्राउज़र एक्शन पॉपअप खुला होता है। जो HTML फ़ाइल खुलेगी, जो भी वर्तमान विंडो के सक्रिय टैब के लिए परिभाषित की गई होगी और पृष्ठ / ब्राउज़र कार्रवाई बटन पर क्लिक करके उपयोगकर्ता द्वारा खोली जाएगी । इसे chrome.browserAction.setPopup() ( MDN ) , या chrome.pageAction.setPopup() ( MDN ) का उपयोग करके और एक tabId निर्दिष्ट करके अलग टैब के लिए एक अलग HTML दस्तावेज़ सौंपा जा सकता है। पॉपअप कई कारणों से नष्ट / किया जा सकता है, लेकिन निश्चित रूप से जब एक और टैब उस विंडो में सक्रिय टैब बन जाता है जिसमें पॉपअप खुला होता है।

हालाँकि, उपयोग की जाने वाली संचार की कोई भी विधि केवल उसी व्यक्ति के लिए संचार करेगी जो वर्तमान में खुला है, जो खुले नहीं हैं। यदि पॉपअप एक समय में एक से अधिक क्रोम विंडो के लिए खुले हैं, तो वे अलग-अलग उदाहरण हैं, अपने स्वयं के दायरे (यानी अपनी स्वयं की विंडो) के साथ। आप ऐसा कुछ सोच सकते हैं जैसे एक ही वेब पेज एक से अधिक टैब में खुला हो।

यदि आपके पास एक बैकग्राउंड स्क्रिप्ट है, तो बैकग्राउंड लिपि संदर्भ क्रोम के पूरे उदाहरण में बना रहता है। यदि आपके पास एक पृष्ठभूमि स्क्रिप्ट नहीं है, तो संदर्भ को जरूरत पड़ने पर बनाया जा सकता है (उदाहरण के लिए पॉपअप दिखाया गया है) और तब नष्ट हो जाता है जब आवश्यकता नहीं होती है।

chrome.tabs.sendMessage() पॉपअप के लिए संवाद नहीं कर सकता है

जैसा कि ऊपर उल्लेख किया गया है, भले ही पॉपअप मौजूद था, यह पृष्ठभूमि के संदर्भ में मौजूद होगा। chrome.tabs.sendMessage() कॉलिंग सामग्री संदेश को एक टैब / फ़्रेम में इंजेक्ट करता है , न कि पृष्ठभूमि के संदर्भ में। इस प्रकार, यह एक गैर-सामग्री स्क्रिप्ट को पॉपअप की तरह संदेश नहीं भेजेगा।

कार्रवाई बटन: सक्षम / अक्षम (ब्राउज़र कार्रवाई) बनाम दिखाने / छिपाने (पेज कार्रवाई)

chrome.pageAction.show() ( MDN ) को कॉल करने से पृष्ठ कार्रवाई बटन दिखाया जा सकता है। यह किसी भी संबंधित पॉपअप को दिखाने का कारण नहीं बनता है। यदि पॉपअप / विकल्प पृष्ठ / अन्य पेज वास्तव में नहीं दिखाया जा रहा है (केवल बटन नहीं), तो इसका दायरा मौजूद नहीं है। जब यह मौजूद नहीं है, यह स्पष्ट रूप से, कोई संदेश प्राप्त नहीं कर सकता है

पृष्ठ क्रिया chrome.pageAction.show() ( MDN ) या hide() ( MDN ) बटन को chrome.pageAction.show() की क्षमता के बजाय, ब्राउज़र क्रियाएं ( MDN ) या disable() ( MDN ) बटन को enable() कर सकती हैं।

प्रोग्राम को आपके एक्सटेंशन से HTML के साथ टैब या विंडो खोलना

अपने विस्तार के भीतर से HTML पृष्ठ युक्त टैब या विंडो खोलने के लिए आप tabs.create() ( MDN ) या windows.create() ( MDN ) का उपयोग कर सकते हैं। हालाँकि, उन दोनों API कॉल के लिए कॉलबैक पृष्ठ के DOM मौजूदा से पहले निष्पादित किया जाता है और इस प्रकार मौजूदा पृष्ठ से जुड़े किसी भी जावास्क्रिप्ट से पहले। इस प्रकार, आप तुरंत उस पृष्ठ की सामग्री द्वारा बनाए गए DOM तक नहीं पहुँच सकते, और न ही पृष्ठ के लिए जावास्क्रिप्ट के साथ बातचीत कर सकते हैं। बहुत विशेष रूप से: कोई runtime.onMessage() नहीं है। संदेश runtime.onMessage() श्रोताओं को जोड़ा जाएगा, इसलिए उस समय भेजे गए कोई भी संदेश नए शुरुआती पृष्ठ द्वारा प्राप्त नहीं किए जाएंगे।

इस समस्या को हल करने के सर्वोत्तम तरीके हैं:

  1. डेटा उपलब्ध है तो नए खुलने वाले पेज को डेटा तब मिल सकता है जब वह इसके लिए तैयार हो। पृष्ठ खोलने की प्रक्रिया शुरू करने से पहले ऐसा करें:
    1. यदि स्रोत पृष्ठभूमि के संदर्भ में है: डेटा को भेजने वाले पृष्ठ के वैश्विक दायरे के लिए उपलब्ध चर में संग्रहीत करें। उद्घाटन पृष्ठ फिर सीधे डेटा को पढ़ने के लिए chrome.extension.getBackgroundPage() का उपयोग कर सकता है।
    2. यदि डेटा का स्रोत पृष्ठभूमि संदर्भ या सामग्री स्क्रिप्ट में है: डेटा को storage.local में रखें। storage.local ( MDN ) । उद्घाटन पृष्ठ तब इसे पढ़ सकता है जब इसका जावास्क्रिप्ट चलाया जाता है। उदाहरण के लिए, आप messageToNewExtensionPage नामक एक कुंजी का उपयोग कर सकते हैं।
  2. यदि आप runtime.sendMessage() का उपयोग कर रहे हैं, तो उस पृष्ठ के कोड से डेटा के स्रोत तक एक संदेश भेजकर ( runtime.sendMessage() या tabs.sendMessage() का उपयोग करके runtime.sendMessage() अपने नए खुलने वाले पृष्ठ से डेटा के हस्तांतरण की शुरुआत करें। tabs.sendMessage() सामग्री स्क्रिप्ट स्रोतों के लिए) डेटा का अनुरोध करना। डेटा वाली स्क्रिप्ट तब runtime.onMessage() द्वारा प्रदान की गई sendResponse (MDN) फ़ंक्शन का उपयोग करके डेटा वापस भेज सकती है।
  3. कम से कम DOM उपलब्ध होने के बाद तक नए खुलने वाले पेज के साथ बातचीत करने के लिए प्रतीक्षा करें, यदि पेज के लिए जावास्क्रिप्ट के चलने तक नहीं। हालांकि यह संभव नहीं है कि यह नए खुलने वाले पेज के बिना विशिष्ट अधिसूचना प्रदान करता है कि यह ऊपर और चल रहा है, ऐसा करना अधिक जटिल है और केवल कुछ विशिष्ट मामलों में उपयोगी है (जैसे कि आप नए पृष्ठ में जावास्क्रिप्ट से पहले कुछ करना चाहते हैं) । 2

अतिरिक्त संदर्भ

क्रोम

फ़ायरफ़ॉक्स

  1. कुछ मामूली अपवादों के साथ: जैसे पृष्ठ संदर्भ में सामग्री डालने के लिए सामग्री स्क्रिप्ट का उपयोग करना।
  2. ऐसे कई तरीके हैं जिनका आप उपयोग कर सकते हैं। कौन सा तरीका सबसे अच्छा है यह इस बात पर निर्भर करेगा कि आप क्या कर रहे हैं (उदाहरण के लिए जब आपको दृश्य में निष्पादित कोड के संबंध में दृश्य तक पहुंचने की आवश्यकता हो)। एक सरल तरीका यह होगा कि चुनाव के अस्तित्व के इंतजार में सिर्फ मतदान हो। विंडो खोलने के लिए निम्न कोड है:

    chrome.windows.create({url: myUrl},function(win){
        //Poll for the view of the window ID. Poll every 50ms for a
        //  maximum of 20 times (1 second). Then do a second set of polling to
        //  accommodate slower machines. Testing on a single moderately fast machine
        //  indicated the view was available after, at most, the second 50ms delay.
        waitForWindowId(win.id,50,20,actOnViewFound,do2ndWaitForWinId);
    });
    function waitForWindowId(id,delay,maxTries,foundCallback,notFoundCallback) {
        if(maxTries--<=0){
            if(typeof notFoundCallback === 'function'){
                notFoundCallback(id,foundCallback);
            }
            return;
        }
        let views = chrome.extension.getViews({windowId:id});
        if(views.length > 0){
            if(typeof foundCallback === 'function'){
                foundCallback(views[0]);
            }
        } else {
            setTimeout(waitForWindowId,delay,id,delay,maxTries,foundCallback
                       ,notFoundCallback);
        }
    }
    function do2ndWaitForWinId(winId,foundCallback){
        //Poll for the view of the window ID. Poll every 500ms for max 40 times (20s).
        waitForWindowId(winId,500,40,foundCallback,windowViewNotFound);
    }
    function windowViewNotFound(winId,foundCallback){
        //Did not find the view for the window. Do what you want here.
        //  Currently fail quietly.
    }
    function actOnViewFound(view){
        //What you desire to happen with the view, when it exists.
    }
  3. MDN से :

    संस्करण 51 से पहले फ़ायरफ़ॉक्स संस्करणों में, runtime.onMessage श्रोता को उसी स्क्रिप्ट से भेजे गए संदेशों के लिए बुलाया जाएगा (जैसे पृष्ठभूमि स्क्रिप्ट द्वारा भेजे गए संदेश भी पृष्ठभूमि स्क्रिप्ट द्वारा प्राप्त किए जाएंगे)। फ़ायरफ़ॉक्स के उन संस्करणों में, यदि आप बिना रनटाइम के एक रनटाइम.sendMessage () कॉल करते हैं। एक श्रोता के रूप में, आप एक अनंत लूप सेट करेंगे जो सीपीयू और लॉक-अप फ़ायरफ़ॉक्स को अधिकतम-आउट करेगा। यदि आपको runtime.sendMessage () runtime.onMessage के भीतर से कॉल करने की आवश्यकता है, तो आपको यह सत्यापित करने के लिए प्रेषक की जाँच करनी होगी। सत्यापित करें कि आप एक संदेश के जवाब में एक संदेश नहीं भेज रहे हैं जो उसी स्क्रिप्ट से भेजा गया था। इस बग को फ़ायरफ़ॉक्स 51 के रूप में हल किया गया था।





firefox-webextensions