1. 程式人生 > >開發順帶NPAPI外掛的Chrome擴充套件

開發順帶NPAPI外掛的Chrome擴充套件

開發附帶NPAPI外掛的Chrome擴充套件


1     NPAPI外掛

1.1   NPAPI簡介

NPAPI(Netscape Plugin Application Programming Interface,網景外掛應用程式介面)是網景公司當年制定的開發基於網景瀏覽器,用於在瀏覽器中執行外部應用程式的通用介面。該介面基於外掛機制,制定了一系列的標準和API,因此也有NPAPI外掛一說。同期的微軟,也在IE中支援ActiveX為瀏覽器外掛,不得不承認微軟在這一點上,把瀏覽器和OS結合的更為緊密,這也可能是當年微軟能夠擊潰網景的原因之一。

但網景的影響深遠,除了微軟特立獨行之外,其他瀏覽器開發廠商奇蹟般的都一致採用了NPAPI來對瀏覽器進行擴充套件(這包括後來從灰燼中重生的FireFox及新生的Chrome;當然,Chrome在不久前時間已經在嘗試拋棄NPAPI了)。因此,在目前來看NPAPI幾乎是IE之外的瀏覽器外掛開發的統一標準。

1.2   準備工作

根據參考資料,從ftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/4.0.1/source/中下載了firefox早期的原始碼,並從中摳出了NPAPI相關的部分(恩,資料上說的不夠詳細)。

解壓原始碼,把modules\plugin\base\public和modules\plugin\sdk\samples\include兩個目錄中的檔案複製出來放在一起(我建立了D:\npapi,把檔案都放這了)。

另外,資料裡提到的三個檔案在modules\plugin\sdk\samples\common下(記住位置,待會會用到)。

1.3   建立外掛

順便提一下,本文以VS2003為範例。

外掛實現的功能:對瀏覽器(貼切點說是對javascript引擎)暴露物件Sample,而Sample又提供了一個sayHello的方法。這樣一來,我們可以在瀏覽器中,使用javascript通過Sample.sayHello();來呼叫外掛所提供的功能。

1.3.1     建立Win32 DLL工程

1.3.2     引入NPAPI庫

在工程屬性中,新增“附加包含目錄”:D:\npapi(之前摳出來的部分)。

1.3.3     新增巨集定義_X86_

1.3.4     新增模組定義檔案(.def檔案)

建立sample.def檔案,內容為:

LIBRARY"sample"

EXPORTS

NP_GetEntryPoints              @1

NP_Initialize                @2

NP_Shutdown               @3

1.3.5     編輯stdafx.h檔案

增加tchar標頭檔案的引入:

#include<tchar.h>

增加NPAPI標頭檔案的引入:

//Mozilla-API

#include<npfunctions.h>

#include<npruntime.h>

#include"npruntime.h"

1.3.6     新增基礎框架檔案

找到np_entry.cpp、npn_gate.cpp和npp_gate.cpp,複製到工程目錄下,並新增到工程(恩恩,位置在modules\plugin\sdk\samples\common)。

在編輯器裡分別開啟著三個檔案,並在檔案頭部加入:

#include"stdafx.h"

1.3.7     編輯sample.cpp檔案

將檔案程式碼修改為:

#include"stdafx.h"

#include"sample.h"

NPErrorNS_PluginInitialize()

{

       return NPERR_NO_ERROR;

}

voidNS_PluginShutdown()

{

}

nsPluginInstanceBase* NS_NewPluginInstance(nsPluginCreateData * aCreateDataStruct)

{

       if(!aCreateDataStruct)

              return NULL;

       CPlugin* plugin = newCPlugin(aCreateDataStruct->instance);

       return plugin;

}

voidNS_DestroyPluginInstance(nsPluginInstanceBase * aPlugin)

{

       if(aPlugin)

              delete (CPlugin *)aPlugin;

}

1.3.8     編輯sample.h檔案

如果檔案不存在,建立一個,並新增到工程。將檔案內容修改為:

#include"stdafx.h"

#include"npruntime.h"

#include"pluginbase.h"

boolIsStringNPIdentifier(NPIdentifier name)

{

       return *(char**)name == (char*)name + 8;

}

char*CopyNPString(NPString str)

{

       char*      r= new char[str.UTF8Length + 1];

       strncpy(r, str.UTF8Characters,str.UTF8Length);

       r[str.UTF8Length] = 0;

       return r;

}

classCSample : public NPObject

