Can Kotlin be used for Android plugins? If yes, then what has to be done in order to make it work? I tried adding a Kotlin class to my plugin then calling it from the main Java singleton, but Gradle wouldn't find it. I think the documentation for Android plugins is lacking a lot of details.

I found a way to make it work:

gradle.conf for the plugin:

[buildscript_dependencies]
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        
[dependencies]
        api ('org.jetbrains.kotlin:kotlin-stdlib:1.3.71')
        api ('org.jetbrains.kotlin:kotlin-stdlib-common:1.3.71')

This adds the kotlin standard library as a dependency, and applies the kotlin-android plugin. You also need to apply it in build.gradle of the build module (res://android/build/build.gradle): 1. Add apply plugin: 'kotlin-android' under buildscript{} . 2. Also, add ext.kotlin_version = '1.3.71' to buildscript{} to specify the kotlin version to use. This is how the top part of it will look like:

buildscript {
    apply from: 'config.gradle'
    ext.kotlin_version = '1.3.71' // This part is added

    repositories {
        google()
        jcenter()
//CHUNK_BUILDSCRIPT_REPOSITORIES_BEGIN
//CHUNK_BUILDSCRIPT_REPOSITORIES_END
    }
    dependencies {
        classpath libraries.androidGradlePlugin
//CHUNK_BUILDSCRIPT_DEPENDENCIES_BEGIN
//CHUNK_BUILDSCRIPT_DEPENDENCIES_END
    }
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' // This part is added

Now for the plugin itself: The tree for an example plugin:

example
├── gradle.conf
└── src
    ├── Example.kt
    └── ExampleSingleton.java

ExampleSingleton.java:

package org.godotengine.godot;

import android.app.Activity;
import android.content.Intent;
import android.content.Context;
import com.godot.game.R;
import javax.microedition.khronos.opengles.GL10;
import org.godotengine.godot.Example;

public class ExampleSingleton extends Godot.SingletonBase {

    static public Godot.SingletonBase initialize(Activity p_activity) {
        return new Example(p_activity);
    }
}

This is just used as an interface for Godot to make it able to initialize our Kotlin class.

Example.kt is a translation of the example Java singleton class provided in the documentation, but without the initiailize function, since that is defined in ExampleSingleton.java:

package org.godotengine.godot

import android.app.Activity
import android.content.Intent
import android.content.Context
import com.godot.game.R
import javax.microedition.khronos.opengles.GL10

class Example(p_activity: Activity): Godot.SingletonBase() {

    protected var appActivity: Activity
    protected var appContext: Context
    private var activity: Godot? = null
    private var instanceId = 0
    fun myFunction(p_str: String): String {
        // A function to bind.
        return "Hello $p_str"
    }

    fun getInstanceId(pInstanceId: Int) {
        // You will need to call this method from Godot and pass in the get_instance_id().
        instanceId = pInstanceId
    }

    // Forwarded callbacks you can reimplement, as SDKs often need them.
    override fun onMainActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {}
    override fun onMainRequestPermissionsResult(requestCode: Int, permissions: Array<String?>?, grantResults: IntArray?) {}
    override fun onMainPause() {}
    override fun onMainResume() {}
    override fun onMainDestroy() {}
    override fun onGLDrawFrame(gl: GL10?) {}
    override fun onGLSurfaceChanged(gl: GL10?, width: Int, height: Int) {} // Singletons will always miss first 'onGLSurfaceChanged' call.

    init {
        // Register class name and functions to bind.
        registerClass("ExampleSingleton", arrayOf(
                "myFunction",
                "getInstanceId"
        ))
        appActivity = p_activity
        appContext = appActivity.getApplicationContext()
        // You might want to try initializing your singleton here, but android
        // threads are weird and this runs in another thread, so to interact with Godot you usually have to do.
        activity = p_activity as Godot
        activity?.apply {
                runOnUiThread(object : Runnable {
                override fun run() {
                    // Useful way to get config info from "project.godot".
                    val key: String = GodotLib.getGlobal("plugin/api_key")
                    // SDK.initializeHere();
                }
            })
        }
    }
}

Now in Godot: Import the Java singleton class as a module (org/godotengine/godot/ExampleSingleton):

Now you should be ready to use the plugin in GDScript as shown in the documentation:

if Engine.has_singleton("ExampleSingleton"):
    var singleton = Engine.get_singleton("ExampleSingleton")
    print(singleton.myFunction("World"))

Result from logcat: 04-10 16:10:22.064 25301 25325 I godot : Hello World

3 years later