Android loading may fallback to standard JVM (#9)

* Android loading may fallback to standard JVM

* Java code must target JVM 1.8 in order to be compatible Android.

Co-authored-by: Salomon BRYS <salomon@kodein.net>
This commit is contained in:
Salomon BRYS 2020-07-16 22:21:30 +02:00 committed by GitHub
parent 0cc4c251f9
commit dbf8301f34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 51 additions and 26 deletions

View File

@ -24,7 +24,7 @@ buildscript {
allprojects { allprojects {
group = "fr.acinq.secp256k1" group = "fr.acinq.secp256k1"
version = "0.2.1-1.4-M3" version = "0.3.0-1.4-M3"
repositories { repositories {
jcenter() jcenter()

View File

@ -0,0 +1,31 @@
package fr.acinq.secp256k1.jni
import android.util.Log
import fr.acinq.secp256k1.Secp256k1
import fr.acinq.secp256k1.NativeSecp256k1
import java.util.*
public object NativeSecp256k1AndroidLoader {
@JvmStatic
@Synchronized
@Throws(Exception::class)
fun load(): Secp256k1 {
try {
System.loadLibrary("secp256k1-jni")
return NativeSecp256k1
} catch (ex: UnsatisfiedLinkError) {
// Purposefully not using Android Log
println("Could not load Android Secp256k1. Trying to extract JVM platform specific version.")
try {
val cls = Class.forName("fr.acinq.secp256k1.jni.NativeSecp256k1JvmLoader")
val load = cls.getMethod("load")
return load.invoke(null) as Secp256k1
} catch (_: ClassNotFoundException) {
throw ex
}
}
}
}

View File

@ -1,16 +0,0 @@
package fr.acinq.secp256k1.jni
import fr.acinq.secp256k1.Secp256k1
import fr.acinq.secp256k1.NativeSecp256k1
public object NativeSecp256k1Loader {
@JvmStatic
@Synchronized
@Throws(Exception::class)
fun load(): Secp256k1 {
System.loadLibrary("secp256k1-jni")
return NativeSecp256k1
}
}

View File

@ -3,6 +3,11 @@ plugins {
`maven-publish` `maven-publish`
} }
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlin { kotlin {
explicitApi() explicitApi()
} }

View File

@ -14,7 +14,7 @@ import java.util.*
* *
* @author leo * @author leo
*/ */
public object NativeSecp256k1Loader { public object NativeSecp256k1JvmLoader {
private var extracted = false private var extracted = false
/** /**
@ -106,7 +106,7 @@ public object NativeSecp256k1Loader {
val extractedLckFile = File(targetDirectory, extractedLckFileName) val extractedLckFile = File(targetDirectory, extractedLckFileName)
return try { return try {
// Extract a native library file into the target directory // Extract a native library file into the target directory
val reader = NativeSecp256k1Loader::class.java.getResourceAsStream(libPath) val reader = NativeSecp256k1JvmLoader::class.java.getResourceAsStream(libPath)
if (!extractedLckFile.exists()) { if (!extractedLckFile.exists()) {
FileOutputStream(extractedLckFile).close() FileOutputStream(extractedLckFile).close()
} }
@ -132,7 +132,7 @@ public object NativeSecp256k1Loader {
extractedLibFile.setExecutable(true) extractedLibFile.setExecutable(true)
// Check whether the contents are properly copied from the resource folder // Check whether the contents are properly copied from the resource folder
NativeSecp256k1Loader::class.java.getResourceAsStream(libPath).use { nativeIn -> NativeSecp256k1JvmLoader::class.java.getResourceAsStream(libPath).use { nativeIn ->
FileInputStream(extractedLibFile).use { extractedLibIn -> FileInputStream(extractedLibFile).use { extractedLibIn ->
if (!nativeIn.contentsEquals(extractedLibIn)) { if (!nativeIn.contentsEquals(extractedLibIn)) {
throw RuntimeException( throw RuntimeException(
@ -196,9 +196,9 @@ public object NativeSecp256k1Loader {
} }
// Load the os-dependent library from the jar file // Load the os-dependent library from the jar file
val packagePath = NativeSecp256k1Loader::class.java.getPackage().name.replace("\\.".toRegex(), "/") val packagePath = NativeSecp256k1JvmLoader::class.java.getPackage().name.replace("\\.".toRegex(), "/")
val embeddedLibraryPath = "/$packagePath/native/${OSInfo.nativeSuffix}" val embeddedLibraryPath = "/$packagePath/native/${OSInfo.nativeSuffix}"
val hasNativeLib = NativeSecp256k1Loader::class.java.getResource("$embeddedLibraryPath/$libraryName") != null val hasNativeLib = NativeSecp256k1JvmLoader::class.java.getResource("$embeddedLibraryPath/$libraryName") != null
if (!hasNativeLib) { if (!hasNativeLib) {
error("No native library found: at $embeddedLibraryPath/$libraryName") error("No native library found: at $embeddedLibraryPath/$libraryName")
} }

View File

@ -16,15 +16,20 @@
package fr.acinq.secp256k1 package fr.acinq.secp256k1
import java.lang.IllegalStateException import java.util.*
internal actual fun getSecpk256k1(): Secp256k1 { private fun tryLoad(platform: String): Secp256k1? {
try { try {
val cls = Class.forName("fr.acinq.secp256k1.jni.NativeSecp256k1Loader") val cls = Class.forName("fr.acinq.secp256k1.jni.NativeSecp256k1${platform.capitalize(Locale.ROOT)}Loader")
val load = cls.getMethod("load") val load = cls.getMethod("load")
return load.invoke(null) as Secp256k1 return load.invoke(null) as Secp256k1
} catch (ex: ClassNotFoundException) { } catch (ex: ClassNotFoundException) {
throw IllegalStateException("Could not load native Secp256k1 JNI library. Have you added the JNI dependency?", ex) return null
} }
} }
internal actual fun getSecpk256k1(): Secp256k1 =
tryLoad("android")
?: tryLoad("jvm")
?: error("Could not load native Secp256k1 JNI library. Have you added the JNI dependency?")