关于 FBReader
FBReader 是很优秀的跨平台电子书阅读器,它原为 Sharp Zaurus 而开发,后来可在 Nokia 770/N800、Motorola EZX系列、Maemo、Linux、Windows 、android等上面运行(iOS上也有移植,但是部分代码还没放出貌似)。FBReader 支持 fb2、HTML、CHM、plucker、Palmdoc、zTxt、TCR、RTF、OEB、OpenReader、Non-DRM’ed mobipocket、Plain text 等广泛的格式。
FBReader插件系统
FBReader之所以能在各平台工作,是因为它为这些平台提供了各自的ui插件,比如linux桌面下可以用gtk或qt,embeded linux下用qt,mac下用cocoa等。 FBReader的核心是ZLibrary,ZLibrary又由core, text, ui三部分组成。core提供了一些和平台无关的接口,从基本的文件系统、xml、network到gui等。当然也有些平台相关的代码比如加载插件的方法等。ui则根据不同的平台实现了core中的一些接口,主要是gui部分。text没仔细看,应该是和文档处理相关的。FBReader的上层代码在fbreader/src,也没仔细看,应该就是具体功能的实现。
笔者按照FBReader的结构写了一个demo,在这里与大家分享下,一起学习插件系统思想。附件中是源代码,因为demo提供了一个基于qt的gui插件,为了方便编译,采用qmake来编译。代码已经在linux和windows的mingw上测试通过。
代码结构如下
core --|--- application: ZLApplication.{h,cpp}, ZLWindow.{h,cpp}
|--- library: ZLibrary.{h,cpp}, ZLibraryImplementation.{h,cpp}
|--- posix : libdl port for mingw
ui --- src ---qt --|-- application: ZLWindow.{h,cpp}
|-- library: ZLQtLibraryImplementation.cpp
app: ZLTest.{h,cpp}, main.cpp
其实作为demo代码还可以精简很多。这里是为了更接近FBReader的接口。
core::ZLibrary
提供了三个静态成员函数,
static bool init(int &argc, char **&argv);
//static ZLPaintContext *createContext();
static void run(ZLApplication *application);
static void shutdown();
分别用来初始化(加载ui插件等),进入事件循环和结束程序的处理(这里shutdown没干实质性的东西)。在main函数里调用这些就能正常运行程序了。
init()里会查找程序目录下的plugins目录下的插件,也可以命令行指定。这里用了libdl的接口dlopen, dlsym, dlclose。插件里提供一个初始化接口initLibrary供这里调用,会生成一个core::ZLibraryImplemention实例(单例)
core::ZLIbraryImplemention.
是个单例,抽象类。只提供接口init(argc, argv)和run(application),在插件中必须实现。比如qt的话在init里生成QApplication,在run里创建窗口并进入事件循环。
ZLIbraryImplemention.h还提供了initLibrary接口作为插件的入口,供ZLibrary::init()调用,插件必须实现之。比如qt的话就new一个ui::ZLibraryQtImplemention。
core::ZLApplication:
初始化窗口。
core::ZLWindow:
窗口的接口。
ui::ZLQtWindow:
继承core::ZLWindow和QWidget,真正的窗口
ui::ZLibraryQtImplemention:
继承core::ZLIbraryImplemention, 功能在那里已描述。
app::ZLTest
继承core::ZLApplication,这里不干什么事情
编译后会在bin目录下生成libZLCore.so(ZLCore.dll), ZLTest(.exe), plugins/libZLUi-Qt.so(ZLUi-Qt.dll)等,直接双击即可运行(其中ZLTest和ZLUi-Qt库依赖ZLCore库,linux下只要不移动这些库的位置就能直接运行)