I'm trying to embed Ktor in an Android Service in order to check remotely some assets on an app at some point.
I'm following the code in this tutorial
I get this error when I attempt to access the link for example on "192.168.2.105:7070":
04-20 14:50:58.523 29389-29389 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mypackage.fetchingservice, PID: 29389
java.lang.NoClassDefFoundError:io.ktor.application.ApplicationEvents$subscribe$1
at io.ktor.application.ApplicationEvents.subscribe(ApplicationEvents.kt:18)
at io.ktor.server.engine.BaseApplicationEngine.<init>(BaseApplicationEngine.kt:29)
at io.ktor.server.engine.BaseApplicationEngine.<init>(BaseApplicationEngine.kt:15)
at io.ktor.server.netty.NettyApplicationEngine.<init>(NettyApplicationEngine.kt:16)
at io.ktor.server.netty.Netty.create(Embedded.kt:10)
at io.ktor.server.netty.Netty.create(Embedded.kt:8)
at io.ktor.server.engine.EmbeddedServerKt.embeddedServer(EmbeddedServer.kt:50)
at io.ktor.server.engine.EmbeddedServerKt.embeddedServer(EmbeddedServer.kt:40)
at io.ktor.server.engine.EmbeddedServerKt.embeddedServer$default(EmbeddedServer.kt:27)
at com.hirschandmann.magickservice.KtorFetchService.onCreate(KtorFetchService.kt:30)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2761)
at android.app.ActivityThread.access$1800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1386)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:935)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:730)
Here's the code. Service is registered in the manifest and I launch it from adb using:
adb shell am startservice com.mypackage.service/.KtorFetchService
class KtorFetchService : Service() {
override fun onBind(intent: Intent?): IBinder {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
private val HTTP_PORT = 7070
override fun onCreate() {
embeddedServer(Netty, HTTP_PORT) {
routing {
get("/") {
call.respondText("My Example Fetch", ContentType.Text.Html)
}
}
}.start(wait = true)
super.onCreate()
}
}
Here's the module gradle file:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.hirschandmann.magickservice"
minSdkVersion 21
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
pickFirst 'META-INF/*'
}
}
repositories {
jcenter()
mavenCentral()
maven { url "http://dl.bintray.com/kotlin/ktor" }
maven { url "https://dl.bintray.com/kotlin/kotlinx" }
}
configurations {
ktlint
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation'com.android.support:appcompat-v7:27.1.1'
testImplementation'junit:junit:4.12'
androidTestImplementation'com.android.support.test:runner:1.0.1'
androidTestImplementation'com.android.support.test.espresso:espresso-core:3.0.1'
// AutoValue
compileOnly "com.google.auto.value:auto-value:1.5.2"
annotationProcessor "com.google.auto.value:auto-value:1.5.2"
// ktlint
ktlint "com.github.shyiko:ktlint:0.15.0"
implementation'com.github.hkk595:Resizer:v1.5'
implementation'com.jrummyapps:android-shell:1.0.1'
implementation'org.nanohttpd:nanohttpd:2.3.1'
implementation"io.ktor:ktor:$ktor_version" // ktor dependency
implementation"io.ktor:ktor-server-netty:$ktor_version"
}
task ktlint(type: JavaExec, group: "verification") {
description = "Check Kotlin code style."
classpath = configurations.ktlint
main = "com.github.shyiko.ktlint.Main"
args "src/**/*.kt"
//args "--reporter=checkstyle,output=${buildDir}/ktlint.xml"
}
check.dependsOn ktlint
androidExtensions {
experimental = true
}
Here's the project's gradle file:
buildscript {
ext.kotlin_version = '1.2.40'
ext.ktor_version = '0.9.1'
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
plugins {
id "io.gitlab.arturbosch.detekt" version "1.0.0.RC6-3"
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
detekt {
version = "1.0.0.RC6-3"
profile("main") {
input = "$projectDir/app/src/main/java"
config = "$projectDir/default-detekt-config.yml"
filters = ".*test.*,.*/resources/.*,.*/tmp/.*"
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
The device is an Odroid C2 with Android 5.1.1 (API 22) I'm using Android studio 3.1 and JRE 1.8 running on a MacOS 10.13.3.
The error is caused by the following line in ktor ApplicationEvents.kt:18
handlers.computeIfAbsent(definition) { LockFreeLinkedListHead() }.addLast(registration)
This causes it to fail as far as ConcurrentHashMap.computeIfAbsent
and java.util.function.Function
has been initially introduced in API level 24 (proof).
Note that ktor server was never intended to run on android and originally targeted to servers with JDK8
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With