一、生成插件
0、环境说明
编译ctk:Qt5.12.2+MSVC2017_64+Cmake
生成插件:Qt5.12.2+MSVC2017_64+qmake
1、服务类,纯虚类,提供接口
abslogservice.h
#ifndef ABSLOGSERVICE_H #define ABSLOGSERVICE_H #include <QObject> class AbsLogService{ public: virtual ~AbsLogService(){} virtual void log(QString info) = 0; }; Q_DECLARE_INTERFACE(AbsLogService,"judesmorning.zxy.AbsLogService") #endif // ABSLOGSERVICE_H
2、实现插件类,实现纯虚函数
logservice.h
#ifndef LOGSERVICE_H #define LOGSERVICE_H #include <QObject> #include "abslogservice.h" class ctkPluginContext; class LogService : public QObject, public AbsLogService { Q_OBJECT Q_INTERFACES(AbsLogService)//表名当前插件类实现这个服务接口 public: LogService(ctkPluginContext* context); void log(QString info); }; #endif // LOGSERVICE_H
logservice.cpp
#include "logservice.h" #include <QDebug> #include "ctkPluginContext.h" #include <QTime> LogService::LogService(ctkPluginContext* context) { context->registerService<AbsLogService>(this); } void LogService::log(QString info) { qDebug()<<QTime::currentTime().toString("HH:mm:ss ") + info;//打印加上时间戳 }
3、激活插件,加入ctk框架的生命周期中
firstpluginactivator.h
#ifndef FIRSTPLUGINACTIVATOR_H #define FIRSTPLUGINACTIVATOR_H #include <QObject> #include "ctkPluginActivator.h" #include "ctkPluginContext.h" #include "logservice.h" class FirstPluginActivator : public QObject, public ctkPluginActivator { Q_OBJECT Q_INTERFACES(ctkPluginActivator) Q_PLUGIN_METADATA(IID "LogPlugin") public: FirstPluginActivator(); void start(ctkPluginContext *context); void stop(ctkPluginContext *context); private: QScopedPointer<AbsLogService> m_log;//智能指针,自动析构回收 }; #endif // FIRSTPLUGINACTIVATOR_H
firstpluginactivator.cpp
#include "firstpluginactivator.h" #include <QDebug> FirstPluginActivator::FirstPluginActivator() { } void FirstPluginActivator::start(ctkPluginContext *context) { qDebug() << "my plugin start"; m_log.reset(new LogService(context)); } void FirstPluginActivator::stop(ctkPluginContext *context) { qDebug() << "my plugin stop"; Q_UNUSED(context) }
4、添加资源文件
资源名随便去,前缀为:TARGET/META_INF,文件名为:MANIFEST.MF
MANIFEST.MF内容:
有些教程上说是前缀是工程名/META_INF,经过测试工程名、MANIFEST.MF中的符号名、IID中的字符串都可以随意取,只需要满足这里的前缀是:TARGET/META_INF格式
有很多可填内容,在ctkPluginConstants.h中能找到相关宏定义
5、.pro文件
QT += core QT -= gui TARGET = ctk-plugin-first TEMPLATE = lib CONFIG += plugin #ctk源码路径 INCLUDEPATH += $$PWD/include/Core += $$PWD/include/PluginFramework #ctk安装路径,主要用到ctkPluginFrameworkExport.h等 INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/Libs/PluginFramework INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/Libs/Core #ctk的动态库路径 LIBS += -LC:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/bin/Debug -lCTKCore -lCTKPluginFramework HEADERS += firstpluginactivator.h logservice.h abslogservice.h SOURCES += firstpluginactivator.cpp logservice.cpp RESOURCES += resource.qrc
注意:target的名字最好和工程名一致,不然可能出现device not open错误
6、编译生成插件
二、使用此插件
1、main.cpp
#include <QCoreApplication> #include <ctkPluginFrameworkFactory.h> #include <ctkPluginFramework.h> #include <ctkPluginException.h> #include <ctkPluginContext.h> #include <QtDebug> #include <QUrl> #include "abslogservice.h"
//插件路径 QString static firstPlugin_filePath = "C:/Users/Administrator/Desktop/myctk2017/ctk-plugin-first/debug/ctk-plugin-first.dll"; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); ctkPluginFrameworkFactory frameworkFactory; QSharedPointer<ctkPluginFramework> framework = frameworkFactory.getFramework(); // 初始化并启动插件框架 try { framework->init(); framework->start(); qDebug() << "CTK plugin framework start..."; } catch (const ctkPluginException &e) { qDebug() << "CTK plugin framework init err: " << e.what(); return -1; } // 获取插件服务的contex ctkPluginContext* pluginContext = framework->getPluginContext(); try { // 安装插件 QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(firstPlugin_filePath)); qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString()); // 启动插件 plugin->start(ctkPlugin::START_TRANSIENT); qDebug() << "Plugin start..."; } catch (const ctkPluginException &e) { qDebug() << QString("Failed install or run plugin: ") << e.what(); return -2; } // 获取服务引用 ctkServiceReference reference = pluginContext->getServiceReference<AbsLogService>(); if (reference) { // 获取指定 ctkServiceReference 引用的服务对象 AbsLogService* service = qobject_cast<AbsLogService*>(pluginContext->getService(reference)); if (service != Q_NULLPTR) { // 调用服务 service->log("hello hhh.."); } } return a.exec(); }
2、.pro
QT -= gui CONFIG += console CONFIG -= app_bundle INCLUDEPATH += $$PWD/include/Core += $$PWD/include/PluginFramework += $$PWD/include/mydll #存放插件的服务接口类的头文件 #ctk的源码 INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/Libs/PluginFramework INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/Libs/Core #ctk的动态库 LIBS += -LC:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/bin/Debug -lCTKCore -lCTKPluginFramework DEFINES += QT_DEPRECATED_WARNINGS SOURCES += main.cpp # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target
注意在ctk环境ok的情况下,只需要用到插件的额dll和插件的纯虚类头文件
3、运行
ps:附上学习ctk的流程
1、编译CTK【可用现成的】
2、编译插件:日志插件【用打印代替存储日志】
3、新建工程:使用日志插件,并调用接口记录一句话
4、插件的依赖测试:编写日志插件和打印插件,日志插件依赖打印插件
5、编写两个插件通信:两种通信方式都需要使用
6、编写插件:使用服务工厂获取服务
7、编写插件:监听CTK所有事件
8、编写插件:使用服务追踪获取服务