NPAPI插件是一套老掉牙的chrome浏览器插件环境。很少还有在使用,但是实际要真需要的时候,问题还是要解决的。
NPAPI插件与JS接口交互+回调交互,一般网上也能找到一些例子,这些例子能解决基本问题。例如实现几个接口+实现几个回调函数与js交互。网上能找到的解决方法有一些弊端。
缺点一:
但是当有上百个接口+上百个回调的时候,他们的方法就不好解决问题了。
缺点二:
当参数多变的时候问题也不好解决。例如
图中参数4,直接是一个JS回调函数,这种如何处理,是解决不了的。
解决办法
怎么创建一个NPAPI插件模板,这里就不介绍了,资源很多。我介绍一下
1).如何处理大批量的接口+
2).大批量的回调函数使用+
3).第三方应用时的奇怪参数转换VARIANT+
1.如何处理大批量的接口
接口函数入口一般是这样的,包括了字符返回值的转换
如果有100个插件接口都写在这个入口,那真的很难维护,但是如何用一个接口转换把不同接口名,不同参数的接口统一处理了。下面是我的方法。写接口的时候只写一个统一处理接口,
定义:NPIdentifier m_idCallCplus;
初始化:m_idCallCplus = NPN_GetStringIdentifier("callCplus");
接口方法注册:
方法入口处理:
bool CPluginObject::invoke(NPIdentifier methodName/*调用接口函数名*/,
const NPVariant *args/*接口参数列表*/,
uint32_t argCount/*参数数量*/,
NPVariant *result/*返回值指针*/)
{
if (methodName == pMe->m_idCallCplus && argCount >= 2/*取最大参数接口参数数量*/ && NPVARIANT_IS_STRING(args[0]) && NPVARIANT_IS_STRING(args[1]))
{
NPString args0 = NPVARIANT_TO_STRING(args[0]);
//args[0] 一般设为你的接口识别名字,plugin.callCplus("WEB_getAppDataDir","");
NPString args1 = NPVARIANT_TO_STRING(args[1]); //第二个参数开始变成你真正需要的参数
char args0_[1024] = {0};
char args1_[1024] = {0};
memcpy(args0_, args0.UTF8Characters, args0.UTF8Length);
memcpy(args1_, args1.UTF8Characters, args1.UTF8Length);
//定义一个公共类m_pManager 专门用来处理接口列表
char* temp = m_pManager->callCplus(args0_, args1_/*针对不同的参数列表,需要定义一个结构来传参数*/);
NPUTF8* resultVal = static_cast<NPUTF8*>(NPN_MemAlloc(strlen(temp) + 1));
strcpy(resultVal, temp);
STRINGZ_TO_NPVARIANT(resultVal, *result);
return true;
}
return false;
}
这样不管有多少接口,多少奇怪的参数都可以以不变应万变,简单处理,贴一下我的处理方式
头文件 QHmanger.h
QHmanger.cpp
2.如何大批量的处理JS的回调函数
需要在插件接口文件plugin.cpp里面实现 Js回调函数指针映射列表,不然是没法被初始化的,我把这个类的写法贴出来,
// pluginCallback begin/
#include <windows.h>
#include <time.h>
//js回调函数索引
#define NP_InitSDK_CallIndex 0
第2个
....
第N个
//JS回调注册名字宏定义
#define NP_InitSDK_CallName "WEB_initSDK"
第2个
....
第N个
pluginCallback::pluginCallback()
{
np_callback.push_back({ NP_InitSDK_CallIndex , NP_InitSDK_CallName });
第2个
....
第N个
}
pluginCallback::~pluginCallback()
{
call_back_is_valid_ = false;
np_callback.clear();
}
//函数指针存入队列
bool pluginCallback::pushCallbackFunc(char* funcName, NPVariant js_in_cb)
{
bool reged = false;
for (int i = 0; i < np_callback.size(); ++i)
{
if (0 == strcmp(funcName, np_callback[i].call_name))
{
NP_Callback cb;
cb.np_Jscb = (NPVariant)js_in_cb;
if (np_callback[i].call_backs_list.size() >= 1)
{
np_callback[i].call_backs_list[0] = cb;
}
else {
np_callback[i].call_backs_list.push_back(cb);
}
reged = true;
}
}
return reged;
}
//获取队列中的对应函数指针
bool pluginCallback::getCallbackFunc(char* funcName, NPVariant& js_out_cb)
{
bool getcall = false;
for (int i = 0; i < np_callback.size(); ++i)
{
if (0 == strcmp(funcName, np_callback[i].call_name))
{
if (np_callback[i].call_backs_list.size() >= 1)
{
NP_Callback cb;
cb = np_callback[i].call_backs_list[0];
//if (NULL == cb.np_Jscb || call_back_is_valid_ == false) return false;
js_out_cb = (NPVariant)cb.np_Jscb;
getcall = true;
}
else
getcall = false;
break;
}
}
return getcall;
}
// pluginCallback end/
当然定义了一个回调函数指针映射表,只是第一步,接下来是Js回调函数注册,定义回调执行函数二次转换方法
我们需要定义一个实际执行回调和NPAPI回调转JS的二次转换,因为你直接执行是不行,类型不同牛头不对马嘴。
static void JSCallbackFun(void * oper_func_name, void * param);
把这个新定义的二次转换函数当成指针传给,回调的执行函数。
同样批量处理的第一个函数参数需要是对应的映射表的Js回调名字,说着很复杂,下面会给使用方式,
3.奇怪的参数转换
在NPAPI插件里,通用的参数有 “整形”,“double型”,“字符型”,“布尔型”,“Object型”
如果是可以直接当函数数指针传递,但是使用却要转换,像这样
NPObject *m_JscallbackTmpObj; //页面函数使用的临时输出回调 指针数组
plugin->m_JscallbackTmpObj = NPN_RetainObject(NPVARIANT_TO_OBJECT(args[num + 1]));
然后在回调执行函数里找到指针执行。
上面的讲的过于复杂,还是上代码比较直接,代码使用vs2017编译的,只需要看如何用的就行,不用去真的跑起来,安装vs2017也是比较麻烦的。
NPAPI代码:https://download.csdn.net/download/abc1029386453/11465096