Android App集成MuPdf,实现Pdf阅读、编辑、标记等功能

By Long Luo

之前开发Android电子书阅读器App时,需要支持Pdf文件的阅读和标记功能,经过分析和测试不同实现方案,最终选择MuPdf方案。

Pdf解决方案

目前手机上实现Pdf文件的支持,有很多解决方案:

  1. Andorid原生自带的Pdf解决方案,主要提供两个类PdfRendererPdfDocument,但是Lollipop才有的类,PdfRenderer中核心代码是用的native方法,所以没办法将PdfRenderer从SDK中抽取出来用,局限性大,不采用。

  2. 开源AndroidPdfViewer,完全使用Java实现,但问题在于太大,性能不及原生,所以放弃。

  3. MuPdf,一款轻量级的pdf框架,支持前面两者功能,同时如果是文本的pdf文档还支持搜索、标注等功能,使用native C代码实现,快,编译好的so库也只有10M大小。

  4. 调起手机中第三方支持Pdf阅读的应用;

  5. 通过pdf.js实现在线预览,需要调用网页,性能不及原生,放弃。

MuPdf

MuPdf是一个轻量级PDF、XPS和E-book阅读器,支持全部平台。

源码下载地址:https://mupdf.com/downloads/archive/

官网提供了一个例子:MuPDF Android Viewer,下面我们来编译并实现。

MuPdf编译

下载源码:

1
$ git clone --recursive git://git.ghostscript.com/mupdf-android-viewer.git

安装Cygwin或者直接在Linux下使用:

1
2
mupdf-android-viewer$cd jni
mupdf-android-viewer/jni$make generate

会调用make -j4 -C libmupdf generate命令编译字体文件,然后在libmupdf目录下生成generated文件夹,里面主要是一些字体文件。

编译libmupdf_java.so

Linux下NDK编译环境配置可以参考之前的文章Linux下Android开发环境搭建指南

或者在Windows下配置好NDK编译,然后进入~/mupdf-android-viewer/jni/libmupdf目录下,ndk-build编译:

1
~\mupdf-android-viewer\jni\libmupdf>ndk-build -j8 APP_BUILD_SCRIPT=platform/java/Android.mk APP_PROJECT_PATH=build/android APP_PLATFORM=android-16 APP_OPTIM=debug APP_ABI=arm64-v8a

编译中出现下列错误:

1
2
3
process_begin: CreateProcess(... ...)
harfbuzz...
make (e=87): 参数错误。

原因是参数太长,解决方案是在mupdf-android-viewer\jni\libmupdf\platform\java的:

在Android.mk文件中添加:LOCAL_SHORT_COMMANDS := true

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
# Android makefile to be used with ndk-build.
#
# Run ndk-build with the following arguments:
# APP_BUILD_SCRIPT=platform/java/Android.mk (this file)
# APP_PROJECT_DIR=build/android (where you want the output)
# APP_PLATFORM=android-16
# APP_OPTIM=release (or debug)
# APP_ABI=all (or armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64)
#
# The top-level Makefile will invoke ndk-build with appropriate arguments
# if you run 'make android'.
#
# Use the MUPDF_EXTRA_CFLAGS, MUPDF_EXTRA_CPPFLAGS, MUPDF_EXTRA_LDFLAGS,
# and MUPDF_EXTRA_LDLIBS variables to add more compiler flags.
#
# LOCAL_C_INCLUDES paths are relative to the NDK root directory.
# LOCAL_SRC_FILES paths are relative to LOCAL_PATH.
#
# We make sure to use absolute paths everywhere, so this makefile works
# regardless of where it is called from.

LOCAL_PATH := $(call my-dir)
MUPDF_PATH := $(realpath $(LOCAL_PATH)/../..)

LOCAL_SHORT_COMMANDS := true

ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
HAVE_NEON := yes
endif

在Application.mk文件中添加:APP_SHORT_COMMANDS := true

1
2
3
4
5
6
7
APP_SHORT_COMMANDS := true

ifdef USE_TESSERACT

APP_STL := c++_static

endif

重新编译,OK的话会在\jni\libmupdf\build\android\libs\arm64-v8a目录下生成下列文件:

1
~\mupdf-android-viewer\jni\libmupdf\build\android\libs\arm64-v8a\libmupdf_java.so

Pdf Viewer集成MuPdf

Demo具体源码可参考:https://github.com/longluo/AndroidPdfViewer

已测试OK!