文章目录

  • ​​一、前言​​
  • ​​二、新建插件PluginA​​
  • ​​三、新建插件PluginB​​
  • ​​四、测试​​

一、前言

服务追踪:如果想在B插件里使用A服务,可以专门写一个类继承ctkServiceTracker,在这个类里完成对A服务的底层操作,然后在B插件里通过这个类提供的接口来使用回收A服务


二、新建插件PluginA

CTK Plugin Framework插件框架学习--服务追踪_#define


插件结构

  • PluginAService:接口类
  • PluginAImpl:实现类
  • PluginAActivator:激活类

接口类:​​PluginAService​

#ifndef PLUGINA_SERVICE_H
#define PLUGINA_SERVICE_H

#include <QtPlugin>

class PluginAService
{
public:
virtual ~PluginAService() {}
virtual void A_Func() = 0;
};

#define PluginAService_iid "org.commontk.service.demos.PluginAService"
Q_DECLARE_INTERFACE(PluginAService, PluginAService_iid)
//此宏将当前这个接口类声明为接口,后面的一长串就是这个接口的唯一标识。
#endif // PLUGINA_SERVICE_H

实现类:​​PluginAImpl​

#ifndef PLUGINA_IMPL_H
#define PLUGINA_IMPL_H

#include "PluginAService.h"
#include <QObject>

class ctkPluginContext;

class PluginAImpl : public QObject, public PluginAService
{
Q_OBJECT
Q_INTERFACES(PluginAService)
/*
此宏与Q_DECLARE_INTERFACE宏配合使用。
Q_DECLARE_INTERFACE:声明一个接口类
Q_INTERFACES:当一个类继承这个接口类,表明需要实现这个接口类
*/

public:
PluginAImpl(ctkPluginContext* context);
void A_Func() Q_DECL_OVERRIDE;
};

#endif // PLUGINA_IMPL_H
#include "plugina_impl.h"
#include <QtDebug>

PluginAImpl::PluginAImpl(ctkPluginContext* context)
{

}

void PluginAImpl::A_Func()
{
qDebug() << "A_Func()";
}

激活类:​​PluginAActivator​

#ifndef PLUGINAACTIVATOR_H
#define PLUGINAACTIVATOR_H

#include <QObject>
#include "ctkPluginActivator.h"
#include "PluginAService.h"

class PluginAActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "PLUGINA")
//向Qt的插件框架声明,希望将xxx插件放入到框架中。

public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);

private:
QSharedPointer<PluginAService> m_s;
};

#endif // PLUGINAACTIVATOR_H
#include "plugina_activator.h"
#include "plugina_impl.h"
#include <QDebug>

void PluginAActivator::start(ctkPluginContext* context)
{
PluginAImpl* pluginAImpl = new PluginAImpl(context);
context->registerService<PluginAService>(pluginAImpl);
m_s.reset(pluginAImpl);
}

void PluginAActivator::stop(ctkPluginContext* context)
{
Q_UNUSED(context)
//Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用
}

三、新建插件PluginB

因为真正使用到A服务的地方就是B插件的实现类里,所以通过构造函数把tracker给传进去。这里的tracker是在激活类里new的,因为context是从实现类里传进来的,根据这个思路也可把context传到B的实现类里,再在实现类里new出tracker

CTK Plugin Framework插件框架学习--服务追踪_#include_02


插件结构

  • PluginBService:接口类
  • PluginBImpl:实现类
  • PluginBActivator:激活类
  • ServiceTracker:追踪类

接口类:​​PluginAService​

#ifndef PLUGINB_SERVICE_H
#define PLUGINB_SERVICE_H

#include <QtPlugin>

class PluginBService
{
public:
virtual ~PluginBService() {}
virtual void B_Func() = 0;
};

#define PluginBService_iid "org.commontk.service.demos.PluginBService"
Q_DECLARE_INTERFACE(PluginBService, PluginBService_iid)
//此宏将当前这个接口类声明为接口,后面的一长串就是这个接口的唯一标识。
#endif // PLUGINB_SERVICE_H

实现类:​​PluginAImpl​

#ifndef PLUGINB_IMPL_H
#define PLUGINB_IMPL_H

#include "PluginBService.h"
#include <QObject>

class ServiceTracker;

class PluginBImpl : public QObject, public PluginBService
{
Q_OBJECT
Q_INTERFACES(PluginBService)
/*
此宏与Q_DECLARE_INTERFACE宏配合使用。
Q_DECLARE_INTERFACE:声明一个接口类
Q_INTERFACES:当一个类继承这个接口类,表明需要实现这个接口类
*/

public:
PluginBImpl(ServiceTracker *tracker);
void B_Func() Q_DECL_OVERRIDE;

private:
ServiceTracker *m_pTracker;
};

#endif // PLUGINB_IMPL_H
#include "pluginb_impl.h"
#include <QtDebug>
#include "../PluginA/PluginAService.h"
#include "ServiceTracker.h"

PluginBImpl::PluginBImpl(ServiceTracker *tracker)
: m_pTracker(tracker)
{

}

void PluginBImpl::B_Func()
{
PluginAService* service = static_cast<PluginAService*>(m_pTracker->getService());
if (service != Q_NULLPTR) {
service->A_Func();
}else {
qDebug()<<"get AbsPrintServer from tracker failed";
}
}

激活类:​​PluginAActivator​

#ifndef PLUGINBACTIVATOR_H
#define PLUGINBACTIVATOR_H

#include <QObject>
#include "ctkPluginActivator.h"
#include "PluginBService.h"

