Qt Webkit中浏览器插件Plugin设计实现是我们要介绍的内容,我们都知道浏览器中有一套由Netscape浏览器传承下来的插件接口,
包括webkit,firefox都是支持的,但是那个开发起来比较困难,并且是平台相关的,借助于Qt的跨平台的特性,可以方便地为Qt开
发出一套跨平台的插件。
QtWebkit中插件可以有两种,一种Mime必须是application/x-qt-plugin或者application/x-qt-styled-widget,而另外一种则无需固定,
可以是除了前面的两种以外任意其它Mime类型。
前一种相对来说开发起来比较容易,只需重新实现
QObject * QWebPage::createPlugin (const QString& classid, const QUrl& url, const QStringList& paramNames, const QStringList ¶mValues)
这个函数即可,这个函数会把HTML文件中的参数都传递进来
下面是一个例子:
class PluginPage : public QWebPage { public: PluginPage(QObject *parent = 0) : QWebPage(parent) {} protected: virtual QObject *createPlugin(const QString &classid, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues) { QObject *result = 0; if (classid == "pushbutton") result = new QPushButton(); else if (classid == "lineedit") result = new QLineEdit(); if (result) result->setObjectName(classid); //可以进行一些处理 return result; } }
这样下面的网页就可以一个pushbutton了:
<html> <body> <object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/> </body> </html>
并且还可以在JavaScript访问到QPushbutton,例如:
document.getElementById('mybutton').text将会返回按钮上的字符串。
上面介绍的插件设计方式中虽然方便,但是其Mime类型只能是application/x-qt-plugin或者application/x-qt-styled-widget,
这个有时候可能满足不了实际应用需求,那么另一种就没有这种限制,那可以是任意Mime类型的。这种设计需要重新实现
QWebPluginFactory这个纯虚基类。先看看他的声明:
class QWEBKIT_EXPORT QWebPluginFactory : public QObject { …… public: struct Plugin { QString name; QString description; QList<MimeType> mimeTypes; }; explicit QWebPluginFactory(QObject* parent = 0); virtual ~QWebPluginFactory(); virtual QList<Plugin> plugins() const = 0; virtual void refreshPlugins(); virtual QObject *create(const QString& mimeType, const QUrl&, const QStringList& argumentNames, const QStringList& argumentValues) const = 0; virtual bool extension(Extension extension, const ExtensionOption* option = 0, ExtensionReturn* output = 0); virtual bool supportsExtension(Extension extension) const; …… };
重点要实现的接口是plugins,用于获取plugin的列表,用于webkit内部判断该mime类型是否被支持,如果可以支持,
那么就会调用create来创建这个插件,而具体打开哪个文件以及参数都会传递进来。
后两个extension和supportsExtension接口暂时没有发现有什么用处,暂不考虑。
因此重新实现的WebPluginFactory如下:
class WebPluginFactory: public QWebPluginFactory { public: WebPluginFactory(QObject *parent = 0); ~WebPluginFactory(){}; QList<QWebPluginFactory::Plugin> plugins() const; void refreshPlugins(); QObject *create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const ; bool extension(QWebPluginFactory::Extension extension, const QWebPluginFactory::ExtensionOption *option = 0, QWebPluginFactory::ExtensionReturn *output = 0); bool supportsExtension(QWebPluginFactory::Extension extension) const; private: // 用于将载入的插件记录下来 mutable QList<QList<QWebPluginFactory::Plugin> > pluginslist; mutable QList<WebKitPluginInteface *> interfaces; };
具体实现主要是create和plugins两个函数:
QList<QWebPluginFactory::Plugin> WebPluginFactory::plugins() const { const char * s=getenv("BROWSER_PLUGIN_DIR"); static bool isFirst=true; if(!isFirst) { return pluginslist; } isFirst=false; QString spath; if(s) spath=s; else { spath="."; } QDir dir(spath); QStringList filters; QString abspath=dir.absolutePath(); filters<<"libqtweb*.so"; //查找下面的动态库,linux下是so,windows下则应该是dll, QStringList files=dir.entryList(filters); foreach(QString file,files) { file=dir.filePath(file); QPluginLoader loader(file,0); QObject * obj= loader.instance(); //下面是载入自定义的接口,只有这样才能支持动态插件创建,如果固定死了,将不利于扩展,后一节会介绍这部分内容 WebKitPluginInteface * interface= qobject_cast<WebKitPluginInteface*> (obj); if (interface == 0) { //ignore error when loading so ; continue; } interface->plugins(); plugins.append(interface->plugins()); pluginslist.append(interface->plugins()); interfaces.append(interface); } return plugins; } void WebPluginFactory::refreshPlugins() { Reload(); } QObject * WebPluginFactory::create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const { for(int i=0;i<pluginslist.size();i++){ for( int j=0;j< pluginslist[i].size();j++){ foreach(WebPluginFactory::MimeType mt, pluginslist[i][j].mimeTypes){ if(mt.name == mimeType) //查找到,创建实例 return interfaces[i]->create( mimeType, url, argumentNames, argumentValues); } } } return NULL; //如果没有,直接返回NULL,webkit会进行处理的 }
这两个最主要的接口都是围绕着mimetype进行的,通过返回的列表告诉webkit插件支持什么类型的文件,而create则根据mimetype来识别文件类型,
然后创建相应的插件。
下面会简单的创建一个插件来演示如何创建一个插件。
上面讲到可以通过扩展QWebPage接口进行动态载入插件,但是插件的接口并没有明确,这里通过介绍自定义的接口来实现插件的动态载入。
首先是接口的定义:
class WebKitPluginInteface { public: virtual ~WebKitPluginInteface(){}; virtual QList<QWebPluginFactory::Plugin> plugins()const =0; virtual QObject *create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const =0; }; Q_DECLARE_INTERFACE(WebKitPluginInteface, "baizx.cnblogs.com/1.0")
这样自定义的插件就可以通过实现这个接口来实现定制的插件。下面是一个例子:
class TestPlugin :public QObject,public WebKitPluginInteface { Q_OBJECT Q_INTERFACES(WebKitPluginInteface) public: TestPlugin(QObject * parent=0): WebkitPlugin(parent){}; virtual ~TestPlugin(){}; virtual QList<QWebPluginFactory::Plugin> plugins()const ; virtual QObject *create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const ; }; QList<QWebPluginFactory::Plugin> TestPlugin::plugins()const { QList<QWebPluginFactory::Plugin> plugins ; QWebPluginFactory::Plugin plugin; QWebPluginFactory::MimeType mimeType; QStringList strings; plugin.name="testplugin"; plugin.description="testplugin !!!"; mimeType.name="application/x-textedit"; mimeType.description="test textedit"; strings.append(".etxt"); mimeType.fileExtensions=strings; QList<QWebPluginFactory::MimeType> mimeTypes; mimeTypes.append(mimeType); plugin.mimeTypes=mimeTypes; plugins.append(plugin); return plugins; } QObject *TestPlugin::create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const { QTextEdit * edit= new QTextEdit(); edit->setObjectName("我是插件"); edit->setPlainText(mimeType + url.toString() ); Q_UNUSED(argumentNames); Q_UNUSED(argumentValues); return edit; }
这样一个简单的插件就创建完毕了,具体实际应用中可能会用到很到参数,并且会载入实际的内容,这里只是一个演示。
小结:Qt Webkit中浏览器插件设计实现的内容介绍完了,希望通过本文的学习能对你有所帮助!