Android电子书阅读器App

By LongLuo

这几天写了个Android App,实现了一个电子书阅读器,下面写下具体开发思路及过程。

主流电子书格式

目前市面上常见的电子书格式有epub、txt、mobi、azw、azw3等,如果做一个电子书阅读器的话,必须支持上述格式。

Epub

epub最开始使用的是epublib ,集成非常简单,只需要将epublib.jar拷贝到libs目录下,并在代码中调用即可,参考代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    try {
EpubReader reader = new EpubReader();
InputStream in = getAssets().open("algorithms.epub");
book = reader.readEpub(in);


Metadata metadata = book.getMetadata();

StringBuffer buffer = new StringBuffer();
for (String s : metadata.getDescriptions()) {
buffer.append(s + " ");
}

String bookInfo = "作者:" + metadata.getAuthors().get(0) +
"\n出版社:" + metadata.getPublishers().get(0) +
"\n出版时间:" + TimeUtils.getStringData(metadata.getDates().get(0).getValue()) +
"\n书名:" + metadata.getTitles().get(0) +
"\n简介:" + metadata.getDescriptions().get(0) +
"\n语言:" + metadata.getLanguage() +
"\n\n封面图:";

mTvText.setText(bookInfo);

Log.i(TAG, "onCreate: bookInfo=" + bookInfo);

// 书籍的阅读顺序,是一个线性的顺序。通过Spine可以知道应该按照怎样的章节,顺序去阅读,
// 并且通过Spine可以找到对应章节的内容。
Spine spine = book.getSpine();

List<SpineReference> spineReferences = spine.getSpineReferences();
if (spineReferences != null && spineReferences.size() > 0) {
Resource resource = spineReferences.get(1).getResource();//获取带章节信息的那个html页面

Log.i(TAG, "initView: book=" + resource.getId() + " " + resource.getTitle() + " " + resource.getSize() + " ");

byte[] data = resource.getData();//和 resource.getInputStream() 返回的都是html格式的文章内容,只不过读取方式不一样
String strHtml = StringUtils.bytes2Hex(data);
Log.i(TAG, "initView: strHtml= " + strHtml);

parseHtmlData(strHtml);
} else {
Log.i(TAG, "initView: spineReferences is null");
}
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 解析html
*/
private void parseHtmlData(String strHtml) throws IOException {
Document doc = Jsoup.parse(strHtml);
Log.i(TAG, "parseHtmlData: doc.title();=" + doc.title());
Elements eles = doc.getElementsByTag("a"); // a标签
// 遍历Elements的每个Element
EpubBean epubBean;
for (Element link : eles) {
String linkHref = link.attr("href"); // a标签的href属性
String text = link.text();
epubBean = new EpubBean();
epubBean.href = linkHref;
epubBean.tilte = text;
indexTitleList.add(epubBean);
Log.i(TAG, "parseHtmlData: linkHref=" + linkHref + " text=" + text);
}
}

不过这种方法仍然看起来比较复杂,由于之后为了支持Pdf,集成了MuPdf,而MuPdf本身也支持epub格式的读写,所以在后来版本中,就只需要保留MuPdf即可,就去除了EpubLib。

Pdf

具体参考Android App集成MuPdf,实现Pdf阅读、编辑、标记等功能 这篇文章,实现Pdf的阅读、编辑、标记等功能。

mobi & azw, azw3

mobi/azw/azw3格式支持,使用了libmobi 开源库。

libmobi编译

下载源码之后,使用NDK编译生成libmobi.so。

在mobi文件夹下增加Android.mk文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_CFLAGS := $(APP_CFLAGS)
LOCAL_CPPFLAGS := $(APP_CPPFLAGS)
LOCAL_ARM_MODE := $(APP_ARM_MODE)

LOCAL_MODULE := libmobi

LOCAL_SRC_FILES := buffer.c common.c compression.c debug.c encryption.c index.c memory.c meta.c miniz.c mobitool.c opf.c parse_rawml.c read.c sha1.c structure.c util.c write.c xmlwriter.c

LOCAL_CFLAGS += -std=c99
LOCAL_CFLAGS += -DUSE_XMLWRITER

LOCAL_LDLIBS := -lz

include $(BUILD_SHARED_LIBRARY)

Application.mk文件内容:

1
2
3
4
5
6
7
8
9
10
11
APP_PLATFORM=android-16

APP_ABI := arm64-v8a armeabi-v7a

APP_OPTIM := release
APP_ARM_MODE := arm

APP_CFLAGS := -O2
APP_CPPFLAGS := -O2

APP_STL := c++_static

在当前目录下:

1
~\jni\mobi>ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk

在libs文件夹下会生成对应的libmobi.so文件。

开发历程

在开发电子书阅读App功能时,从无到有,逐渐添加功能,下面就是我开发的过程:

1. 最简单的Demo

只实现了简单的epub的阅读:https://github.com/longluo/EbookReader/tree/demobook

2. 丰富各种界面

https://github.com/longluo/EbookReader/tree/demobook

3. 移植FBReader App

参考开源的FBReader,https://github.com/longluo/EbookReader/tree/fbreader

4. 增加Pdf支持

集成MuPdf:https://github.com/longluo/EbookReader/tree/pdf

5. 增加azw/mobi格式支持

集成LibMobi,实现azw/mobi格式支持: https://github.com/longluo/EbookReader/tree/azw_mobi

ToDos

  1. 书架展示
  2. 书签功能
  3. 修改字体、背景等; …