目录
1.引言
2.实现原理
3.实际应用
3.1.界面控制
3.2.访问服务管理插件
4.总结
1.引言
在CTK框架(三): 插件的安装讲解了插件的安装、启动、停止和卸载方法,对于一个插件可以这样写;但是如果是在一个大型的应用程序中,里面有很多插件,就需要一个管理这些插件的服务,CTK官方就提供给了一个:PluginAdmin。
PluginAdmin它本身也是一个插件,它提供服务的接口有:
struct PluginAdmin
{virtual ~PluginAdmin() {}virtual void installAllPlugin() = 0;virtual void startAllPlugin() = 0;virtual void stopAllPlugin() = 0;virtual void uninstallAllPlugin() = 0;
};
- installAllPlugin:安装系统所有插件
- startAllPlugin:启动系统所有插件
- stopAllPlugin:停止系统所有插件
- uninstallAllPlugin: 卸载系统所有插件
2.实现原理
跟其它CTK插件服务的一样,在PluginAdmin插件里面实现了接口PluginAdmin,代码如下:
pluginadminservice.h
#ifndef PLUGINADMINSERVICE_H
#define PLUGINADMINSERVICE_H#include <QObject>
#include <service/pluginadmin/pluginAdmin.h>
#include <ctkPluginContext.h>
#include <service/event/ctkEventAdmin.h>class PluginAdminService :public QObject,public PluginAdmin
{Q_OBJECTQ_INTERFACES(PluginAdmin)public:explicit PluginAdminService(ctkPluginContext* context,QObject *parent = nullptr);~PluginAdminService();public:void installAllPlugin() Q_DECL_OVERRIDE;void startAllPlugin() Q_DECL_OVERRIDE;void stopAllPlugin() Q_DECL_OVERRIDE;void uninstallAllPlugin() Q_DECL_OVERRIDE;signals:private slots:private:ctkPluginContext *m_context;ctkDictionary m_dictionary;ctkProperties m_properties;//事件管理服务插件ctkEventAdmin *m_eventAdmin;QSharedPointer<ctkPluginFramework> m_framework;QStringList m_libFilter;QString m_path;
};#endif // PLUGINADMINSERVICE_H
pluginadminservice.cpp
#include "pluginadminservice.h"
#include <service/event/ctkEventConstants.h>
#include <QCoreApplication>
#include <QDirIterator>
#include <QJsonArray>
#include <QThread>
#include <ctkPluginException.h>
#include <ctkPluginFrameworkFactory.h>
#include <ctkPluginFrameworkLauncher.h>PluginAdminService::PluginAdminService(ctkPluginContext* context, QObject* parent) :QObject(parent),m_context(context),m_eventAdmin(nullptr),m_framework(nullptr)
{//注册插件管理服务context->registerService<PluginAdmin>(this);ctkServiceReference eventRef = context->getServiceReference<ctkEventAdmin>();m_eventAdmin = qobject_cast<ctkEventAdmin*>(context->getService(eventRef));if (eventRef) {context->ungetService(eventRef);}m_path = QCoreApplication::applicationDirPath() + "/plugins";ctkPluginFrameworkLauncher::addSearchPath(m_path, true);
#if defined(Q_OS_WIN)m_libFilter << "*.dll";
#elif defined(Q_OS_LINUX)m_libFilter << "*.so";
#elif defined(Q_OS_MAC)m_libFilter << "*.dylib";
#endif
}PluginAdminService::~PluginAdminService()
{
}void PluginAdminService::installAllPlugin()
{QDirIterator dirIter(m_path, m_libFilter, QDir::Files);QString fileLocation;while (dirIter.hasNext()) {try {fileLocation = dirIter.next();if (!fileLocation.contains(QString("pluginadmin"))) {m_context->installPlugin(QUrl::fromLocalFile(fileLocation));qDebug() << QString::fromLocal8Bit("1.1 安装插件:") << fileLocation;}else {qDebug() << QString::fromLocal8Bit("1.2 未重复安装插件:") << fileLocation;}}catch (const ctkPluginException& exc) {qCritical() << fileLocation << exc.what();}}
}void PluginAdminService::startAllPlugin()
{foreach(const QSharedPointer<ctkPlugin> &plugin, m_context->getPlugins()) {try {if (QString("system.plugin") != plugin->getSymbolicName()&& QString("pluginadmin") != plugin->getSymbolicName()) {plugin->start();qDebug() << QString::fromLocal8Bit("2.1 启动插件:") << plugin->getSymbolicName();}else {qDebug() << QString::fromLocal8Bit("2.2 未重复启动插件:") << plugin->getSymbolicName();}}catch (const ctkPluginException& exc) {qCritical() << exc.what();}}
}void PluginAdminService::stopAllPlugin()
{foreach(const QSharedPointer<ctkPlugin> &plugin, m_context->getPlugins()) {try {if (QString("system.plugin") != plugin->getSymbolicName()&& QString("pluginadmin") != plugin->getSymbolicName()) {qDebug() << QString::fromLocal8Bit("3.1 停止插件:") << plugin->getSymbolicName();plugin->stop();}else {qDebug() << QString::fromLocal8Bit("3.2 未停止运行插件:") << plugin->getSymbolicName();}}catch (const ctkPluginException& exc) {qCritical() << exc.what();}}
}void PluginAdminService::uninstallAllPlugin()
{foreach(const QSharedPointer<ctkPlugin> &plugin, m_context->getPlugins()) {try {if (QString("system.plugin") != plugin->getSymbolicName()&& QString("pluginadmin") != plugin->getSymbolicName()) {qDebug() << QString::fromLocal8Bit("4.1 卸载插件:") << plugin->getSymbolicName();plugin->uninstall();}}catch (const ctkPluginException& exc) {qCritical() << exc.what();}}foreach(const QSharedPointer<ctkPlugin> &plugin, m_context->getPlugins()) {qDebug() << QString::fromLocal8Bit("4.2 未卸载插件:") << plugin->getSymbolicName();}
}
其实实现也不难,以安装插件的installAllPlugin函数实现为例,如果是windows,就是在应用程序的插件目录下面循环查找.dll文件,依次调用ctkPluginContext的installPlugin函数,安装插件,所以这个插件目录不能存放不是插件的.dll文件,否则就会出现安装异常。
启动器
pluginadminactivator.h
#ifndef PLUGINADMINACTIVATOR_H
#define PLUGINADMINACTIVATOR_H#include "pluginadminthread.h"
#include "pluginadmindialog.h"#include <ctkPluginActivator.h>#include <QObject>class PluginAdminActivator : public QObject, public ctkPluginActivator
{Q_OBJECTQ_INTERFACES(ctkPluginActivator)Q_PLUGIN_METADATA(IID "pluginadmin")public:PluginAdminActivator();void start(ctkPluginContext* context) Q_DECL_OVERRIDE;void stop(ctkPluginContext* context) Q_DECL_OVERRIDE;private:QThread *m_pluginAdminThread;PluginAdminDialog* m_pluginAdminDialog;
};#endif // PLUGINADMINACTIVATOR_H
pluginadminactivator.cpp
#include "pluginadminactivator.h"
#include <QDebug>PluginAdminActivator::PluginAdminActivator() :m_pluginAdminThread(nullptr)
{}void PluginAdminActivator::start(ctkPluginContext* context)
{qDebug() << "插件启动";m_pluginAdminThread = new PluginAdminThread(context);m_pluginAdminThread->start();m_pluginAdminDialog = new PluginAdminDialog(context);m_pluginAdminDialog->setWindowTitle(QString::fromLocal8Bit("插件管理器"));m_pluginAdminDialog->show();
}void PluginAdminActivator::stop(ctkPluginContext* context)
{Q_UNUSED(context)if (m_pluginAdminThread){m_pluginAdminThread->exit();m_pluginAdminThread->wait();m_pluginAdminThread->deleteLater();m_pluginAdminThread = nullptr;}
}#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
Q_EXPORT_PLUGIN2(PluginAdmin, PluginAdminActivator)
#endif
3.实际应用
3.1.界面控制
PluginAdmin提供了一个简单的插件管理界面,加载PluginAdmin插件会弹出如图所示界面:
直接在界面就可以管理系统的所有插件了。
3.2.访问服务管理插件
跟CTK插件访问服务的方式一样,访问PluginAdmin提供的服务,一般在系统退出的时候调用,代码如下:
//系统退出函数
void MainWindow::closeEvent(QCloseEvent* e)
{ctkServiceReference reference = context->getServiceReference<PluginAdmin>();if (reference ) {PluginAdmin* pPluginManager = context->getService<PluginAdmin>(reference);assert(pPluginManager );pPluginManager->stopAllPlugin();}
}
4.总结
PluginAdmin是CTK插件框架中的一个重要组件,它负责管理插件的生命周期和插件之间的交互。通过PluginAdmin,可以很方便的管理插件。这使得CTK插件框架能够支持高度模块化和可扩展的应用程序开发。