{

public:

       CSample(NPP npp) : mNpp(npp) { }

       ~CSample() { }

       static NPObject* _Creator(NPP npp,NPClass *aClass) { return new CSample(npp); }

       static void _Deallocate(NPObject *npobj){ delete (CSample*)npobj; }

       static void _Invalidate(NPObject *npobj){ ((CSample*)npobj)->Invalidate(); }

       static bool _HasMethod(NPObject *npobj,NPIdentifier name) { return ((CSample*)npobj)->HasMethod(name); }

      static bool _Invoke(NPObject *npobj,NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result){ return ((CSample*)npobj)->Invoke(name, args, argCount, result); }

       static bool _InvokeDefault(NPObject*npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) { return((CSample*)npobj)->InvokeDefault(args, argCount, result); }

       static bool _HasProperty(NPObject *npobj, NPIdentifier name) { return ((CSample*)npobj)->HasProperty(name); }

       static bool _GetProperty(NPObject *npobj,NPIdentifier name, NPVariant *result) { return((CSample*)npobj)->GetProperty(name, result); }

       static bool _SetProperty(NPObject *npobj,NPIdentifier name, const NPVariant *value) { return((CSample*)npobj)->SetProperty(name, value); }

       static bool _RemoveProperty(NPObject*npobj, NPIdentifier name) { return ((CSample*)npobj)->RemoveProperty(name);}

       static bool _Enumerate(NPObject *npobj,NPIdentifier **identifier, uint32_t *count) { return((CSample*)npobj)->Enumerate(identifier, count); }

       static bool _Construct(NPObject *npobj,const NPVariant *args, uint32_t argCount, NPVariant *result) { return((CSample*)npobj)->Construct(args, argCount, result); }

       virtual void Invalidate() { }

       virtual bool HasMethod(NPIdentifier name)

       {

              if(IsStringNPIdentifier(name))

              {

                     char*      methodName = *(char**)name;

                     if(_tcscmp(methodName,TEXT("sayHello")) == 0)

                            return true;

              }

              return false;

       }

       virtual bool Invoke(NPIdentifier name,const NPVariant *args, uint32_t argCount, NPVariant *result)

       {

              if(IsStringNPIdentifier(name))

              {

                     char*      methodName = *(char**)name;

                     if(_tcscmp(methodName,TEXT("sayHello")) == 0)

                     {

                            MessageBox(NULL,TEXT("hello, npapi."), TEXT("plugin-sample"), MB_OK |MB_ICONINFORMATION);

                            return true;

                     }

              }

              return false;

       }

       virtual bool InvokeDefault(constNPVariant *args, uint32_t argCount, NPVariant *result) { return true; }

       virtual bool HasProperty(NPIdentifiername) { return false; }

       virtual bool GetProperty(NPIdentifiername, NPVariant *result) { return false; }

       virtual bool SetProperty(NPIdentifiername, const NPVariant *value) { return false; }

       virtual bool RemoveProperty(NPIdentifiername) { return false; }

       virtual bool Enumerate(NPIdentifier**identifier, uint32_t *count) { return false; }

       virtual bool Construct(const NPVariant*args, uint32_t argCount, NPVariant *result) { return false; }

private:

       NPP        mNpp;

};

staticNPClass Sample = {

       NP_CLASS_STRUCT_VERSION_CTOR,

       CSample::_Creator,

       CSample::_Deallocate,

       CSample::_Invalidate,

       CSample::_HasMethod,

       CSample::_Invoke,

       CSample::_InvokeDefault,

       CSample::_HasProperty,

       CSample::_GetProperty,

       CSample::_SetProperty,

       CSample::_RemoveProperty,

       CSample::_Enumerate,

       CSample::_Construct

};

classCPlugin : public nsPluginInstanceBase

