ONYX and KOReader intro

I recently got an ONYX Boox Poke6 – an 6-inch Android-based e-ink reader.

ONYX has at least three lineups that I know of, targeting the Global, Chinese, and Russian markets. The one I got is from the Chinese lineup.

I’ve also ended up going for KOReader as my main reader app, because it’s infinitely customizable, doesn’t tie me to any specific ecosystem or hardware, and has a great community around it.

KOReader is mostly written in Lua, and has platform specific runtime, also known as “glue code”, to run it: on Android it uses luajit-launcher.

It also has some device specific features: for example, backlight brightness and warmth control. Here’s the general idea:

  1. A specific Device ID for a supported device is detected in DeviceInfo.kt based on Android Build fields such as MANUFACTURER, BRAND, and MODEL.
  2. That Device ID is later mapped to a device specific light controller in LightsFactory.kt

So when a new device needing a non-generic hardware control comes out – it has to be added to the luajit-launher. It’s very easy, here’s the PR for the Poke6.

That’d be it – the device should now be supported and use correct light controller. However KOReader has a very long release cycle, and luajit-launcher dependency also takes some time to update.

Solution would be to build an updated KOReader from sources, however:

  1. It would require setting up a proper enviroment to build Android apps
  2. A release commit would need some backporting to get it working

So I’ve decided to go for a simpler approach: just patch and rebuild the APK.

Patching the APK

Here’s the matching code:

// Onyx Poke 5
BRAND == "onyx" && MODEL == "poke5p"
-> Id.ONYX_POKE5

// Onyx Poke 6
BRAND == "onyx" && MODEL == "poke6"
-> Id.ONYX_POKE6

The first part is there for a while, and is included in release builds. The POKE6 entry is for the new device I’ve added.

So the patch itself is very simple: just change poke5p into poke6, since POKE5 uses light controller compatible with Poke6.

Okay, now to the actual patching. Grab the latest release APK: v2025.04 as of writing.

Unpack it with almighty apktool:

$ apktool d -f -r koreader-android-arm64-v2025.04.apk -o koreader-android-arm64-v2025.04
I: Using Apktool 2.11.1 on koreader-android-arm64-v2025.04.apk with 8 threads
I: Baksmaling classes.dex...
I: Copying raw resources...
I: Copying raw manifest...
I: Copying original files...
I: Copying assets...
I: Copying lib...
I: Copying unknown files...

Find the smali code responsible for device identification, and replace the specific string

$ cd koreader-android-arm64-v2025.04
$ rg poke5p
smali/org/koreader/launcher/device/DeviceInfo.smali
4019:    const-string v1, "poke5p"
$ sed -ie 's/poke5p/poke6/' smali/org/koreader/launcher/device/DeviceInfo.smali
$ cd ..

And rebuild the patched apk:

$ apktool b -f koreader-android-arm64-v2025.04
I: Using Apktool 2.11.1 on koreader-android-arm64-v2025.04.apk with 8 threads
I: Copying raw resources...
I: Smaling smali folder into classes.dex...
W: Unknown file type, ignoring: org/koreader/launcher/device/DeviceInfo.smalie
I: Building apk file...
I: Importing assets...
I: Importing lib...
I: Importing unknown files...
I: Built apk into: koreader-android-arm64-v2025.04/dist/koreader-android-arm64-v2025.04.apk

We now have to zipalign and sign the APK so it can be installed. Previously I’ve used separate tools for that, and this was always the most painful part to remember how to do correctly.

This time I’ve found the uber-apk-signer, which is way easier to use for such simple patching workflows:

$ java -jar uber-apk-signer-1.3.0.jar --apks koreader-android-arm64-v2025.04/dist/
source:
	.../koreader-android-arm64-v2025.04/dist
...
keystore:
... (DEBUG_EMBEDDED)

01. koreader-android-arm64-v2025.04.apk
    ...
	- zipalign success
	- sign success

	VERIFY
	file: .../koreader-android-arm64-v2025.04/dist/koreader-android-arm64-v2025.04-aligned-debugSigned.apk (29.04 MiB)
	...
	- zipalign verified
	- signature verified [v1, v2, v3]
            ...
            Subject: CN=Android Debug, OU=Android, O=US, L=US, ST=US, C=US
            ...
Successfully processed 1 APKs and 0 errors in 0.71 seconds.

That’s it! Now just install it with adb:

$ adb install koreader-android-arm64-v2025.04/dist/koreader-android-arm64-v2025.04-aligned-debugSigned.apk
Performing Incremental Install
Serving...
All files should be loaded. Notifying the device.
Success
Install command complete in 1071 ms

Of course to install a “self-signed” package you’d have to uninstall the official build first – but that’s not a big issue for KOReader since it stores all of its data externally, so you don’t really lose any data by reinstalling the app.

Postscriptum

It’s been more than 6 years since my last post here. I didn’t really have any interesting things to post about; they always felt too small or irrelevant.

But today I’ve thought it would be a good idea to post things even if they feel small or irrelevant: publicly posting stuff I’d usually keep private, so it’s easier for people (myself included) to find and use these notes.

This small note felt like a good starting point – let’s hope my next post doesn’t come in 2030.

Sorry if you’re here for *OS security stuff – I’m not doing that for last 5 years or so.