Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attempting to run an embedded Ktor HTTP Server on Android

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.

like image 823
Simi Avatar asked Apr 20 '18 15:04

Simi


1 Answers

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

like image 59
Sergey Mashkov Avatar answered Oct 08 '22 16:10

Sergey Mashkov