最近需要写一个Mac平台上的简单的跨浏览器的插件,需要在js中调用本地方法,而npapi满足此要求。
NPAPI就是Netscape Plugin Application Programming Interface的缩写了,虽然Netscape已经去了,但是这个却被沿用下来,在各大浏览器中都得以实现。还是纪念下曾经的浏览器的鼻祖啊。
在网络上搜索了很长时间,一直没有找到合适的满足自己需求的代码例子。且这方面的文档也少的可怜。
还是先提一下,有两个系列的文章还是不错,虽然或许可能也不完全正确,但是帮助理解npapi的编程模型是非常有帮助的:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
#import <WebKit/npapi.h>
#import <WebKit/npfunctions.h> #import <WebKit/npruntime.h> // Browser function table,可以通过它来得到浏览器提供的功能 static NPNetscapeFuncs * browser ; static const char *plugin_method_name_open = "open" ; //////////////////////////////////// /*******各种接口的声明*********/ //在NPAPI编程的接口中你会发现有NP_打头的,有NPP_打头的,有NPN_打头的 //NP是npapi的插件库提供给浏览器的最上层的接口 //NPP即NP Plugin是插件本身提供给浏览器调用的接口,主要被用来填充NPPluginFuncs的结构体 //NPN即NP Netscape ,是浏览器提供给插件使用的接口,这些接口一般都在NPNetscapeFuncs结构体中 //Mach-o entry points,浏览器和创建交流的最上层的接口 NPError NP_Initialize (NPNetscapeFuncs *browserFuncs ) ; NPError NP_GetEntryPoints (NPPluginFuncs *pluginFuncs ) ; void NP_Shutdown ( void ) ; //NPP Functions NPError NPP_New (NPMIMEType pluginType , NPP instance , uint16_t mode , int16_t argc , char * argn [ ] , char * argv [ ] , NPSavedData * saved ) ; NPError NPP_Destroy (NPP instance , NPSavedData ** save ) ; NPError NPP_SetWindow (NPP instance , NPWindow * window ) ; NPError NPP_NewStream (NPP instance , NPMIMEType type , NPStream * stream , NPBool seekable , uint16_t * stype ) ; NPError NPP_DestroyStream (NPP instance , NPStream * stream , NPReason reason ) ; int32 NPP_WriteReady (NPP instance , NPStream * stream ) ; int32 NPP_Write (NPP instance , NPStream * stream , int32 offset , int32 len , void * buffer ) ; void NPP_StreamAsFile (NPP instance , NPStream * stream , const char * fname ) ; void NPP_Print (NPP instance , NPPrint * platformPrint ) ; int16_t NPP_HandleEvent (NPP instance , void * event ) ; void NPP_URLNotify (NPP instance , const char * URL , NPReason reason , void * notifyData ) ; NPError NPP_GetValue (NPP instance , NPPVariable variable , void *value ) ; NPError NPP_SetValue (NPP instance , NPNVariable variable , void *value ) ; //Functions for scriptablePluginClass bool plugin_has_method (NPObject *obj , NPIdentifier methodName ) ; bool plugin_invoke (NPObject *obj , NPIdentifier methodName , const NPVariant *args , uint32_t argCount , NPVariant *result ) ; bool hasProperty (NPObject *obj , NPIdentifier propertyName ) ; bool getProperty (NPObject *obj , NPIdentifier propertyName , NPVariant *result ) ; //////////////////////////////////// static struct NPClass scriptablePluginClass = { NP_CLASS_STRUCT_VERSION , NULL , NULL , NULL , plugin_has_method , plugin_invoke , NULL , hasProperty , getProperty , NULL , NULL , } ; //接口的实现 NPError NP_Initialize (NPNetscapeFuncs * browserFuncs ) { browser = browserFuncs ; return NPERR_NO_ERROR ; } NPError NP_GetEntryPoints (NPPluginFuncs * pluginFuncs ) { pluginFuncs ->version = 11 ; pluginFuncs ->size = sizeof (pluginFuncs ) ; pluginFuncs ->newp = NPP_New ; pluginFuncs ->destroy = NPP_Destroy ; pluginFuncs ->setwindow = NPP_SetWindow ; pluginFuncs ->newstream = NPP_NewStream ; pluginFuncs ->destroystream = NPP_DestroyStream ; pluginFuncs ->asfile = NPP_StreamAsFile ; pluginFuncs ->writeready = NPP_WriteReady ; pluginFuncs ->write = (NPP_WriteProcPtr )NPP_Write ; pluginFuncs ->print = NPP_Print ; pluginFuncs ->event = NPP_HandleEvent ; pluginFuncs ->urlnotify = NPP_URLNotify ; pluginFuncs ->getvalue = NPP_GetValue ; pluginFuncs ->setvalue = NPP_SetValue ; return NPERR_NO_ERROR ; } void NP_Shutdown ( void ) { } bool plugin_has_method (NPObject *obj , NPIdentifier methodName ) { // This function will be called when we invoke method on this plugin elements. NPUTF8 *name = browser ->utf8fromidentifier (methodName ) ; bool result = strcmp (name , plugin_method_name_open ) == 0 ; browser ->memfree (name ) ; return result ; } bool plugin_invoke (NPObject *obj , NPIdentifier methodName , const NPVariant *args , uint32_t argCount , NPVariant *result ) { // Make sure the method called is "open". NPUTF8 *name = browser ->utf8fromidentifier (methodName ) ; if ( strcmp (name , plugin_method_name_open ) == 0 ) { browser ->memfree (name ) ; BOOLEAN_TO_NPVARIANT ( false , *result ) ; // Meke sure the arugment has at least one String parameter. if (argCount > 0 && NPVARIANT_IS_STRING (args [ 0 ] ) ) { // Build CFURL object from the arugment. NPString str = NPVARIANT_TO_STRING (args [ 0 ] ) ; CFURLRef url = CFURLCreateWithBytes (NULL , ( const UInt8 * )str. UTF8Characters , str. UTF8Length , kCFStringEncodingUTF8 , NULL ) ; if (url ) { // Open URL with the default application by Launch Service. OSStatus res = LSOpenCFURLRef (url , NULL ) ; CFRelease (url ) ; BOOLEAN_TO_NPVARIANT (res == noErr , *result ) ; } } return true ; } browser ->memfree (name ) ; return false ; } bool hasProperty (NPObject *obj , NPIdentifier propertyName ) { return false ; } bool getProperty (NPObject *obj , NPIdentifier propertyName , NPVariant *result ) { return false ; } //NPP Functions Implements NPError NPP_New (NPMIMEType pluginType , NPP instance , uint16_t mode , int16_t argc , char * argn [ ] , char * argv [ ] , NPSavedData * saved ) { // Create per-instance storage //obj = (PluginObject *)malloc(sizeof(PluginObject)); //bzero(obj, sizeof(PluginObject)); //obj->npp = instance; //instance->pdata = obj; if ( !instance ->pdata ) { instance ->pdata = browser ->createobject (instance , &scriptablePluginClass ) ; } // Ask the browser if it supports the CoreGraphics drawing model NPBool supportsCoreGraphics ; if (browser ->getvalue (instance , NPNVsupportsCoreGraphicsBool , &supportsCoreGraphics ) != NPERR_NO_ERROR ) supportsCoreGraphics = FALSE ; if ( !supportsCoreGraphics ) return NPERR_INCOMPATIBLE_VERSION_ERROR ; // If the browser supports the CoreGraphics drawing model, enable it. browser ->setvalue (instance , NPPVpluginDrawingModel , ( void * )NPDrawingModelCoreGraphics ) ; return NPERR_NO_ERROR ; } NPError NPP_Destroy (NPP instance , NPSavedData ** save ) { // If we created a plugin instance, we'll destroy and clean it up. NPObject *pluginInstance =instance ->pdata ; if ( !pluginInstance ) { browser ->releaseobject (pluginInstance ) ; pluginInstance = NULL ; } return NPERR_NO_ERROR ; } NPError NPP_SetWindow (NPP instance , NPWindow * window ) { return NPERR_NO_ERROR ; } NPError NPP_NewStream (NPP instance , NPMIMEType type , NPStream * stream , NPBool seekable , uint16_t * stype ) { *stype = NP_ASFILEONLY ; return NPERR_NO_ERROR ; } NPError NPP_DestroyStream (NPP instance , NPStream * stream , NPReason reason ) { return NPERR_NO_ERROR ; } int32 NPP_WriteReady (NPP instance , NPStream * stream ) { return 0 ; } int32 NPP_Write (NPP instance , NPStream * stream , int32 offset , int32 len , void * buffer ) { return 0 ; } void NPP_StreamAsFile (NPP instance , NPStream * stream , const char * fname ) { } void NPP_Print (NPP instance , NPPrint * platformPrint ) { } int16_t NPP_HandleEvent (NPP instance , void * event ) { return 0 ; } void NPP_URLNotify (NPP instance , const char * url , NPReason reason , void * notifyData ) { } NPError NPP_GetValue (NPP instance , NPPVariable variable , void *value ) { NPObject *pluginInstance =NULL ; switch (variable ) { case NPPVpluginScriptableNPObject : // If we didn't create any plugin instance, we create it. pluginInstance =instance ->pdata ; if (pluginInstance ) { browser ->retainobject (pluginInstance ) ; } * (NPObject ** )value = pluginInstance ; break ; default : return NPERR_GENERIC_ERROR ; } return NPERR_NO_ERROR ; } NPError NPP_SetValue (NPP instance , NPNVariable variable , void *value ) { return NPERR_GENERIC_ERROR ; } |
测试代码
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
<html>
<head> <script> function run() { var plugin = document.getElementById("pluginId"); plugin.open("http://www.geeklu.com"); } </script> </head> <body > <embed width="0" height="0" type="test/x-open-with-default-plugin" id="pluginId"> <button onclick="run()">run </button> </body> </html> |
8 Responses to NPAPI 插件 编程起步