Attempting to run an embedded Ktor HTTP Server on Android - 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.

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

I've been running a Netty-based Ktor server on Android 5+ for a while, and I've created this minimal repo to demo it: https://github.com/gnarea/minimal-ktor-server-android

Related

How to generate gRPC code with protobuf on Kotlin for Android client?

I created a gRPC server (hosted by AWS) in nodejs and I can connect to it with a nodejs client implementation from my local machine.
I'm using the com.google.protobuf plugin to auto generate code from my .proto file.
My gradle sync works and the app builds successfully but I can't find the generated code classes.
I'm struggling to find a good implementation example for a Kotlin for Android gRPC client but I followed these articles:
gRPC In Kotlin(Android)
Java Basic Tutorial
My app/src/main/protos/responder.proto file
syntax = "proto3";
option java_package = "protos.grpc";
package responder;
message ConnectionRequest {
int32 userId = 2;
}
message ConnectionResponse {
string response = 1;
}
service ResponderService {
rpc responderConnect (stream ConnectionRequest) returns (stream ConnectionResponse) {};
}
Project build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
kotlin_version = '1.3.72'
protobufPluginVersion = '0.8.6'
grpcVersion = '1.12.0'
protocVersion = '3.2.0'
}
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.protobuf:protobuf-gradle-plugin:$protobufPluginVersion"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
def nav_version = "2.2.2"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
And my app's build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.protobuf'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "organisation.responder.two"
minSdkVersion 19
targetSdkVersion 29
versionCode 31
versionName "2.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
...
implementation 'io.grpc:grpc-okhttp:1.30.0'
implementation 'io.grpc:grpc-protobuf-lite:1.30.0'
implementation 'io.grpc:grpc-stub:1.30.0'
implementation 'io.grpc:grpc-core:1.30.0'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53'
def multidex_version = "2.0.1"
implementation "androidx.multidex:multidex:$multidex_version"
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.12.0"
}
plugins {
javalite {
artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0"
}
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.30.0"
}
}
generateProtoTasks {
all().each { task ->
task.builtins {
remove java
}
task.plugins {
javalite {}
grpc {
// Options added to --grpc_out
option 'lite'
}
}
}
}
}
As I said above, the gradle sync is successful and the project builds successfully. But where is the autogenerated code?
After following this build.gradle file as an example, I managed to generate the grpc code using the gradle protobuf plugin.
Major changes to my app level build.gradle file included:
Adding path to .proto file in sourceSets block under android block.
android {
...
sourceSets {
main {
proto {
srcDir 'src/main/protos' <-- path to .proto file
}
}
}
}
Change the protobuf block in app level build.gradle file
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.12.0"
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.30.0"
}
}
generateProtoTasks {
all().each { task ->
task.builtins {
remove javanano
java {
option 'lite'
}
}
task.plugins {
grpc {
// Options added to --grpc_out
option 'lite'
}
}
}
}
}
After a successful sync and build, the generated code files where located under app/build/generated/source/proto/debug/grpc/protos/grpc/ResponderServiceGrpc.java and app/build/generated/source/proto/debug/java/protos/grpc/Responder.java

Not able to execute testng.xml file from gradle command line

I have created a gradle project with kotlin in android studio for mobile automation And created task in build.gradle While I am executing test from command prompt eg: 'gradle Test' my test is not getting executed(Message is getting printed which is mention on this tasks). When I am executing directly from testng.xml file than scripts is getting executed successfully.
Below sample code for build.gradle
App -> build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.appium.automation"
minSdkVersion 21
targetSdkVersion 28`enter code here`
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'io.appium:java-client:7.0.0'
implementation 'org.assertj:assertj-core:3.12.2'
implementation 'org.testng:testng:6.14.3'
implementation 'org.junit.jupiter:junit-jupiter-api:5.5.0-M1'
implementation 'io.cucumber:cucumber-java8:4.3.1'
implementation 'org.apache.commons:commons-lang3:3.9'
implementation 'io.cucumber:cucumber-testng:4.3.1'
implementation 'io.cucumber:gherkin:5.1.0'
implementation 'com.aventstack:extentreports:4.0.9'
}
tasks.withType(Test) {
print("Hi")
useTestNG(){
println("Hi2")
suites '/app/testng.xml'
println("Hi3")
}
}
Project -> build.gradle
buildscript {
ext.kotlin_version = '1.3.31'
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
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
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
I suppose the problem is with test options, try inserting this code to build.gradle in app level.
android {
testOptions {
unitTests.includeAndroidResources = true
unitTests.all {
useJUnitPlatform()
reports {
junitXml.enabled = true
html.enabled = false
}
testLogging {
events "passed", "skipped", "failed"
// to run JUnit 3/4 tests:
testImplementation("junit:junit:4.12")
testRuntime("org.junit.vintage:junit-vintage-engine:5.7.0")
}
}
}
}
This issue was mentioned at: https://github.com/kotest/kotest/issues/622
To execute a concrete test from command line, you can try:
./gradlew test --tests "com.MyTestCkass.myTest"

Error in gradle Android studio: "Cannot invoke method get() on null object"

I have a projects with number of modules, each one is a separate app.
I added Firebase to one module, and since then another one's gradle cannot be sync.
I keep getting: "Cannot invoke method get() on null object", which disappear when I comment out the play-service" dependencies.
My gradle is:
buildscript {
repositories {
google()
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
}
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
repositories {
maven { url 'https://maven.fabric.io/public' }
}
android {
compileSdkVersion 27
buildToolsVersion "27.0.3"
defaultConfig {
applicationId "xxxx"
minSdkVersion 14
targetSdkVersion 27
// multiDexEnabled true
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
implementation('com.crashlytics.sdk.android:crashlytics:2.9.1#aar') {
transitive = true;
}
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.google.android.gms:play-services-location:15.0.1'
implementation 'com.google.android.gms:play-services-maps:15.0.1'
}
The top-level project gradle:
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
I use gradle version 4.4 and Android plugin version 3.1.3
The error's stack
java.lang.NullPointerException: Cannot invoke method get() on null object
at
org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:91)
at
org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:48)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at
org.codehaus.groovy.runtime.callsite.NullCallSite.call(NullCallSite.java:35)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at
org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:57)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at com.google.gms.googleservices.GoogleServicesPlugin$1$_afterResolve_closure1.doCall(GoogleServicesPlugin.groovy:316)
at
sun.reflect.GeneratedMethodAccessor357.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at
java.lang.reflect.Method.invoke(Method.java:498)
at
org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at
groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at
org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
at
groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
at
groovy.lang.Closure.call(Closure.java:414)
at
groovy.lang.Closure.call(Closure.java:430)
(another 150 lines)
Any suggestion will help,
Cheers.
if you use difference modules you must add firebase config to all android modules
therefor
add implementation 'com.google.firebase:firebase-core:x' to dependencies
add apply plugin: 'com.google.gms.google-services'
get firebase config ("google-service.json") for each android module and add to each module

