2 回答

TA貢獻1893條經(jīng)驗 獲得超10個贊
由于內(nèi)容腳本的注入方式,您的腳本不起作用。
問題
當(dāng)您(重新)加載擴展程序時,與某些人的預(yù)期相反,Chrome 不會將內(nèi)容腳本注入到與清單中的模式匹配的現(xiàn)有選項卡中。只有在加載擴展后,任何導(dǎo)航都會檢查URL以進行匹配,并將注入代碼。
那么,時間表:
你打開一些標(biāo)簽。沒有內(nèi)容腳本1。
您加載您的擴展程序。它的頂級代碼被執(zhí)行:它嘗試將消息傳遞給當(dāng)前選項卡。
由于那里還沒有聽眾,它失敗了。(這可能是
chrome://extensions/
頁面,你無論如何都不能注入)之后,如果您嘗試導(dǎo)航/打開新選項卡,則會注入偵聽器,但不再執(zhí)行頂級代碼。
1 - 如果您重新加載擴展程序,也會發(fā)生這種情況。如果注入了內(nèi)容腳本,它將繼續(xù)處理其事件/不會被卸載,但無法再與擴展進行通信。(詳情見最后的附錄)
解決方案
解決方案1:您可以先向選項卡詢問您是否已準(zhǔn)備好發(fā)送消息,并在靜默時以編程方式注入腳本??紤]:
// Backgroundfunction ensureSendMessage(tabId, message, callback){ chrome.tabs.sendMessage(tabId, {ping: true}, function(response){ if(response && response.pong) { // Content script ready chrome.tabs.sendMessage(tabId, message, callback); } else { // No listener on the other end chrome.tabs.executeScript(tabId, {file: "content_script.js"}, function(){ if(chrome.runtime.lastError) { console.error(chrome.runtime.lastError); throw Error("Unable to inject script into tab " + tabId); } // OK, now it's injected and ready chrome.tabs.sendMessage(tabId, message, callback); }); } });}chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { ensureSendMessage(tabs[0].id, {greeting: "hello"});});
和
// Content scriptchrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { if(request.ping) { sendResponse({pong: true}); return; } /* Content script action */});
解決方案2:始終注入腳本,但要確保它只執(zhí)行一次。
// Backgroundfunction ensureSendMessage(tabId, message, callback){ chrome.tabs.executeScript(tabId, {file: "content_script.js"}, function(){ if(chrome.runtime.lastError) { console.error(chrome.runtime.lastError); throw Error("Unable to inject script into tab " + tabId); } // OK, now it's injected and ready chrome.tabs.sendMessage(tabId, message, callback); });}
和
// Content scriptvar injected;if(!injected){ injected = true; /* your toplevel code */}
這更簡單,但在擴展重新加載方面存在復(fù)雜性。重新加載擴展后,舊腳本仍然存在1,但它不再是“你的”上下文 - 因此injected
將是未定義的。注意可能兩次執(zhí)行腳本的副作用。
解決方案3:在初始化時不加選擇地注入內(nèi)容腳本。如果可以安全地運行相同的內(nèi)容腳本兩次,或者在頁面完全加載后運行它,則這樣做是安全的。
chrome.tabs.query({}, function(tabs) { for(var i in tabs) { // Filter by url if needed; that would require "tabs" permission // Note that injection will simply fail for tabs that you don't have permissions for chrome.tabs.executeScript(tabs[i].id, {file: "content_script.js"}, function() { // Now you can use normal messaging }); }});
我還懷疑你希望它在一些動作上運行,而不是在擴展加載上運行。例如,您可以使用瀏覽器操作并將代碼包裝在chrome.browserAction.onClicked
偵聽器中。
關(guān)于孤立內(nèi)容腳本的附錄
當(dāng)重新加載擴展程序時,人們會希望Chrome清理所有內(nèi)容腳本。但顯然事實并非如此; 內(nèi)容腳本的偵聽器未被禁用。但是,任何具有父擴展的消息都將失敗。這應(yīng)該被視為一個錯誤,并且可能在某些時候被修復(fù)。我要打電話給這個州“孤兒”
這在以下兩種情況中都不是問題:
內(nèi)容腳本沒有頁面上事件的偵聽器(例如,只執(zhí)行一次,或者只偵聽來自后臺的消息)
內(nèi)容腳本不對頁面執(zhí)行任何操作,僅發(fā)送有關(guān)事件的背景消息。
但是,如果情況并非如此,那么您就會遇到一個問題:內(nèi)容腳本可能正在執(zhí)行某些操作,但是會失敗或干擾另一個非孤立的實例。
解決方法是:
跟蹤頁面可以觸發(fā)的所有事件偵聽器
在對這些事件采取行動之前,請向背景發(fā)送“心跳”消息。3A。如果背景響應(yīng),我們很好,應(yīng)該執(zhí)行操作。3B。如果消息傳遞失敗,我們就是孤兒,應(yīng)該停止; 忽略該事件并取消注冊所有偵聽器。
代碼,內(nèi)容腳本:
function heartbeat(success, failure) { chrome.runtime.sendMessage({heartbeat: true}, function(reply){ if(chrome.runtime.lastError){ failure(); } else { success(); } });}function handler() { heartbeat( function(){ // hearbeat success /* Do stuff */ }, function(){ // hearbeat failure someEvent.removeListener(handler); console.log("Goodbye, cruel world!"); } );}someEvent.addListener(handler);
背景腳本:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { if(request.heartbeat) { sendResponse(request); return; } /* ... */});
添加回答
舉報