diff --git a/CHANGELOG.md b/CHANGELOG.md index c2cd1908ef..8ebf866831 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ All notable changes to this project will be documented in this file. Take a look * EPUB HREFs that are not percent-encoded but carry a fragment or query (e.g. `chapter one.xhtml#section`, with a space in the filename) now keep their `#fragment`/`?query` instead of encoding the separators into the path. This fixes table of contents and Media Overlays links failing to resolve and navigate in poorly-authored EPUBs. +#### LCP + +* [#796](https://github.com/readium/kotlin-toolkit/issues/796) Fixed a crash (`UnsatisfiedLinkError`) when the `liblcp` native library cannot be loaded, for example on some rooted devices. `LcpService()` now returns `null` in this case too, and logs the cause with Timber. + ## [3.3.0] - 2026-06-02 diff --git a/readium/lcp/src/main/java/org/readium/r2/lcp/service/LcpClient.kt b/readium/lcp/src/main/java/org/readium/r2/lcp/service/LcpClient.kt index c14c08bf48..372c41bae3 100644 --- a/readium/lcp/src/main/java/org/readium/r2/lcp/service/LcpClient.kt +++ b/readium/lcp/src/main/java/org/readium/r2/lcp/service/LcpClient.kt @@ -6,7 +6,7 @@ import java.lang.reflect.InvocationTargetException import org.readium.r2.lcp.LcpError import org.readium.r2.lcp.LcpException import org.readium.r2.shared.InternalReadiumApi -import org.readium.r2.shared.extensions.tryOr +import timber.log.Timber internal object LcpClient { @@ -47,10 +47,17 @@ internal object LcpClient { Class.forName("org.readium.lcp.sdk.Lcp") } - fun isAvailable(): Boolean = tryOr(false) { - instance - true - } + fun isAvailable(): Boolean = + try { + instance + true + } catch (e: Throwable) { + // We catch any Throwable instead of Exception, because loading the liblcp native + // library can fail with an UnsatisfiedLinkError, which is an Error. + // See https://github.com/readium/kotlin-toolkit/issues/796 + Timber.e(e, "The Readium LCP library is unavailable") + false + } fun createContext(jsonLicense: String, hashedPassphrases: String, pemCrl: String): Context = try {