CTK框架(十):PluginAdmin插件

目录

1.引言

2.实现原理

3.实际应用

3.1.界面控制

3.2.访问服务管理插件

4.总结


1.引言

CTK框架(三): 插件的安装讲解了插件的安装、启动、停止和卸载方法,对于一个插件可以这样写;但是如果是在一个大型的应用程序中,里面有很多插件,就需要一个管理这些插件的服务,CTK官方就提供给了一个:PluginAdmin。

PluginAdmin它本身也是一个插件,它提供服务的接口有:

cpp 复制代码
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

cpp 复制代码
#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_OBJECT
    Q_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

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

cpp 复制代码
#ifndef PLUGINADMINACTIVATOR_H
#define PLUGINADMINACTIVATOR_H

#include "pluginadminthread.h"
#include "pluginadmindialog.h"

#include <ctkPluginActivator.h>

#include <QObject>

class PluginAdminActivator : public QObject, public ctkPluginActivator
{
    Q_OBJECT
    Q_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

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提供的服务,一般在系统退出的时候调用,代码如下:

cpp 复制代码
//系统退出函数
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插件框架能够支持高度模块化和可扩展的应用程序开发。

相关推荐
东风吹柳4 分钟前
观察者模式(sigslot in C++)
c++·观察者模式·信号槽·sigslot
A懿轩A12 分钟前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
汪洪墩14 分钟前
【Mars3d】设置backgroundImage、map.scene.skyBox、backgroundImage来回切换
开发语言·javascript·python·ecmascript·webgl·cesium
云空19 分钟前
《QT 5.14.1 搭建 opencv 环境全攻略》
开发语言·qt·opencv
Anna。。21 分钟前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea
我曾经是个程序员44 分钟前
鸿蒙学习记录
开发语言·前端·javascript
爱上语文1 小时前
宠物管理系统:Dao层
java·开发语言·宠物
大胆飞猪1 小时前
C++9--前置++和后置++重载,const,日期类的实现(对前几篇知识点的应用)
c++
1 9 J1 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
夕泠爱吃糖1 小时前
C++中如何实现序列化和反序列化?
服务器·数据库·c++