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插件框架能够支持高度模块化和可扩展的应用程序开发。

相关推荐
虾球xz2 小时前
游戏引擎学习第276天:调整身体动画
c++·学习·游戏引擎
Aric_Jones2 小时前
lua入门语法,包含安装,注释,变量,循环等
java·开发语言·git·elasticsearch·junit·lua
Akiiiira2 小时前
【日撸 Java 三百行】Day 12(顺序表(二))
java·开发语言
虾球xz2 小时前
游戏引擎学习第275天:将旋转和剪切传递给渲染器
c++·学习·游戏引擎
EndingCoder2 小时前
2025年JavaScript性能优化全攻略
开发语言·javascript·性能优化
码上淘金6 小时前
【Python】Python常用控制结构详解:条件判断、遍历与循环控制
开发语言·python
Brilliant Nemo6 小时前
四、SpringMVC实战:构建高效表述层框架
开发语言·python
虾球xz7 小时前
游戏引擎学习第268天:合并调试链表与分组
c++·学习·链表·游戏引擎
fpcc7 小时前
跟我学c++高级篇——模板元编程之十三处理逻辑
c++
格林威8 小时前
Baumer工业相机堡盟工业相机的工业视觉中为什么偏爱“黑白相机”
开发语言·c++·人工智能·数码相机·计算机视觉