2 回答
TA貢獻1893條經驗 獲得超10個贊
由于內容腳本的注入方式,您的腳本不起作用。
問題
當您(重新)加載擴展程序時,與某些人的預期相反,Chrome 不會將內容腳本注入到與清單中的模式匹配的現有選項卡中。只有在加載擴展后,任何導航都會檢查URL以進行匹配,并將注入代碼。
那么,時間表:
你打開一些標簽。沒有內容腳本1。
您加載您的擴展程序。它的頂級代碼被執行:它嘗試將消息傳遞給當前選項卡。
由于那里還沒有聽眾,它失敗了。(這可能是
chrome://extensions/頁面,你無論如何都不能注入)之后,如果您嘗試導航/打開新選項卡,則會注入偵聽器,但不再執行頂級代碼。
1 - 如果您重新加載擴展程序,也會發生這種情況。如果注入了內容腳本,它將繼續處理其事件/不會被卸載,但無法再與擴展進行通信。(詳情見最后的附錄)
解決方案
解決方案1:您可以先向選項卡詢問您是否已準備好發送消息,并在靜默時以編程方式注入腳本??紤]:
// 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:始終注入腳本,但要確保它只執行一次。
// 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 */}這更簡單,但在擴展重新加載方面存在復雜性。重新加載擴展后,舊腳本仍然存在1,但它不再是“你的”上下文 - 因此injected將是未定義的。注意可能兩次執行腳本的副作用。
解決方案3:在初始化時不加選擇地注入內容腳本。如果可以安全地運行相同的內容腳本兩次,或者在頁面完全加載后運行它,則這樣做是安全的。
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偵聽器中。
關于孤立內容腳本的附錄
當重新加載擴展程序時,人們會希望Chrome清理所有內容腳本。但顯然事實并非如此; 內容腳本的偵聽器未被禁用。但是,任何具有父擴展的消息都將失敗。這應該被視為一個錯誤,并且可能在某些時候被修復。我要打電話給這個州“孤兒”
這在以下兩種情況中都不是問題:
內容腳本沒有頁面上事件的偵聽器(例如,只執行一次,或者只偵聽來自后臺的消息)
內容腳本不對頁面執行任何操作,僅發送有關事件的背景消息。
但是,如果情況并非如此,那么您就會遇到一個問題:內容腳本可能正在執行某些操作,但是會失敗或干擾另一個非孤立的實例。
解決方法是:
跟蹤頁面可以觸發的所有事件偵聽器
在對這些事件采取行動之前,請向背景發送“心跳”消息。3A。如果背景響應,我們很好,應該執行操作。3B。如果消息傳遞失敗,我們就是孤兒,應該停止; 忽略該事件并取消注冊所有偵聽器。
代碼,內容腳本:
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; }
/* ... */});添加回答
舉報