{

public:

       CPlugin(NPP pNPInstance) :nsPluginInstanceBase(), m_pNPInstance(pNPInstance), m_bInitialized(FALSE),m_sample(NULL) { }

       ~CPlugin() { }

       NPBool init(NPWindow* pNPWindow)

       {

              m_bInitialized = TRUE;

              return TRUE;

       }

       void shut()

       {

              if(m_sample)

              {

//                   NPN_ReleaseObject(m_sample);

                     delete m_sample;

                     m_sample = NULL;

              }

              m_bInitialized = FALSE;

       }

       NPBool isInitialized()

       {

              return m_bInitialized;

       }

       NPError GetValue(NPPVariable variable,void *value)

       {

              switch(variable)

              {

              case NPPVpluginNameString:

                     *((char**)value) ="plugin-sample";

                     break;

              case NPPVpluginDescriptionString:

                     *((char**)value) ="plugin-sample for Chrome";

                     break;

              case NPPVpluginScriptableNPObject:

//                   if(m_sample == NULL)

//                          m_sample =(CSample*)NPN_CreateObject(m_pNPInstance, &Sample);

//

//                   if(m_sample != NULL)

//                          NPN_RetainObject(m_sample);

                     if(m_sample == NULL)

                     {

                            m_sample = newCSample(m_pNPInstance);

                            m_sample->_class= &Sample;

                     }

                     *((NPObject**)value) =m_sample;

                     break;

              }

              returnnsPluginInstanceBase::GetValue(variable, value);

       }

private:

       NPP        m_pNPInstance;

       NPBool   m_bInitialized;

       CSample*       m_sample;

};

1.3.9     新增Version資源

以文字編輯器方式開啟資原始檔,在版本資訊BLOCK中新增:

VALUE"MIMEType", "application/plugin-sample"

1.3.10  編譯輸出

自此,sample.dll已經躺在Debug目錄下了。

1.4   需要注意的問題

1.4.1     庫檔案的捆綁

考慮到工程的獨立性,我們可以把庫檔案與工程捆綁在一起,我的做法是在工程內建立一個inc目錄,把之前提到的D:\npapi下所有檔案複製過來,並把“附加包含目錄”改為:inc。

1.4.2     謹記MIMEType

一定要記得新增Version資源,並新增MIMEType項。

1.4.3     無效的NPN_CreateObject?

在後續的測試過程中,NPN_CreateObject總是無法有效的建立物件。因此,在sample.h中,我們採用了直接new CSample();的方式(具體原因有待研究)。

2     Chrome擴充套件

2.1   簡介

不愧是Google出品,Chrome從一推出就受到了業界大量的關注和使用者的青睞,幾年下來,市場份額一直在膨脹。其中原因不僅是小巧輕量和啟動快速,也有其快速支援最新Web標準等多方面的緣故。對於第三方開發商,Google也提供了Chrome擴充套件程式設計介面,用來提升瀏覽器本身的個性化定製。

Chrome擴充套件基於HTML5構建,面向javascript引擎暴露瀏覽器內部物件,使用javascript即可直接操作瀏覽器物件,從而實現功能擴充套件。當然,如果我們希望實現的功能超出了Chrome本身提供的內建物件所涵蓋的範圍,則需要之前提到的NPAPI外掛的支援了(這就類似IE瀏覽器中通過new ActiveXObject建立COM物件來增強瀏覽器功能一樣)。

2.2   開始編寫

哦哦,提醒一下,下面提到的所有檔案,務必放到同一個目錄中。

擴充套件實現的功能:在每個頁面(空白處)的右鍵選單中,新增“sayHello”選單項,使用者點選這個選單項時,擴充套件程式通過呼叫NPAPI外掛的sayHello方法,實現彈出“hello,npapi.”對話方塊的功能。

2.2.1     準備一個圖示檔案(.png)

去網上下載一個png檔案吧,32x32、48x48、64x64、128x128等尺寸的都可以。總之,這是一件彰顯個性的事情。

2.2.2     準備NPAPI外掛(.dll)

恩,之前編譯好,已經在Debug目錄躺的妥妥的sample.dll,把他複製過來吧。

2.2.3     編寫manifest.json

內容如下:

{

  "manifest_version" : 2,

  "minimum_chrome_version" :"6.0.0.0",

  "name" : "我的擴充套件",

  "description" : "我的擴充套件",

  "version" : "1.0.0",

  "permissions" : [

    "contextMenus",

    "tabs",

    "http://*/*",

    "https://*/*"

  ],

  "icons" : {

    "128" : "sayHello.png"

  },

  "background" : {

    "page" :"background.html"

  },

  "plugins" : [

    { "path" :"sample.dll", "public" : true }

  ]

}

2.2.4     編寫background.html

內容如下:

<html>

<head></head>

<body>

       <embedtype="application/plugin-sample"id="Sample"></embed>

       <scripttype="text/javascript"src="background.js"></script>

</body>

</html>

2.2.5     編寫background.js

內容如下:

var bkgnd= chrome.extension.getBackgroundPage();

var sample= bkgnd.document.getElementById("Sample");

functiongetClickHandler(type) {

       return function(info, tab) {

              var url = info.pageUrl;

              var title = tab.title;

              if(type == "page") {

                     sample.sayHello();

              }

       }

}

