1. 程式人生 > >Chrome 瀏覽器外掛之監控網頁地址

Chrome 瀏覽器外掛之監控網頁地址

瀏覽器外掛開發手冊:http://open.chrome.360.cn/extension_dev/overview.html
瀏覽器外掛demo,請先參考部落格:https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html
注意事項,由於js和C++的差異性,導致踩了不少坑:

1.js如果提及預設值,請填寫null。
坑:chrome.tabs.getAllInWindow(integer windowId, function callback)
windowId  預設為當前視窗 然後給了一個連線值:chrome.windows.WINDOW_ID_NONE,此時發現獲取不到資料。如果引數給null就對了

2.js函式執行順序是非同步的,並不會等待,所以需要使用回撥,返回值不一定是正確的。如下通過函式返回值判斷標籤是否存在的方式是錯誤的:
錯誤方式:
function isExistTab()
{
	//block1
	var bExist = false;
	chrome.tabs.getAllInWindow(null, function(tabs)
	{
		//block2
		for ( var i = 0; i <tabs.length; i++)
		{
			url = tabs[i].url;
			if(url.indexOf("pan.bitqiu.com") != -1)
			{
				bexist = true;
				break;
			}
		}
	});
	//block3
	return bExist ;
}

除錯你會發現,程式碼執行順序是block1=》block3=》block2 ,並不是順序執行

3.js中的try catch 只會抓當前程式碼塊的異常,並不會捕獲程式碼塊裡面的函式的異常
function test()
{
	try
	{
		....
		....
		//這段function程式碼的異常不會被捕獲
		function()
		{
			try{}
			catch(e){}
		}
	}
	catch(e)
	{
	}
}

首先我們需要學習參考手冊,瞭解基本的外掛包格式和物件介面。監控瀏覽器網頁地址可以參考瀏覽器外掛demo學習裡面的使用方法。

開發思考?
  1. 如何需要監控瀏覽器請求發生變化?
  2. 如何開啟標籤頁,判斷標籤頁是否存在?

問題1:如何需要監控瀏覽器請求發生變化?
答:首先監控瀏覽器請求那麼生命週期必須和瀏覽器共存,才能在整體上監控瀏覽器請求變化。
那麼首先可以排除popup裡面處理js,所以我們把目標轉移到content.js 和 background.js, 但是根據手冊我們:

下面是content scipt可以做的一些事情範例:

從頁面中找到沒有寫成超連結形式的url,並將它們轉成超連結。
放大頁面字型使文字更清晰
找到並處理DOM中的microformat
當然,content scripts也有一些限制,它們不能做的事情包括 :

不能使用除了chrome.extension之外的chrome.* 的介面
不能訪問它所在擴充套件中定義的函式和變數
不能訪問web頁面或其它content script中定義的函式和變數
不能做cross-site XMLHttpRequests
這些限制其實並不像看上去那麼糟糕。Content scripts 可以使用messages機制與它所在的擴充套件通訊,來間接使用chrome.*介面,或訪問擴充套件資料。Content scripts還可以通過共享的DOM來與web頁面通訊。更多功能參見執行環境。

所以我們在content.js裡面沒有辦法處理和標籤頁相關的事物。但是可以使用messages機制和其他擴充套件通訊。message 需要json格式字串

document.addEventListener('DOMContentLoaded', function()
{
	try
	{
		//alert(JSON.stringify(document));
		//按照匹配規則匹配
		//if(location.href == 'https://www.baidu.com/')
		//傳送訊息,有backgrand處理
		chrome.runtime.sendMessage({greeting:location.href}, function(response) {
		});
	}
	catch(e)
	{
		alert(e);
	}
	
});

問題1:如何開啟標籤頁?
答:通過問題1我們可以知道如果處理messge的話,最好的方式就是在background.js裡面處理message,因為background.js可以很輕鬆的和標籤頁互動,並且處理標籤頁的事務。

// 監聽來自content-script的訊息


chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
{
	//{greeting:url}
	try
	{
		var url = request.greeting;
		//url.match()
		isExistTab(bExist =>{
			if(bExist)
			{
				//alert(url);
			}
			else
			{
				//如果不存在開啟新的標籤頁
				openUrlNewTab("https://pan.bitqiu.com/");
			}
		});
	}
	catch(e)
	{
		alert(e);
	}
	
	sendResponse('ans:ok');
});

// 獲取當前選項卡ID
function getCurrentTabId(callback)
{
	chrome.tabs.query({active: true, currentWindow: true}, function(tabs)
	{
		if(callback) callback(tabs.length ? tabs[0].id: null);
	});
}

// 當前標籤開啟某個連結
function openUrlCurrentTab(url)
{
	getCurrentTabId(tabId => {
		chrome.tabs.update(tabId, {url: url});
	})
}

// 新標籤開啟某個連結
function openUrlNewTab(url)
{
	chrome.tabs.create({url: url});
}

//判斷某個標籤頁是否存在
function isExistTab(callback)
{
	chrome.tabs.getAllInWindow(null, function(tabs)
	{
		bexist = false;
		for ( var i = 0; i <tabs.length; i++)
		{
			url = tabs[i].url;
			if(url.indexOf("pan.bitqiu.com") != -1)
			{
				bexist = true;
				break;
			}
		}
		
		if(callback) callback(bexist)
	});
}

現在就是配置外掛manifest.json

{
  "manifest_version": 2,
  
  "name": "watch_url_redirect",
  
  "description": "watch url address if is match role and open a new tab ",
  
  "version": "1.0.2",
  
  "icons":
	{
		"16": "img/icon.png",
		"48": "img/icon.png",
		"128": "img/icon.png"
	},
  
  "background":
	{
		"scripts": ["js/background.js"]
	},
	
  "browser_action": 
	{
		"default_icon": "img/icon.png",
		"default_title": "stwatch",
		"default_popup": "popup.html"
	},
	
	// 需要直接注入頁面的JS
	"content_scripts": 
	[
		{
			// "<all_urls>" 表示匹配所有地址
			"matches": ["<all_urls>"],
			// 多個JS按順序注入
			"js": ["js/content-script.js"],
			// 程式碼注入的時間,可選值: "document_start", "document_end", or "document_idle",最後一個表示頁面空閒時,預設document_idle
			"run_at": "document_start"
		}
	],
	
	// 許可權申請
	"permissions":
	[
		"contextMenus", // 右鍵選單
		"tabs", // 標籤
		"notifications", // 通知
		"webRequest", // web請求
		"webRequestBlocking", // 阻塞式web請求
		"storage", // 外掛本地儲存
		"http://*/*", // 可以通過executeScript或者insertCSS訪問的網站
		"https://*/*" // 可以通過executeScript或者insertCSS訪問的網站
	]
	
}

此時整個外掛完成請求監控。

思考:
其實在寫background.js的時候我發現事實我們可以監控:chrome.webRequest.onBeforeRequest.addListener,但是不知道為什麼這個介面沒有被觸發,所以使用了message機制來實現。等後面有時間研究在來解決這個問題.