Skip to main content

Integration of MuPDF Project as a Library into an Android Studio Project

I have needed to use MuPDF library in my android project. After some research, I have seen that there are many integration tutorials but, but integrated projects are developed on Eclipse. For projects on AndroidStudio+Gradle, there is no example. I mean there is no specific example which exactly refers to this issue. So, after achieving my goal, I want to share the steps publicly so that it can be reused by others.

1-First of all, get the source code of MuPDF, compile with as described in this link. Make sure that it runs on an android device, so that we could be sure that if we see any problem it is not related to MuPDF compilation.

2-Add a new library module with same package name of Mupdf (com.artifex.mupdfdemo) into your project. Copy all java files under mupdf/platform/android/src/com/artifex/mupdfdemo into this newly created package.

3- Copy res folder under /mupdf/platform/android under main directory of Mupdf module of your project. Edit AndroidManifest.xml file of the module if necessary. Omit unnecessary definitions. There is only application tag in my AndroidManifest.xml file and its content is:

android:allowbackup="true" 
android:label="@string/app_name"

4- Create a folder under mupdf/src/main. Name it as 'jniLibs'.

There should be compiled C files under mupdf/platform/android/obj/local/armeabi-v7a. Copy armeabi-v7a under jniLibs dir and augment it 3 times. Name other directories as armeabi, mips, x86.

5- Under mupdf module, edit build.gradle. Add following lines under android tag.

sourceSets.main {
    jniLibs.srcDir 'src/main/jniLibs'
}
That is it. I have inserted java files too, because I aim to use them in my project. If you don't need them, if you just want to use compiled C files, you can directly pass to 4th and 5th steps and apply them to the app module. I am new at this structure. So, this is my solution and it may not be best. If you see any step as a bad practice, please drop your recommendation as a comment. I 'd always like to follow the best ways of what I do ;)

OS: Ubuntu 12.04
Gradle Version: 0.12.2

