为了允许的QWebView加载插件,必须使能QWebView的Javascript和Plugins属性,使能方法为:

QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptEnabled,true);
QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled,true);

或者

//这里假设webView是QWebView的对象:QWebView *webView;
webView->settings()->setAttribute(QWebSettings::JavascriptEnabled,true);
webView->settings()->setAttribute(QWebSettings::PluginsEnabled,true);

然后为QWebView添加插件工厂,这个插件工厂中包含了QWebView中所有可用的插件库,当然这个插件工厂中包含哪些插件得由我们程序员来定。添加插件工厂的方法为:
//为QWebView添加插件工厂,即告诉QWebView有哪些插件可用。
//这里的 WebkitPluginFactory 是Qt的虚类 QWebPluginFactory 的实现类,后面会讲到这个类。
webView->page()->setPluginFactory(new WebkitPluginFactory(this));

下面我们就来实现这个插件工厂类WebkitPluginFactory, 主要需要实现的就是 QWebPluginFactory  中的两个虚函数:

virtual QObject *create(const QString &mimeType, const QUrl &url, 
      const QStringList &argumentNames,const QStringList & argumentValues )const = 0;
virtual QList<Plugin>    plugins () const = 0;
plugins() 方法为获取所有可用的插件列表, create() 方法则根据mimeType等参数来决定创建相应的插件。下面给出这个类的实现代码:

webkitpluginfactory.h :

#ifndef WEBKITPLUGINFACTORY_H
#define WEBKITPLUGINFACTORY_H
 
#include <QWebPluginFactory>
#include <QUrl>
#include "webkitplugininterface.h"
 
class WebkitPluginFactory : public QWebPluginFactory
{
    Q_OBJECT
public:
    WebkitPluginFactory(QObject *parent = 0);
    QObject *create ( const QString & mimeType, const QUrl & url, const QStringList & argumentNames, const QStringList & argumentValues ) const;
    QList<QWebPluginFactory::Plugin> plugins () const;
 
private:
    // 插件列表
    mutable QList<QList<QWebPluginFactory::Plugin> > pluginslist;
    //插件接口,这个接口是我们自定义的插件的同意接口。
    //这个接口在后面会讲到。
    mutable QList<WebKitPluginInterface *> interfaces;
};
 
 
#endif // WEBKITPLUGINFACTORY_H

webkitpluginfactory.cpp :

#include "webkitpluginfactory.h"
#include <QPluginLoader>
 
#include <QDebug>
#include <QDir>
 
 
WebkitPluginFactory::WebkitPluginFactory(QObject *parent) :
        QWebPluginFactory()
{
    qDebug()<<"debug : WebkitPluginFactory";
}
 
QList<QWebPluginFactory::Plugin> WebkitPluginFactory::plugins () const
{
 
    //const char * s=getenv("BROWSER_PLUGIN_DIR");
    const char *s = "/home/nxx/FlashPlugin-build-desktop";
    static bool isFirst=true;
    static QList<QWebPluginFactory::Plugin> plugins;
    if(!isFirst)
    {
        return plugins;
    }
    isFirst=false;
    plugins.clear();
 
    QString spath;
    if(s)
        spath=s;
    else
        spath=".";
 
    QDir dir(spath);
    QStringList filters;
    QString abspath=dir.absolutePath();
    qDebug()<<abspath;
 
    //获取指定目录下的所有插件,linux下是插件库的后缀为so,windows下则是dll,
    filters<<"lib*.so";
    QStringList files=dir.entryList(filters);
    qDebug()<<"files: "<<files;
    foreach(QString file,files)
    {
        qDebug()<<QLibrary::isLibrary(file);
        file=dir.filePath(file);
        qDebug()<<"path: "<<file;
        QPluginLoader loader(file);
        QObject * obj= loader.instance();
        if(obj==0)
            qDebug()<<"error: "<<loader.errorString();
        //下面是载入自定义的接口,只有这样才能支持动态插件创建,如果固定死了,将不利于扩展
        WebKitPluginInterface * interface= qobject_cast<WebKitPluginInterface*> (obj);
        if(interface==0)
        {
            qDebug()<<"ignore error when loading so" ;
            continue;
        }
        qDebug()<<"load plugins: "<<interface->plugins().at(0).name;
        plugins.append(interface->plugins());
        pluginslist.append(interface->plugins());
        interfaces.append(interface);
    }
    if(plugins.isEmpty()){
        qDebug()<<"no plugins is loaded!";
    }
    return plugins;
}
 
 
QObject * WebkitPluginFactory::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(QWebPluginFactory::MimeType mt, pluginslist[i][j].mimeTypes)
            {
                if(mt.name == mimeType) //更具MIME类型,创建相应的插件实例
                    return interfaces[i]->
                            create( mimeType, url, argumentNames, argumentValues);
            }
        }
    }
    return NULL; //如果没有,直接返回NULL,webkit会进行处理的
}

下面就可以开始编写插件库。首先我们定义插件的统一接口,然后每个插件类只需实现该接口就行了,这样有利于扩展插件库。

自定义的插件接口:

webkitplugininterface.h :

