2015-09-25 9 views
5

inserisco il codice qui sotto:messaggistica tra la trascrizione dei contenuti e lo sfondo della pagina in un'estensione Chrome non funziona come dovrebbe essere

manifest.json

{ 
    "manifest_version": 2, 

    "name": "Demo", 
    "description": "all_frames test", 
    "version": "1.0", 

    "background": { 
    "scripts": ["background.js"] 
    }, 

    "content_scripts": [{ 
     "matches": ["*://*/*"], 
     "js":   ["content.js"], 
     "all_frames": true 
    }], 

    "permissions": [ 
      "tabs", 
      "*://*/*" 
    ] 
} 

background.js

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 
    var tabStatus = changeInfo.status; 

    if (tabStatus == 'complete') { 

     function return_msg_callback() { 
      console.log('Got a msg from cs...') 
     } 

     chrome.tabs.sendMessage(tabId, { 
      text: 'hey_cs' 
     }, return_msg_callback); 
    } 

}); 

content.js

/* Listen for messages */ 
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { 
    /* If the received message has the expected format... */ 
    if (msg.text && (msg.text == 'hey_cs')) { 
     console.log('Received a msg from bp...') 
     sendResponse('hey_bp'); 
    } 
}); 

Quindi, se vado in un sito che include iFrame di origine incrociata multipli, ad es. http://www.sport.es/, si vedrà che tutti gli iFrame all'interno della pagina ricevono il messaggio dalla pagina di sfondo ma solo uno di essi è in grado di rispondere. È un comportamento normale?

Grazie in anticipo per la risposta.

+0

Se si tratta di una situazione normale, una citazione dai documenti: _Se più pagine sono in ascolto di eventi onMessage, solo il primo a chiamare sendResponse() per un particolare evento riuscirà a inviare la risposta.Tutte le altre risposte a quell'evento saranno ignorate._ – Xan

+0

@Xan Quindi qui stiamo parlando di tutti gli iFrame in una pagina ... così come per i documenti, tutti gli iFrame devono rispondere. no? – jack

+0

Quindi quello che voglio sapere è se un iFrame è considerato come una singola pagina? – jack

risposta

7

Si invia un solo messaggio con una richiamata diretta, quindi in modo naturale Chrome può utilizzare questa richiamata di risposta una sola volta (è una connessione una tantum a un'entità, che si tratti di una pagina o di un iframe).

  • Soluzione 1: inviare più messaggi a ogni iframe esplicitamente:

    manifest.json, autorizzazioni aggiuntive:

    "permissions": [ 
        "webNavigation" 
    ], 
    

    background.js

    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 
        ............. 
        // before Chrome 49 it was chrome.webNavigation.getAllFrames(tabId, ..... 
        // starting with Chrome 49 tabId is passed inside an object 
        chrome.webNavigation.getAllFrames({tabId: tabId}, function(details) { 
         details.forEach(function(frame) { 
          chrome.tabs.sendMessage(
           tabId, 
           {text: 'hey_cs'}, 
           {frameId: frame.frameId}, 
           function(response) { console.log(response) } 
          ); 
         }); 
        }); 
    }); 
    
  • Soluzione 2: rielaborare la logica dello script in background in modo che lo script di contenuto sia il principale nella comunicazione e lasciare che invii il messaggio una volta caricato.

    content.js

    chrome.runtime.sendMessage({text: "hey"}, function(response) { 
        console.log("Response: ", response); 
    }); 
    

    background.js

    chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { 
        console.log("Received %o from %o, frame", msg, sender.tab, sender.frameId); 
        sendResponse("Gotcha!"); 
    }); 
    
+0

Non capisco come la prima soluzione proposta risolva la situazione, poiché invio un messaggio allo script di contenuto solo dopo che la pagina è stata caricata completamente e ciò significa che, di sicuro, lo script del contenuto è stato caricato nella pagina. A proposito, ho testato la tua soluzione proposta e non cambia nulla. – jack

+0

Sulla tua seconda soluzione, non mi interessa quanto tempo impiegano gli iframe per caricare; in realtà se si esegue il mio codice di esempio pubblicato nella domanda, non si riceve mai la risposta. Altrimenti, ciò che hai proposto non è adatto a quello che voglio fare come descritto nel problema. Questo perché vogliamo fare qualcosa nello script di contenuto, non quando lo script di contenuto viene caricato ma quando il caricamento della pagina è completo, cioè quando riceviamo il messaggio che lo stato di tabs.onUpdated è completo. Ciò implica implicitamente che tutti gli iFrame sono caricati. – jack

+0

@wOxxOm quale versione di chrome stai usando? per quanto mi riguarda, sto eseguendo 45.0.2454.99 (64-bit) e vedo solo una risposta dallo script di contenuto alla pagina di sfondo nella console di background anche se più messaggi vengono inviati dalla pagina di sfondo al script di contenuto e vedo quei log nella finestra della console degli strumenti di sviluppo della pagina web. – jack

3

Invece di messaggistica, è possibile utilizzare executeScript per i vostri scopi. Mentre l'argomento della richiamata viene usato raramente (e non credo che molti sanno come funziona), è perfetto qui:

chrome.tabs.executeScript(tabId, {file: "script.js"}, function(results) { 
    // Whichever is returned by the last executed statement of script.js 
    // is considered a result. 
    // "results" is an Array of all results - collected from all frames 
}) 

È possibile fare in modo, per esempio, che l'ultima istruzione eseguita è qualcosa di simile

// script.js 
/* ... */ 
result = { someFrameIdentifier: ..., data: ...}; 
// Note: you shouldn't do a "return" statement - it'll be an error, 
// since it's not a function call. It just needs to evaluate to what you want. 

Assicurarsi di rendere script.js in grado di eseguire più di una volta nello stesso contesto.

Per un identificatore di frame, è possibile definire il proprio algoritmo. Forse è sufficiente un URL, forse puoi usare lo frame's position in the hierarchy.

+0

non possiamo ottenere il frameId come identificatore di frame? – jack

+0

Non credo uno script di contenuto può scoprire "frameId" nel formato utilizzato da altre API di Chrome. Non sono sicuro al 100%. – Xan