One of the first globally modernized forks of PdfiumAndroid with 16KB page size support and rebuilt 64-bit native libraries to comply with Google Play 2025 policies and Android 15 kernel mandates.
A high-performance native PDF rendering library for Android using PDFium from AOSP. This fork provides the native PDF rendering engine with recompiled C++ libraries enforcing 16KB page-size alignment — critical for forward compatibility with Android 15+ and Google Play Store requirements.
In 2024, Google announced that all apps on the Play Store must support 16KB memory page sizes or face removal. This requirement stems from Android 15's kernel changes supporting devices with 16KB page sizes (vs. traditional 4KB).
At the time, the original PdfiumAndroid library was unmaintained and non-compliant. Rather than risk app removal, this fork was created to:
- ✅ Rebuild all native C++ libraries with 16KB page alignment (
-Wl,-z,max-page-size=16384) - ✅ Modernize the entire build toolchain (AGP 8.12.0, Gradle 8.14.2, Java 17, NDK 27.3.13750724)
- ✅ Update to Android 15 (API 35) compile and target SDK
- ✅ Ensure forward compatibility with Google Play 2025 policies
- ✅ Provide 64-bit only builds (arm64-v8a, x86_64) per Google Play requirements
- ✅ Ship modern Chromium-based PDFium with V8 JavaScript engine support
This fork has been validated in production applications serving:
- 700+ active users across 50+ countries
- 20,000+ sessions with 99.8% crash-free rate
(Metrics verified via Firebase Analytics & Android Vitals)
Add JitPack to your project's settings.gradle (recommended) or root build.gradle:
// settings.gradle (Gradle 7.0+)
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}Or for older projects using build.gradle:
// root build.gradle
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}Add the library to your module's build.gradle:
dependencies {
implementation 'com.github.Akul-Tyagi:PdfiumAndroid:v1.11.4-16kb'
}| Component | Before (1.9.x) | After (1.11.4-16kb) |
|---|---|---|
| Page Size Support | 4KB only | 16KB aligned ✅ |
| Compile SDK | 31 | 35 (Android 15) |
| Target SDK | 31 | 35 (Android 15) |
| Min SDK | 19 | 21 |
| AGP Version | 4.x | 8.12.0 |
| Gradle Version | 6.x | 8.14.2 |
| Java Version | 8 | 17 |
| NDK Version | 21.x | 27.3.13750724 |
| ABIs Supported | 32-bit + 64-bit | 64-bit only (arm64-v8a, x86_64) |
| PDFium Source | AOSP 7.1.2 | Chromium-based with V8 |
| Jetifier | Required | Disabled |
This fork includes completely rebuilt native libraries with:
- 16KB page alignment enforced via linker flags:
-Wl,-z,common-page-size=16384 -Wl,-z,max-page-size=16384
- Modern Chromium-based PDFium with full V8 JavaScript engine
- Optimized native library loading via unified
NativeLoaderclass - 64-bit architectures only (arm64-v8a, x86_64) for Google Play compliance
Each architecture includes the following shared libraries:
| Library | Purpose |
|---|---|
libpdfium.cr.so |
Main PDFium rendering engine |
libv8.cr.so |
V8 JavaScript engine for PDF forms |
libv8_libbase.cr.so |
V8 base library |
libicuuc.cr.so |
ICU Unicode support |
libthird_party_icu_icui18n.cr.so |
ICU internationalization |
libc++_chrome.so |
C++ standard library (Chrome build) |
libchrome_zlib.cr.so |
Compression library |
libthird_party_abseil-cpp_absl.cr.so |
Abseil C++ library |
libbase_allocator_partition_allocator_*.cr.so |
Memory allocator libraries |
Android 15 introduces support for devices with 16KB memory page sizes. Apps with native libraries must be compiled with proper alignment to run on these devices.
Application.mk:
APP_STL := c++_static
APP_CPPFLAGS += -fexceptions
APP_PLATFORM := android-21
APP_ABI := arm64-v8a x86_64
# 16KB compatibility flags
APP_LDFLAGS += -Wl,-z,common-page-size=16384 -Wl,-z,max-page-size=16384Android.mk:
# Force 16KB page alignment on the JNI library
LOCAL_LDFLAGS += -Wl,-z,common-page-size=16384 -Wl,-z,max-page-size=16384This ensures:
- ✅ Compatibility with 16KB page size devices (Android 15+)
- ✅ Backward compatibility with 4KB devices
- ✅ Google Play Store compliance
// build.gradle
android {
namespace "com.shockwave.pdfium"
compileSdk 35
defaultConfig {
minSdk 21
targetSdk 35
versionName "1.11.4-16kb"
ndk { abiFilters "arm64-v8a", "x86_64" }
}
ndkVersion "27.3.13750724"
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}# jitpack.yml
jdk:
- openjdk21
before_install:
- sdkmanager --install "ndk;27.3.13750724" >/dev/null
- yes | sdkmanager --licenses >/dev/null
install:
- export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/27.3.13750724"
- chmod +x gradlew
- ./gradlew --no-daemon clean :assembleRelease :publishToMavenLocalvoid openPdf() {
ImageView iv = (ImageView) findViewById(R.id.imageView);
ParcelFileDescriptor fd = ...;
int pageNum = 0;
PdfiumCore pdfiumCore = new PdfiumCore(context);
try {
PdfDocument pdfDocument = pdfiumCore.newDocument(fd);
pdfiumCore.openPage(pdfDocument, pageNum);
int width = pdfiumCore.getPageWidthPoint(pdfDocument, pageNum);
int height = pdfiumCore.getPageHeightPoint(pdfDocument, pageNum);
// ARGB_8888 - best quality, high memory usage, higher possibility of OutOfMemoryError
// RGB_565 - little worse quality, twice less memory usage
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
pdfiumCore.renderPageBitmap(pdfDocument, bitmap, pageNum, 0, 0, width, height);
// For annotations and form fields, add 'true' as last param
iv.setImageBitmap(bitmap);
pdfiumCore.closeDocument(pdfDocument); // important!
} catch(IOException ex) {
ex.printStackTrace();
}
}fun openPdf() {
val pdfiumCore = PdfiumCore(context)
val fd: ParcelFileDescriptor = /* get file descriptor */
try {
val pdfDocument = pdfiumCore.newDocument(fd)
pdfiumCore.openPage(pdfDocument, 0)
val width = pdfiumCore.getPageWidthPoint(pdfDocument, 0)
val height = pdfiumCore.getPageHeightPoint(pdfDocument, 0)
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
pdfiumCore.renderPageBitmap(pdfDocument, bitmap, 0, 0, 0, width, height)
imageView.setImageBitmap(bitmap)
pdfiumCore.closeDocument(pdfDocument)
} catch (e: IOException) {
e.printStackTrace()
}
}public void printInfo(PdfiumCore core, PdfDocument doc) {
PdfDocument.Meta meta = core.getDocumentMeta(doc);
Log.d(TAG, "title = " + meta.getTitle());
Log.d(TAG, "author = " + meta.getAuthor());
Log.d(TAG, "subject = " + meta.getSubject());
Log.d(TAG, "keywords = " + meta.getKeywords());
Log.d(TAG, "creator = " + meta.getCreator());
Log.d(TAG, "producer = " + meta.getProducer());
Log.d(TAG, "creationDate = " + meta.getCreationDate());
Log.d(TAG, "modDate = " + meta.getModDate());
}public void printBookmarksTree(List<PdfDocument.Bookmark> tree, String sep) {
for (PdfDocument.Bookmark b : tree) {
Log.d(TAG, String.format("%s %s, p %d", sep, b.getTitle(), b.getPageIdx()));
if (b.hasChildren()) {
printBookmarksTree(b.getChildren(), sep + "-");
}
}
}
// Usage:
List<PdfDocument.Bookmark> toc = pdfiumCore.getTableOfContents(pdfDocument);
printBookmarksTree(toc, "-");PdfiumCore core = new PdfiumCore(context);
PdfDocument document = core.newDocument(fd);
int pageIndex = 0;
core.openPage(document, pageIndex);
List<PdfDocument.Link> links = core.getPageLinks(document, pageIndex);
for (PdfDocument.Link link : links) {
RectF mappedRect = core.mapRectToDevice(document, pageIndex,
startX, startY, sizeX, sizeY, 0, link.getBounds());
if (clickedArea(mappedRect)) {
String uri = link.getUri();
if (link.getDestPageIdx() != null) {
// Jump to page
int destPage = link.getDestPageIdx();
} else if (uri != null && !uri.isEmpty()) {
// Open URI using Intent
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);
}
}
}| Method | Description |
|---|---|
newDocument(ParcelFileDescriptor) |
Create document from file |
newDocument(ParcelFileDescriptor, String) |
Create document from password-protected file |
newDocument(byte[]) |
Create document from byte array |
newDocument(byte[], String) |
Create document from password-protected byte array |
getPageCount(PdfDocument) |
Get total page count |
openPage(PdfDocument, int) |
Open single page |
openPage(PdfDocument, int, int) |
Open range of pages |
getPageWidth(PdfDocument, int) |
Get page width in pixels (requires page open) |
getPageHeight(PdfDocument, int) |
Get page height in pixels (requires page open) |
getPageWidthPoint(PdfDocument, int) |
Get page width in points (1/72") |
getPageHeightPoint(PdfDocument, int) |
Get page height in points (1/72") |
getPageSize(PdfDocument, int) |
Get page size without opening page |
renderPage(PdfDocument, Surface, ...) |
Render to Surface |
renderPageBitmap(PdfDocument, Bitmap, ...) |
Render to Bitmap |
getDocumentMeta(PdfDocument) |
Get document metadata |
getTableOfContents(PdfDocument) |
Get bookmarks tree |
getPageLinks(PdfDocument, int) |
Get links from page |
mapPageCoordsToDevice(...) |
Map page coords to screen |
mapRectToDevice(...) |
Map rect from page to screen |
closeDocument(PdfDocument) |
Close document and release resources |
// RGB_565 - Lower memory usage (default recommended)
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
// ARGB_8888 - Higher quality, more memory
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Add to your ProGuard rules:
-keep class com.shockwave.**
This keeps the Pdfium native interface classes required for JNI calls.
This library includes native libraries (~34MB per architecture) for high-fidelity PDF rendering with V8 JavaScript support. Use APK splits or App Bundles to reduce download size:
android {
bundle {
abi {
enableSplit = true
}
}
// Or for APK splits:
splits {
abi {
enable true
reset()
include 'arm64-v8a', 'x86_64'
universalApk false
}
}
}Google Play requires 64-bit support and is phasing out 32-bit-only apps. This fork focuses on 64-bit architectures (arm64-v8a, x86_64) for optimal compatibility and performance.
The src/main/jni/lib directory contains prebuilt libraries for 32-bit architectures (armeabi-v7a, x86) from the original build, but they are not 16KB aligned. For 16KB compliance, only use the libraries in src/main/jniLibs/.
- No support for password-protected PDFs
- No link/bookmark handling or form rendering
- No JavaScript support for interactive PDFs
- Limited rendering quality options
- No document metadata extraction
- AndroidPdfViewer (16KB Fork) — The companion high-level PDF viewer library with gestures, zoom, and more
- Original PdfiumAndroid — The upstream native library (unmaintained)
- mhiew's PdfiumAndroid — Previous maintenance fork
- PDFium from AOSP — The underlying rendering engine
- 🎯 16KB page size compliance — Critical for Android 15 and Play Store 2025
- ⬆️ Compile/Target SDK updated to 35 (Android 15)
- ⬆️ AGP updated to 8.12.0
- ⬆️ Gradle updated to 8.14.2
- ⬆️ NDK updated to 27.3.13750724
- ⬆️ Java 17 support
- ⬆️ Min SDK raised to 21
- 🔄 Rebuilt native libraries with Chromium-based PDFium + V8
- 🔄 New unified
NativeLoaderfor reliable library loading - ✅ 64-bit only builds (arm64-v8a, x86_64)
- ✅ Jetifier disabled
See CHANGELOG.md for full version history from upstream.
- Android Studio with AGP 8.12.0+ support
- JDK 17+
- Android NDK 27.3.13750724
# Clone the repository
git clone https://github.com/Akul-Tyagi/PdfiumAndroid.git
cd PdfiumAndroid
# Build the library
./gradlew assembleRelease
# Publish to local Maven
./gradlew publishToMavenLocalThe prebuilt native libraries are already 16KB aligned. If you need to rebuild:
cd src/main/jni
$ANDROID_NDK_HOME/ndk-buildContributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Submit a pull request
Original work Copyright 2015 Bekket McClane
Modified work Copyright 2016 Bartosz Schiller
Modified work Copyright 2022 Min Hiew
Modified work Copyright 2024 Akul Tyagi (16KB modernization fork)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---
PDFium License (BSD-style):
Copyright 2014 PDFium Authors. All rights reserved.
See LICENSE file for full terms.
- Bekket McClane — Original PdfiumAndroid author
- Bartosz Schiller — AndroidPdfViewer ecosystem
- Min Hiew — Previous maintenance work
- PDFium Authors — The underlying rendering engine
⭐ Star this repo if it helped you comply with Google Play 2025 requirements! ⭐