Jatin guglani
Jatin guglani

Reputation: 267

can I invoke a composable kotlin function(jetpack compose) from from cpp using jni

I know that we can call a normal Kotlin method in cpp using JNI, by using (env)->GetMethodID(class, Methodname, signatures) and (env)->CallVoidMethod(object, methodID, parameters)

but I'm unable to do the same for composable kotlin method when using jetpack compose. (env)->GetMethodID is returning null in this case.

I'm getting error:

java.lang.NoSuchMethodError: no non-static method "Lcom/example/jetpackcompose/MainActivity;.MessageCard(Ljava/lang/String;Ljava/lang/String;)V"

I also tried to invoke a composable method from a non-composable method and invoke the non-composable method from jni but that's also not possible because a composable method can only be invoked from another composable method.

Is there a way to invoke a composable kotlin method from jni?

MainActivity.kt

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        var str:String = stringFromJNI()
        MessageCardCpp()
    }
}

@Composable
fun MessageCard(author: String, body: String) {
    Row() {

        Image(painter = painterResource(R.drawable.sampleimage),
            contentDescription = "Sample Image",
            modifier = Modifier
                .size(80.dp)
                .clip(CircleShape)
        )

        Spacer(modifier = Modifier.width(8.dp))

        Column() {
            Text(author, fontSize = 30.sp)
            Spacer(modifier = Modifier.width(4.dp))
            Text(body, fontSize = 30.sp)
        }
    }
}

external fun stringFromJNI(): String
external fun MessageCardCpp()

companion object {
    // Used to load the 'jetpackcompose' library on application startup.
    init {
        System.loadLibrary("jetpackcompose")
    }
}
}

native-lib.cpp

extern "C" JNIEXPORT void JNICALL
Java_com_example_jetpackcompose_MainActivity_MessageCardCpp(JNIEnv *env, jobject thiz) {

jclass MainActivity = (env)->FindClass("com/example/jetpackcompose/MainActivity");

if(MainActivity == nullptr) {

    __android_log_print(ANDROID_LOG_DEBUG, "Demo", "%s", "GetClass returns Null");
    return;
}

jmethodID MessageCard = (env)->GetMethodID(MainActivity, "MessageCard","(Ljava/lang/String;Ljava/lang/String;)V");

if(MessageCard == nullptr) {

    __android_log_print(ANDROID_LOG_DEBUG, "Demo", "%s", "GetMethodID returns Null");
    return;
}

(env)->CallVoidMethod(thiz, MessageCard, env->NewStringUTF("Android JetPack"), env->NewStringUTF("Hello Cpp"));
}

Upvotes: 2

Views: 369

Answers (1)

Botje
Botje

Reputation: 31020

I'm afraid your question is a non-starter. The @Composable annotation is processed by the Android Kotlin plugin at compile time simply by inspecting all method/function calls. The generated code no longer contains @Composable calls, but references to a graph that represents your application's layout and how to render it.

By contrast, the JNI code can only execute at runtime, so it is too late to call @Composable methods.

Upvotes: 1

Related Questions