Comments

  1. THANK YOU, THANK YOU, THANK YOU!!!!!!!! Helped me a lot!!

    ReplyDelete
  2. Hi. The link in your first step is not reachable. Any other sources ? Thanks

    ReplyDelete
  3. Hi, thx a lot for this great Tuto.

    android/obj/local/armeabi-v7a folder is pretty huge. are all files and folders needed to be copied in the jniLibs folder ?

    thx.

    ReplyDelete
    Replies
    1. It is the output of ndk compilation. So, yes. But you can omit augmenting part depending on your case.

      Delete
    2. Hi,

      Thx for your answer. Augmenting part is needed to support all proc architecture, isn't it ?

      Regards.

      Delete
    3. Yes. Different architecture will look for the directory associated to it.

      Delete
  4. I got the error:

    Gradle DSL method not found: `main()`

    - The project MY_PROJECT_NAME may be using a version of Gradle that does not contain the method.
    - The build may be missing a Gradle Plugin.

    ReplyDelete
  5. Please note that when i remove these lines from build.gradle of MuPDF the error disappears:
    sourceSets.main {
    jniLibs.srcDir 'src/main/jniLibs'
    }

    ReplyDelete
  6. Hi, step is in the app or in the mupdfdemo ?

    ReplyDelete
  7. Is ti possible to have your project source code ?

    ReplyDelete
  8. I'm getting a "Cannot open document" error. Any idea why ?

    ReplyDelete
    Replies
    1. One of the reasons for this error is "broken" file or "incomplete" download of file.

      Delete
  9. Thank you very much for this article! Been trying to get it to working for four days and this is the only thing that worked! :D

    ReplyDelete
  10. I guess muPDF have changed the project structure a bit. For example, now they have started viewer package.

    I just followed every step, and everything is working well. Thanks to clear guidelines in this blog.

    But after integrating muPDF 1.9 ( I did not cloned source from git but downloaded from their download link) and it made apk size 10 MB to 59.9 MB. for previous versions of muPDF (1.3), it did not increased this much of size. Any one else faced such problem?

    ReplyDelete
  11. Well done!!!!
    Thanks for taking the time to write this. You're great!!!

    ReplyDelete
  12. " There should be compiled C files under mupdf/platform/android/obj/local/armeabi-v7a. Copy armeabi-v7a under jniLibs dir and augment it 3 times. Name other directories as armeabi, mips, x86. " For me , don even have obj folder , you mean these file will auto compiled after we create jnilib ?

    ReplyDelete
  13. Forgive me if the question sounds naive as I am not at all familiar with ndk, native code integration and make files.

    My question is, does the above mentioned process to integrate mupdf, change with the ndk integration changes that google introduced with android studio 2.2+ and gradle 2.2.0+? Can we directly link the mupdf Makefile in android studio and start using mupdf library? What changes do I need to make in the integration process if I do NOT want to use "android.useDeprecatedNdk=true" in my project?

    I would really appreciate any guidance that I could get.

    Thanks.

    ReplyDelete
  14. Great work, This tutorial is awesome so thank you

    I have a problem in step 1 - I built but app is crashing when I try it on emulator(API 19 with x86 processor)

    It is great if you have Idea why this may happen
    This is the logcat message
    E/AndroidRuntime( 2464): FATAL EXCEPTION: main
    E/AndroidRuntime( 2464): Process: com.artifex.mupdfdemo, PID: 2464
    E/AndroidRuntime( 2464): java.lang.UnsatisfiedLinkError: Couldn't load mupdf_java32 from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.artifex.mupdfdemo-2.apk"],nativeLibraryDirectories=[/data/app-lib/com.artifex.mupdfdemo-2, /system/lib]]]: findLibrary returned null
    E/AndroidRuntime( 2464): at java.lang.Runtime.loadLibrary(Runtime.java:358)
    E/AndroidRuntime( 2464): at java.lang.System.loadLibrary(System.java:526)
    E/AndroidRuntime( 2464): at com.artifex.mupdfdemo.MuPDFCore.(MuPDFCore.java:15)
    E/AndroidRuntime( 2464): at com.artifex.mupdfdemo.MuPDFActivity.openFile(MuPDFActivity.java:229)
    E/AndroidRuntime( 2464): at com.artifex.mupdfdemo.MuPDFActivity.onCreate(MuPDFActivity.java:359)
    E/AndroidRuntime( 2464): at android.app.Activity.performCreate(Activity.java:5231)
    E/AndroidRuntime( 2464): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
    E/AndroidRuntime( 2464): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
    E/AndroidRuntime( 2464): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
    E/AndroidRuntime( 2464): at android.app.ActivityThread.access$800(ActivityThread.java:135)
    E/AndroidRuntime( 2464): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
    E/AndroidRuntime( 2464): at android.os.Handler.dispatchMessage(Handler.java:102)
    E/AndroidRuntime( 2464): at android.os.Looper.loop(Looper.java:136)
    E/AndroidRuntime( 2464): at android.app.ActivityThread.main(ActivityThread.java:5017)
    E/AndroidRuntime( 2464): at java.lang.reflect.Method.invokeNative(Native Method)
    E/AndroidRuntime( 2464): at java.lang.reflect.Method.invoke(Method.java:515)
    E/AndroidRuntime( 2464): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
    E/AndroidRuntime( 2464): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
    E/AndroidRuntime( 2464): at dalvik.system.NativeStart.main(Native Method)
    W/ActivityManager( 1571): Force finishing activity com.artifex.mupdfdemo/.MuPDFActivity
    W/ActivityManager( 1571): Force finishing activity com.artifex.mupdfdemo/.ChoosePDFActivity

    ReplyDelete
  15. Getting this error
    Error: executing external native build for ndkBuild mupdf-android-viewer-mini\libmupdf\platform\java\Android.mk

    How to resolve this error,please help me

    ReplyDelete
  16. link is not working. .... mentioned in step 1

    ReplyDelete

Post a Comment

Popular posts from this blog

Migration from Proxmox to Openstack

I needed to migrate virtual machines in proxmox to openstack. VMs are in raw format. I needed to take some actions for a succesfull migration. I have perform all actions on Ubuntu 12.04 with virt-manager. qemu-kvm is installed. Here is the list of actions that I took: First, close the machine and copy the image file into your Ubuntu. Convert raw image to qcow2 format: qemu-img convert -O qcow2 image1.raw image1.qcow2 You need the image in qcow2 format for compatibility with openstack platform.  Open the converted image in virt-manager. Before opening, edit disk options. Under ' advanced options ' section, select ' qcow2 ' as ' storage forma t '. Start the virtual machine. You should see the login screen soon. (If you don't set storage format, vm will not find a bootable device. )   If everything is ok so far, close the vm. Take qcow2 image and upload it into glance. It may take time depending on size of it. After this process is completed, open a

Xposed - How to hook a method with primitive-type parameter

Xposed Framework is a great tool to take actions which Android SDK doesn't provide for developers. One of the great hacks that you can do is hooking a method. You can see parameters given to a method, with many other properties of it. There are some tutorials on Internet, but in this tutorials, they show hooking method without parameters or with class parameters. Its code is: findAndHookMethod("com.android.settings.Settings", lpparam.classLoader, "updateHeaderList", List.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { //your code } });