class PluginBImpl;
class ServiceTracker;

class PluginBActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "PLUGINB")
//向Qt的插件框架声明,希望将xxx插件放入到框架中。

public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);

private:
PluginBImpl *m_pPlugin;
ServiceTracker* m_pTracker;
ctkServiceRegistration m_registration;
};

#endif // PLUGINBACTIVATOR_H
#include "pluginb_activator.h"
#include "pluginb_impl.h"
#include "ServiceTracker.h"
#include "pluginb_impl.h"
#include <QDebug>

void PluginBActivator::start(ctkPluginContext* context)
{
// 开启服务跟踪器
m_pTracker = new ServiceTracker(context);
m_pTracker->open();

m_pPlugin = new PluginBImpl(m_pTracker);
m_registration = context->registerService<PluginBService>(m_pPlugin);
}

void PluginBActivator::stop(ctkPluginContext* context)
{
Q_UNUSED(context)
//Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用

// 注销服务
m_registration.unregister();

// 关闭服务跟踪器
m_pTracker->close();

delete m_pPlugin;
m_pPlugin = Q_NULLPTR;
}

追踪类:​​ServiceTracker​

#ifndef SERVICETRACKER_H
#define SERVICETRACKER_H

#include <ctkPluginContext.h>
#include <ctkServiceTracker.h>
#include "../PluginA/PluginAService.h"

class ServiceTracker : public ctkServiceTracker<PluginAService *>
{
public:
ServiceTracker(ctkPluginContext* context) : ctkServiceTracker<PluginAService *>(context) {}
~ServiceTracker() {}

protected:
// 在 Service 注册时访问
PluginAService* addingService(const ctkServiceReference& reference) Q_DECL_OVERRIDE {
qDebug() << "Adding service:" << reference.getPlugin()->getSymbolicName();
PluginAService* service = (PluginAService*)(ctkServiceTracker::addingService(reference));
return service;
}

void modifiedService(const ctkServiceReference& reference, PluginAService* service) Q_DECL_OVERRIDE {
qDebug() << "Modified service:" << reference.getPlugin()->getSymbolicName();
ctkServiceTracker::modifiedService(reference, service);
}

void removedService(const ctkServiceReference& reference, PluginAService* service) Q_DECL_OVERRIDE {
qDebug() << "Removed service:" << reference.getPlugin()->getSymbolicName();
ctkServiceTracker::removedService(reference, service);
}
};


#endif // SERVICETRACKER_H

四、测试

我们在B插件的实现类中的​​B_Func()​​接口中,通过服务追踪调用了服务A的接口A_Func(),如下:

CTK Plugin Framework插件框架学习--服务追踪_ctk_03

启用插件,然后调用B_Func(),修改main.cpp,添加如下代码段

//启用A插件
try {
// 安装插件
QString PluginA_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/PluginA/bin/plugins/PluginA.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginA_dir));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}

//启用B插件
try {
// 安装插件
QString PluginB_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/PluginB/bin/plugins/PluginB.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginB_dir));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}

// 获取服务引用
ctkServiceReference reference = pluginContext->getServiceReference<PluginBService>();
if (reference) {
// 获取指定 ctkServiceReference 引用的服务对象
PluginBService* service = pluginContext->getService<PluginBService>(reference);
if (service != Q_NULLPTR) {
// 调用服务
service->B_Func();
}
}

main.cpp完整代码:

#include "mainwindow.h"

#include <QApplication>

#include "ctkPluginFrameworkFactory.h"
#include "ctkPluginFramework.h"
#include "ctkPluginException.h"
#include "ctkPluginContext.h"
#include "ctkPluginFrameworkLauncher.h"
#include <QDebug>

#include "../HelloCTK/HelloService.h"
#include "event_listener.h"
#include "../PluginA/PluginAService.h"
#include "../PluginB/PluginBService.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setApplicationName("CTK_PluginFramework");//给框架创建名称,Linux下没有会报错

ctkPluginFrameworkFactory frameworkFactory;
QSharedPointer<ctkPluginFramework> framework = frameworkFactory.getFramework();

// 初始化并启动插件框架
try {
framework->init();
framework->start();
qDebug() << "======================================";
qDebug() << "CTK plugin framework start...";
qDebug() << "======================================";
} catch (const ctkPluginException &e) {
qDebug() << "CTK plugin framework init err: " << e.what();
return -1;
}

// 获取插件服务的contex
ctkPluginContext* pluginContext = framework->getPluginContext();

//---------------------------------------------------------------------------------------------------------------------------------------
//注册事件调用

//启用A插件
try {
// 安装插件
QString PluginA_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/PluginA/bin/plugins/PluginA.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginA_dir));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}

//启用B插件
try {
// 安装插件
QString PluginB_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/PluginB/bin/plugins/PluginB.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginB_dir));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}

// 获取服务引用
ctkServiceReference reference = pluginContext->getServiceReference<PluginBService>();
if (reference) {
// 获取指定 ctkServiceReference 引用的服务对象
PluginBService* service = pluginContext->getService<PluginBService>(reference);
if (service != Q_NULLPTR) {
// 调用服务
service->B_Func();
}
}

// 停止插件
//ctkPluginFrameworkLauncher::stop();

//---------------------------------------------------------------------------------------------------------------------------------------

MainWindow w;
w.show();

return a.exec();
}

CTK Plugin Framework插件框架学习--服务追踪_插件框架_04


可以看到在插件B中成功通过服务追踪,调用了服务A的接口A_Func()