chrome.contextMenus.create({"title" : "sayHello", "type" :"normal", "contexts" : [ "page" ],"onclick" : getClickHandler("page") });

2.3   安裝與測試

開啟Chrome設定的“擴充套件程式”頁面,勾選“開發者模式”,點選“載入正在開發的擴充套件程式”,在彈出的對話方塊中,選擇Chrome擴充套件所在的目錄,然後再確認“新增”即可。

2.4   釋出

同上,在開發者模式下,選擇“打包擴充套件程式”,在彈出的對話方塊中,選擇Chrome擴充套件所在的目錄,然後再次點選“打包擴充套件程式”即可(第一次打包時,Chrome會自動生成一個金鑰檔案;以後每次打包,都需要選擇這個金鑰檔案)。

打包之後的Chrome擴充套件,是一個.crx的zip壓縮檔案,可以直接拖拽到Chrome的擴充套件程式頁面,實現安裝。

3     參考資料

Mozilla官方文件(英文):

https://developer.mozilla.org/en-US/docs/Plugins

https://developer.mozilla.org/en-US/docs/Gecko_Plugin_API_Reference/Plug-in_Basics

NPAPI開發詳解(中文):

http://mozilla.com.cn/post/21666/

http://wenku.baidu.com/view/c4b939f59e314332396893ce.html

Chrome擴充套件官方文件(英文):

https://developer.chrome.com/extensions/index.html

Chrome擴充套件(中文):

http://open.chrome.360.cn/extension_dev/overview.html

4     本文程式碼

http://download.csdn.net/detail/lonely001/6419841

相關推薦

開發順帶NPAPI外掛Chrome擴充套件

開發附帶NPAPI外掛的Chrome擴充套件 1     NPAPI外掛 1.1   NPAPI簡介 NPAPI(Netscape Plugin Application Programming Interface,網景外掛應用程式介面)是網景公司當年制定的開發基於網景瀏覽

開發附帶NPAPI外掛Chrome擴充套件

NPAPI(Netscape Plugin Application Programming Interface,網景外掛應用程式介面)是網景公司當年制定的開發基於網景瀏覽器,用於在瀏覽器中執行外部應用程式的通用介面。該介面基於外掛機制,制定了一系列的標準和API,因此也

開發Chrome 擴充套件程式Hello

chrome擴充套件程式是基於HTML+CSS+Javascript的工程。 所以開發Web的同學開發這個瀏覽器擴充套件學習起來是非常方便的。專案結構主要包含一個manifest.json檔案來儲存專案資訊。本文參考官方地址:https://developer.chrome.com/extensions

Edge 開發團隊透露更多細節:相容 Chrome 擴充套件

   隨著微軟對 Edge 瀏覽器將採用 Chromium 核心的訊息的確認,越來越多的人開始關注並議論此事。在 Reddit 上的相關話題下,有人寫道: 此舉並不會有助於 Edge 的市場份額。現在沒有用 Edge 的人,並不會因為一個 Ch

Chrome擴充套件程式開發之時鐘Demo

1、簡介 Chrome擴充套件是一系列檔案的集合,一個web應用 需要的檔案: 配置檔案(manifest.json) 擴充套件圖示(icon.png 可以是任意的名字,在配置檔案中會使用到) popup彈出視窗html檔案(popup.html) 靜態資原

Vscode外掛 livereload配合chrome擴充套件程式livereload實現網頁自動重新整理(儲存時)

前段時間電腦系統壞了,重新裝系統後便是繁瑣的軟體重灌了(對於程式猿來說,開發環境才是大事),這不,重灌vscode外掛livereload時,竟然忘了它怎麼用了!!!?於是有要百度一波,但是,查了好幾個部落格才解決了我的問題。。。怪自己記性不好啦。。。好的,進入正題。

一篇文章教你順利入門和開發chrome擴充套件程式

前言 關於chrome extension的開發經驗總結或說明文件等資料很多,很多人在寫,然而,我也是一員。但是,也許這篇文章,可能給你一些不一樣的感受。 前面部分大多數是一些基礎介紹,和別人的資料大同小異,但是用的是通俗的語言或者我自己理解來描述的,不是拷貝官方的描述,不然的話,你乾脆看官方文件就好啦,幹

寫一個google chrome 擴充套件外掛

2012-10-24 周海漢 2012.10.24 chrome外掛開發比ie簡單多了。IE必須開發activex控制元件,不懂com,不懂VC,非常困難。而chrome只需懂點JS,CSS,HTML5就差不多了。 方法如下:

