CTK Plugin Framework中的MANIFEST.MF文件
简述
在创建CTK插件时,MANIFEST.MF
是一个必须的文件 。这个文件有特殊的格式要求。
如果将 MANIFEST
翻译为中文,是“清单”的意思。在CTK中,MANIFEST.MF
文件包含了各种清单头(例如:Plugin-Name
),用于描述插件的信息。
清单头
CTK本身提供了一些清单头,这些可以在 ctkPluginConstants
类中找到:
项 | 描述 |
---|---|
Plugin-SymbolicName |
插件的符号名 |
Plugin-Copyright |
插件的版权信息 |
Plugin-Description |
插件的简要描述 |
Plugin-Name |
插件的名称 |
Plugin-Vendor |
插件的供应商 |
Plugin-Localization |
标识插件的 Qt .qm 文件的基本名称 |
Require-Plugin |
插件所需的其他插件的符号名称 |
Plugin-Version |
插件的版本号 |
Plugin-ActivationPolicy |
插件的激活策略 |
Plugin-UpdateLocation |
在插件更新操作期间,获取新插件版本的位置 |
大部分清单头是一些描述性字符串,比较简单。但有一些相对复杂,它们有自己的约束,下面主要对这部分进行讲解。
版本号
插件的版本号由 Plugin-Version
头指定,语法如下:
version ::= majorVersion('.'minorVersion('.'microVersion('.'qualifier)?)?)?
majorVersion ::= digit+
minorVersion ::= digit+
microVersion ::= digit+
qualifier ::= (alpha|digit|'_'|'-')+
digit ::= [0..9]
alpha ::= [a..zA..Z]1234567
注意: version中不能有空格
激活策略
插件的激活策略由 Plugin-ActivationPolicy
头指定,默认值是 lazy
。
激活策略的值包括:
项 | 描述 |
---|---|
eager |
插件使用 ctkPlugin::START_ACTIVATION_POLICY 选项启动,当框架启动时会立即激活。 |
lazy |
插件使用 ctkPlugin::START_ACTIVATION_POLICY 选项启动,并在 ctkPlugin::STARTING 状态等待,直到插件的第一类实例化发生。插件将在实例返回给请求者之前被激活。 |
依赖的插件
头指令 resolution
- 标识 Require-Plugin
头中的解析类型,默认值是 mandatory
。
指令值包括:
项 | 描述 |
---|---|
optional (可选) |
表示所需的插件是可选的,并且即使所需的插件没有被解析,该插件也可以被解析。 |
mandatory (强制) |
表示在解析插件时,所需的插件也必须被解析。如果所需的插件不能被解析,则模块解析失败。 |
指令值被编码在 Require-Plugin
头中,例如:
Require-Plugin: com.acme.module.test; resolution:="optional"1
头属性 plugin-version
- 标识 Require-Plugin
头中指定插件的一系列版本,默认值是 0.0.0
。
属性值被编码在 Require-Plugin
头中,例如:
Require-Plugin: com.acme.module.test; plugin-version="1.1"
Require-Plugin: com.acme.module.test; plugin-version="[1.0,2.0)"12
plugin-version
的属性值使用 ,
来指定插件版本的范围。如果指定为单个版本,则意味着包含大于或等于指定版本的任何插件版本范围。
获取清单头
我们为插件提供了一个 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
创建一个 Qt 控制台应用程序,.pro
内容如下:
QT += core
QT -= gui
TEMPLATE = app
CONFIG += console
TARGET = GetMetaData
LIBS += -L$$PWD/Libs -lCTKCore -lCTKPluginFramework
INCLUDEPATH += \
$$PWD/../../CTK-master/Libs/Core \
$$PWD/../../CTK-master/Libs/PluginFramework
SOURCES += \
main.cpp123456789101112131415
再来看看 main.cpp
:
#include <QCoreApplication>
#include <QDirIterator>
#include <QtDebug>
#include <ctkPluginFrameworkFactory.h>
#include <ctkPluginFramework.h>
#include <ctkPluginException.h>
#include <ctkPluginContext.h>
const QString c_strSearchPath = "E:/CTK/Plugins";
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
ctkPluginFrameworkFactory frameWorkFactory;
QSharedPointer<ctkPluginFramework> framework = frameWorkFactory.getFramework();
try {
// 初始化并启动插件框架
framework->init();
framework->start();
qDebug() << "CTK Plugin Framework start ..." << "\r\n";
} catch (const ctkPluginException &e) {
qDebug() << "Failed to initialize the plugin framework: " << e.what();
return -1;
}
// 获取插件上下文
ctkPluginContext* pluginContext = framework->getPluginContext();
// 遍历路径下的所有插件
QDirIterator itPlugin(c_strSearchPath, QStringList() << "*.dll", QDir::Files);
while (itPlugin.hasNext()) {
QString strPlugin = itPlugin.next();
try {
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(QFileInfo(strPlugin).absoluteFilePath()));
plugin->start(ctkPlugin::START_TRANSIENT);
// 获取清单头和值
QHash<QString, QString> headers = plugin->getHeaders();
qDebug() << "headers:" << headers << "\r\n";
// 获取符号名
QString symb = plugin->getSymbolicName();
qDebug() << "symbolic name:" << test<< "\r\n";
// 获取版本号
ctkVersion version = plugin->getVersion();
qDebug() << "version:" << version.toString()
<< "major:" << version.getMajor()
<< "micro:" << version.getMicro()
<< "minor:" << version.getMinor()
<< "qualifier:" << version.getQualifier();
} catch(const ctkPluginException &e) {
qDebug() << "Failed to install plugin" << e.what();
return -1;
}
}
return app.exec();
}
在CTK框架初始化并启动之后,我们使用 QDirIterator
遍历指定目录中的所有插件(示例中只有一个),并利用 ctkPluginContext
对每个插件进行安装。安装的每个插件都有一个相关的 ctkPlugin
对象,它是插件生命周期的接入点。
有了 ctkPlugin
,一切都会变得十分简单。getHeaders()
会返回一个 QHash<QString, QString>
,其中包含了所有的清单头和对应的值。如果要获取插件的符号名、版本号,除了使用 QHash
外,ctkPlugin
还提供了两个方便的函数 - getSymbolicName()
和 getVersion()
。