CTK Plugin Framework中创建插件
CTK 源码中有一部分插件相关的示例,进入
CTK-master/Libs/PluginFramework/Testing
目录
使用cmake构建插件
由于CTK 插件框架是基于Qt 实现的,所以插件的创建也符合Qt 的标准。
创建插件
首先,定义一个测试的接口类,包含了服务提供的功能。
test_plugin_service.h内容如下:
#ifndef TEST_PLUGIN_SERVICE_H
#define TEST_PLUGIN_SERVICE_H
#include <QtPlugin>
#include <QString>
class TestPluginService
{
public:
virtual ~TestPluginService() {}
virtual bool test(const QString& username, const QString& password) = 0;
};
#define TestService_iid "org.commontk.service.TestService"
Q_DECLARE_INTERFACE(TestPluginService, TestService_iid)
#endif // Test_PLUGIN_SERVICE_H
使用 Q_DECLARE_INTERFACE
宏让Qt元对象系统感知到该接口,可在运行时识别实现了该接口的插件。
注意:TestService_iid
是一个标识接口的字符串且必须唯一。
接着为该接口定义一个实现类TestPlugin
。让子类实现接口到同时继承QObject
,使这个类成为一个插件。
test_plugin.h
内容如下:
#ifndef TEST_PLUGIN_H
#define TEST_PLUGIN_H
#include "test_plugin_service.h"
#include <QObject>
class ctkPluginContext;
class TestPlugin : public QObject, public TestPluginService
{
Q_OBJECT
Q_INTERFACES(TestPluginService)
public:
TestPlugin(ctkPluginContext* context);
bool test(const QString& username, const QString& password) Q_DECL_OVERRIDE;
};
#endif // TEST_PLUGIN_H
Q_INTERFACES
宏用于告诉Qt该类实现的接口。
实现一个简单的登录例子,假设用户名为 "root"
,密码为 "root"
,登录成功返回true否则,登录失败。
test_plugin.cpp
内容如下:
#include "test_plugin.h"
#include <ctkPluginContext.h>
TesthPlugin::TestPlugin(ctkPluginContext* context)
{
context->registerService<TestPluginService>(this);
}
bool TestPlugin::test(const QString& username, const QString& password)
{
if (QString::compare(username, "root") == 0
&& QString::compare(password, "root") == 0) {
return true;
} else {
return false;
}
}
ctkPluginContext
类是CTK 插件的上下文,将服务注册给它,在需要时就可以直接获取了。
注意: ctkPluginContext
是与运行框架交互的唯一方法。
除此之外,还需要为插件提供一个生命周期类。该类继承自CTKPlugin
中的 ctkPluginActivator
,在 ctkPluginActivator
中提供了两个虚函数 start()
和 stop()
,通过实现生命周期类来完成服务的注册。
test_plugin_activator.h
内容如下:
#ifndef TEST_PLUGIN_ACTIVATOR_H
#define TEST_PLUGIN_ACTIVATOR_H
#include <ctkPluginActivator.h>
#include "test_plugin_service.h"
class TestPluginActivator : public QObject,
public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "test_plugin")
public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);
private:
QScopedPointer<TestPluginService> service;
};
#endif // TEST_PLUGIN_ACTIVATOR_H
使用 registerService()
向 CTKPlugin
插件系统中注册该插件时会调用start()
生命周期的开始 ,而 stop()
则是插件生命周期的终止。
test_plugin_activator.cpp
内容如下:
#include "test_plugin_activator.h"
#include "test_plugin.h"
void TestPluginActivator::start(ctkPluginContext* context)
{
service.reset(new TestPlugin(context));
}
void TestPluginActivator::stop(ctkPluginContext* context)
{
Q_UNUSED(context)
}
配置插件
由于CTK采用CMake来构建的,下面就使用CMake来配置CTK插件。
CMakeList.txt
内容如下:
project(test_plugin)
set(PLUGIN_export_directive "test_plugin_export")
set(PLUGIN_SRCS
test_plugin.cpp
test_plugin_activator.cpp
test_plugin_service.h
)
set(PLUGIN_MOC_SRCS
test_plugin.h
test_plugin_activator.h
)
set(PLUGIN_resources
)
ctkFunctionGetTargetLibraries(PLUGIN_target_libraries)
ctkMacroBuildPlugin(
NAME ${PROJECT_NAME}
EXPORT_DIRECTIVE ${PLUGIN_export_directive}
SRCS ${PLUGIN_SRCS}
MOC_SRCS ${PLUGIN_MOC_SRCS}
RESOURCES ${PLUGIN_resources}
TARGET_LIBRARIES ${PLUGIN_target_libraries}
TEST_PLUGIN
)
其中必须包含一个 project
命令,项目名必须对应于插件的目录名。
PLUGIN_export_directive
是导出相关的指令,应该使用与 xxx_export.h
文件中相同的标记 # define <export-directive> Q_DECL_EXPORT
。
在生成CTK插件时,需要一个 qrc
文件和 MF
文件。CTK提供的ctkMacroBuildPlugin工具可以在创建插件工程的同时自动创建这两个文件,不过需要在源文件目录下放置两个 cmake 文件 manifest_headers.cmake
和 target_libraries.cmake
。
manifest_headers.cmake
主要包含插件的元信息:
set(Plugin-ActivationPolicy "eager")
set(Plugin-Name "test_plugin")
set(Plugin-Version "1.0.0")
set(Plugin-Description "a plugin for test")
set(Plugin-Vendor "test")
set(Plugin-ContactAddress "https://test.com/test")
set(Plugin-Category "test")
target_libraries.cmake
用于列出构建当前CTK插件所需的库:
set(target_libraries
CTKPluginFramework
)
完成以上步骤,将插件放置到CTK 源码包CTK-master/Libs/PluginFramework/Testing/FrameworkTestPlugins
中,这样以来,在编译 CTK 时也可以编译我们自己的插件。
除此之外,还需要修改 CTK-master/Libs/PluginFramework/Testing
中的 CMakeLists.txt
文件,将我们的插件添加进去。
编译插件
重新编译CTK,插件编译成功,也生成了qrc
文件和 MF
文件。
使用qmake构建插件
需要的文件
创建CTK插件时,需要一个 qrc
文件和 MF
文件。在使用CMake编译插件时可以在目录中找到这两个文件,其中MANIFEST.MF
是插件属性(包含:符号名、插件名、版本号等)文件:
Plugin-SymbolicName: test.plugin
Plugin-ActivationPolicy: eager
Plugin-Category: test
Plugin-ContactAddress: https://test.com/test
Plugin-Description: A plugin for test
Plugin-Name: test_plugin
Plugin-Vendor: test
Plugin-Version: 1.0.0
而 test_plugin_manifest.qrc
是资源集合文件:
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/test.plugin/META-INF">
<file>MANIFEST.MF</file>
</qresource>
</RCC>
将资源文件编译成二进制,以便在程序中访问。
创建插件
了解了 qrc
和 MF
文件,创建插件变得十分简单。
CMake 和 qmake 相比:
- CMake:需要
CMakeList.txt
、manifest_headers.cmake
、target_libraries.cmake
- qmake:需要
.pro
、test_plugin_manifest.qrc
和MANIFEST.MF
除此之外,其他文件(例如:test_plugin_service.h
)则保持不变。
注意: 其他文件内容请参考上面代码
这个是 .pro
文件:
QT += core
QT -= gui
TEMPLATE = lib
CONFIG += plugin
TARGET = test_plugin
LIBS += -L$$PWD/Libs -lCTKCore -lCTKPluginFramework
INCLUDEPATH += \
$$PWD/../../CTK-master/Libs/Core \
$$PWD/../../CTK-master/Libs/PluginFramework
HEADERS += \
test_plugin_service.h \
test_plugin.h \
test_plugin_activator.h
SOURCES += \
test_plugin.cpp \
test_plugin_activator.cpp
RESOURCES += testplugin_manifest.qrc
由于构建的是一个共享库,所以需要将 TEMPLATE
设置为 lib
,同时还必须将 CONFIG
设置为 plugin
。
创建 CTK 插件时,需要依赖 CTKCore
和 CTKPluginFramework
,所以也要将他们包含进来。
最后,记得使用 RESOURCES
指定资源集合文件。
编译加载
编译生成 tset_plugin.dll
。