Jenkins外掛開發進階篇之擴充套件外掛功能

之前寫過一篇文章是關於如何開發jenkins外掛,主要講述了開發jenkins外掛時需要準備的環境,如何新建一個jenkins外掛工程,以及對工程專案目錄結構的解析。本文是jenkins外掛開發的進階篇,主要講述如何擴充套件jenkins外掛的功能。如下圖所示:(1)Job任

如何開發一個搶單chrome外掛

出於學寫chrome外掛&滿足買買買心態的目的,試了下從零開始寫一個chrome搶單外掛。實驗的網站是nike和adidas的美國官網。 大致歷程 買本chrome外掛教程通讀一下。 在

雜記(3)chrome擴充套件程式開發之在目標頁面執行JS指令碼

一、背景說明在雜記(2)中,我們寫了JS指令碼在chrome瀏覽器的開發者模式console頁面執行,用於搶bus票,但這個指令碼有個弊端是當頁面重新整理後,指令碼會自動清除,無法再執行,如何解決呢?我們可以開發一個chrome外掛,啟動這個外掛,當chrome瀏覽器一開啟目

FireFox外掛擴充套件開發(四)——常見問題的解決

一、FireFox擴充套件中的外掛註冊問題 使用擴充套件,如果擴充套件中帶了XPCOM元件,放在擴充套件的components目錄下,名別寫錯了,今天折騰半天就因為筆誤,總是馬虎。然後要刪除profile中的兩個xpt檔案,重起FireFox,它們會自動註冊。所以元件介面等有

Chrome 擴充套件程式開發

按chrome開發規範,我們首先建一個資料夾,如D:\AutoClickDemo\,在該資料夾下新建一個名為manifest.json的文字檔案,並按實際情況放一個圖片檔案,作為外掛的圖示。然後新建一個名為myscript.js的js指令碼檔案,作為我們需要自定

NPAPI外掛開發詳細記錄:用VS2010開發NPAPI外掛步驟

前面一段時間關注了用firebreath開發外掛,但是感覺用起來不是那麼得心應手,還是回到NPAPI開發外掛上來。 本文根據NPAPI開發詳解,Windows版進行開發,其中以VS2008為例進行開發,在VS2010中基本上是相同的。 必須的plugin sdk,將其解壓到

Chrome擴充套件外掛-用於API & HTTP 請求除錯:Postman

    Postman 是一個非常棒的Chrome擴充套件,提供功能強大的API & HTTP 請求除錯。它能夠傳送任何型別的HTTP requests (GET, HEAD, POST, PUT..),附帶任何數量的引數+ headers。支援不同的認證機制(ba

Chrome擴充套件外掛流程

一、瀏覽器外掛基礎步驟: 1、檔案最基礎的配置 : 一個manifest檔案、一個或多個html檔案、可選的一個或多個javascript檔案、可選的任何需要的其他檔案,例如圖片;在開發應用(擴充套件)時,需要把這些檔案都放到同一個目錄下。釋出應用(擴充套件)時,這個目錄全部打包到一個應用(擴充套件)名是.c

NPAPI外掛開發學習:實現非IE瀏覽器的類似ActiveX的本地程式(外掛)呼叫

轉載CSDN博友的一篇文章,方便以後學習。 一.Netscape Plugin Interface(NPAPI) 大致的說明可以看下官方文件Plugin 本文主要針對於javascript與外掛互動部分做一些交流,比如用於數字證書的操作(淘寶和支

NPAPI外掛開發詳細記要:外掛執行流程分析

NPAPI外掛開發詳細記錄:外掛執行流程分析本文詳細分析外掛的程式碼是如何執行的,主要分析np_entry.cpp、npn_gate.cpp和npp_gate.cpp.希望能夠有所收穫。 在windows平臺下,外掛就是一個dll,注意到這個dll的def檔案內容是:LIB

NPAPI外掛開發學習:Webkit的外掛機制

轉載CSDN博友的一篇關於NPAPI外掛機制的博文。 # 外掛機制(NPAPI plugin) ## 概述 Chromium中的NPAPI外掛(plugin)來源於mozilla的外掛機制。因為它被廣泛的應用,很多外掛廠商或者開發者基於它編寫了數以萬計的外掛,因而

chrome擴充套件開發之在content_script裡執行目標頁面的函式。

如果我們想在content_script裡執行目標頁面的函式很容易寫出下面的程式碼: //content_script.jstest() //直接呼叫目標頁面的函式 但chrome是禁止這種訪