Unresolved reference async in Kotlin

I am trying to perform network operation async in Kotlin. I read it you can do async using async function. I am getting below error, can anyone guess what could be the issue ?
Unresolved reference: async
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
async() {
val forecastWeather = ForecastRequest("302015").execute()
Log.d("Test", forecastWeather.toString())
}
}
ForecastRequest.kt
class ForecastRequest(val zipcode: String) {
companion object {
private val APP_ID = "XYZ"
private val URL = "http://api.openweathermap.org/data/2.5/" +
"forecast/daily?mode=json&units=metric&cnt=7"
private val COMPLETE_URL = "$URL&APPID=$APP_ID&q="
}
fun execute(): ForecastResponse {
val forecastJsonStr = java.net.URL(COMPLETE_URL + zipcode).readText()
return Gson().fromJson(forecastJsonStr, ForecastResponse::class.java)
}
}
Top level build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.1.2-4'
repositories {
maven { url 'https://maven.google.com' }
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha2'
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
}
}
allprojects {
repositories {
maven { url 'https://maven.google.com' }
jcenter()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Module level build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.williams.thirddemo"
minSdkVersion 23
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.google.code.gson:gson:2.8.1'
}
async is available inside kotlinx.couroutines
Make sure that you added the dependency in your gradle file:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'
Also make sure that the async is called on a coroutine scrope such as GlobalScope.
val deferredResult = GlobalScope.async {
}
I see async function is available in anko library not Kotlin library itself. https://github.com/Kotlin/anko
I resolved by adding this dependency in build.gradle compile "org.jetbrains.anko:anko-commons:0.10.1" as this is not available in Kotlin itself.
I see that async is deprecated now, library suggests to use doAsync instead.
doAsync {
val forecastWeather = ForecastRequest("302015").execute()
uiThread {
Log.d("Test", forecastWeather.toString())
}
}
Different Kotlin libraries can have different implementations of async that do different things.
If you wanted the general async-await function from the core library, make sure you have a dependency to kotlinx.coroutines
if you are using Deferred , make sure you import kotlinx.coroutines.Deferred, there is also a chance you import firebase Deferred

Crashlytics - Unable to get crash reports when the app crashes while not connected to android studio

I'm using crashytics from Fabric.io in my app.
Here's how I have initialised it in my MainActivity.java at the very last of onCreate() method:
Fabric.with(this, new Crashlytics());
Here's build.gradle (Project: abc) file:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
maven { url 'https://maven.fabric.io/public'}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'com.google.gms:google-services:3.0.0'
classpath 'io.fabric.tools:gradle:1.+'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
maven { url "https://dl.bintray.com/hani-momanii/maven"}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Here's build.gradle (Module: app) file:
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.xxx.abc"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
repositories {
mavenCentral()
maven {
url "https://jitpack.io"
}
maven { url 'https://maven.fabric.io/public' }
}
dexOptions {
javaMaxHeapSize "4g"
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile('com.crashlytics.sdk.android:crashlytics:2.6.6#aar') {
transitive = true;
}
}
apply plugin: 'com.google.gms.google-services'
and
<meta-data
android:name="io.fabric.ApiKey"
android:value="xxxxxxxxxxxxxxxxxxxxxxxxxxx"
/> is defined in the AndroidManifest.xml between <application> tags.
The problem is that I'm unable to get the crash reports whenever the app crashes while not connected to Android Studio though I get the reports when the app crashes while connected to it.
Why is this happening and how can I get the crash reports each and every time the app crashes whether connected to Android Studio or not?
Remove from Activity and put inside Application class
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
}
Don't forget to add name in Application tag of manifest.xml
<application
...
android:name=".MyApplication"
...
</application>

Categories

Resources