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

相关推荐
捕鲸叉13 分钟前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer17 分钟前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq20 分钟前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
记录成长java2 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山2 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
青花瓷2 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
睡觉谁叫~~~2 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
音徽编程2 小时前
Rust异步运行时框架tokio保姆级教程
开发语言·网络·rust
观音山保我别报错2 小时前
C语言扫雷小游戏
c语言·开发语言·算法
小屁孩大帅-杨一凡3 小时前
java后端请求想接收多个对象入参的数据
java·开发语言