#ifndef WEBKITPLUGININTERFACE_H
#define WEBKITPLUGININTERFACE_H
#include <QWebPluginFactory>
 
class WebKitPluginInterface
{
public:
    virtual ~WebKitPluginInterface(){};
    virtual QList<QWebPluginFactory::Plugin> plugins()const =0;
    virtual QObject *create(const QString &mimeType,
                            const QUrl &url,
                            const QStringList &argumentNames,
                            const QStringList &argumentValues) const =0;
};
 
//声明WebKitPluginInterface为一个接口
Q_DECLARE_INTERFACE(WebKitPluginInterface, "com.plugin.uvchip.www/1.0")
#endif // WEBKITPLUGININTERFACE_H
 

上面的那段代码中的Q_DECLARE_INTERFACE() 是在定义接口是必须添加声明。下面是Qt对这个宏的说明:

Q_DECLARE_INTERFACE ( ClassName, Identifier )
This macro associates the given Identifier (a string literal) to the interface class called ClassName. The Identifier must be unique.
下面我们开始实现这个接口:
我们将flashplugin编译成库,这样就可以供插件工厂WebkitPluginFactory加载访问了。

flashplugin.h :

#ifndef FLASHPLUGIN_H
#define FLASHPLUGIN_H
 
#if defined(FLASHPLUGIN_LIBRARY)
#  define FLASHPLUGINSHARED_EXPORT Q_DECL_EXPORT
#else
#  define FLASHPLUGINSHARED_EXPORT Q_DECL_IMPORT
#endif
 
#include "webkitplugininterface.h"
#include <QtPlugin>
 
class FLASHPLUGINSHARED_EXPORT FlashPlugin : public QObject, public WebKitPluginInterface  {
        Q_OBJECT
        Q_INTERFACES(WebKitPluginInterface) //声明WebKitPluginInterface是一个接口
    public:
        FlashPlugin(): WebKitPluginInterface(){};
        ~FlashPlugin(){};
        QList<QWebPluginFactory::Plugin> plugins()const ;
        QObject *create(const QString &mimeType,
                                const QUrl &url,
                                const QStringList &argumentNames,
                                const QStringList &argumentValues) const ;
 
};
#endif // FLASHPLUGIN_H

flashplugin.cpp :

#include "flashplugin.h"
 
#include <QTextEdit>
#include <QUrl>
#include <QDebug>
 
QList<QWebPluginFactory::Plugin> FlashPlugin::plugins()const
{
    QWebPluginFactory::MimeType mimeType;
    mimeType.name="application/x-shockwave-flash";
    mimeType.description=QObject::tr("flash");
    mimeType.fileExtensions.append(".flv");
    mimeType.fileExtensions.append(".f4v");
    mimeType.fileExtensions.append(".swf");
 
    QList<QWebPluginFactory::MimeType> mimeTypes;
    mimeTypes.append(mimeType);
 
    QWebPluginFactory::Plugin plugin;
    plugin.name=QObject::tr("External Video viewer plugin");
    plugin.description=QObject::tr("Use vlc to open video files !!!");
    plugin.mimeTypes=mimeTypes;
 
    QList<QWebPluginFactory::Plugin> plugins ;
    plugins.append(plugin);
    return plugins;
}
QObject *FlashPlugin::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() +"\n\n"
         +QString::fromUtf8("这里本来是需要adobeFlash插件的,")+"\n"
         +QString::fromUtf8("但现在替换成了我们自定义的插件(QTextEdit插件了)。") );
 
    Q_UNUSED(argumentNames);
    Q_UNUSED(argumentValues);
    qDebug()<<"create flash plugin";
    return edit;
}
 
//Q_EXPORT_PLUGIN2()必不可少,
//只有这样FlashPlugin插件类才为外部可见,插件名为WebkitPluginFlash
Q_EXPORT_PLUGIN2(WebkitPluginFlash, FlashPlugin)

Q_EXPORT_PLUGIN2 在Qt帮助文档中的说明如下:

Q_EXPORT_PLUGIN2 ( PluginName, ClassName )
This macro exports the plugin class ClassName for the plugin specified by PluginName. The value of PluginName should correspond to the TARGET specified in the plugin's project file.

There should be exactly one occurrence of this macro in the source code for a Qt plugin, and it should be used where the implementation is written rather than in a header file.

Q_EXPORT_PLUGIN2(WebkitPluginFlash, FlashPlugin) 中的WebkitPluginFlash为编译之后生成的库的名字,这里的生成的库的完整名字为:libWebkitFlashPlugin.so, FlashPlugin 是插件类名。

现在只要把生成的libWebkitFlashPlugin.so插件库拷贝到webkitpluginfactory插件工厂能搜到的目录下就行了(本例中我在webkitpluginfactory.cpp中指定的位置为 const char *s = "/home/nxx/FlashPlugin-build-desktop";)。

上面的插件库和前面的工厂类,QWebView对象组合在一起就可以实现:

当用QWebView打开包含了需要 mimeType.name="application/x-shockwave-flash" 类型的插件的网页的时候,就会调用到我们自定义的flashplugin插件了。

效果如下:

pluginView

 posted on 2011-04-15 21:46  Braincol  阅读(6349)  评论(0编辑  收藏  举报