CNSDK init error in C++/OpenGL 3D model viewer app

Attempting to integrate Leia CNSDK into existing 3D model viewer app which uses C++ and OpenGL.

Basic CNSDK integration (download and extract .zip and include .aar) working.

But when attempting to call doCNSDKInit(), getting this error:

[LeiaSDK] [info] version: 0.7.28 (refs/heads/main - 1c3d3935a7689b416e48d5ebfeaddb3b9fd03fff)
[LeiaSDK] [error] leia_core *leia::sdk::leia_core_init_async(leia_core_init_configuration *):
    android platform cannot be initialized without JavaVM. Set PlatformInitArgs.javaVM in
    leia::AndroidPlatform::AndroidPlatform(const leia::PlatformInitArgs &)
    D:/a/CNSDK/CNSDK/leia/common/android/androidPlatform.cpp:114 (-2)

Will probably be able to figure it out eventually but if anyone else has been able to solve this please let me know, thank you

1 Like

(Leia, please allow editing of posts; had to delete and re-create to fix a typo and add a bit of text)

For others facing this problem, there is a simple workaround (which hopefully can be refined in additional comments from people with better knowledge).

A bit of background: any android app with a non-trivial amount of C++ is highly likely to define function JNI_OnLoad(). Unfortunately this creates a minor conflict since the Leia CNSDK also defines JNI_OnLoad(), and the top level app version of the function will take precedence; i.e. Leia SDK JNI_OnLoad() won’t be called, and this leads directly to the error reported above.

This can be easily verified by adding a dummy JNI_OnLoad() in file app/src/main/cpp/native-lib.cpp in the CNSDK sample app. Build and launch, and it will crash with the same error.

It is common practice to store a global handle to the JavaVM * passed into JNI_OnLoad() (e.g. g_vm). So by simply adding one line in the CNSDK init function, we can fix the error and get our app running (this snippet is from doCNSDKInit()):

        leia::sdk::CoreInitConfiguration config;
        config.SetPlatformAndroidJavaVM(g_vm);  // <-- Add this line (g_vm should be set in JNI_OnLoad())
        config.SetPlatformAndroidHandle(LEIA_CORE_ANDROID_HANDLE_ACTIVITY, activity);

HTH

(Due to lack of permission to edit own post, had to delete and re-create instead of updating in-place)

If you see this error in your “real world” (non-“toy”) project:

[LeiaSDK] [info] version: 0.7.28 (refs/heads/main - 1c3d3935a7689b416e48d5ebfeaddb3b9fd03fff)
[LeiaSDK] [error] leia_core *leia::sdk::leia_core_init_async(leia_core_init_configuration *):
    JNI call failed: methodId = jniEnv->GetMethodID(clazz, name, signature) in 
    leia::jni::InstanceMethod<_jobject *()>::InstanceMethod(
        JNIEnv *, jclass, const char *, const char *
    ) [T = _jobject *()] D:/a/CNSDK/CNSDK\leia/common/android/jniUtils.hpp:556 (-2)
java.lang.NoSuchMethodError: no non-static method 
    "Ljava/lang/Class;.getApplication()Landroid/app/Application;"

it may be necessary to pass the activity explicitly via 3rd parameter, rather than the way the sample app does it where because the native function is defined in MainActivity, the 2nd parameter implicitly contains a reference to the activity, e.g.

Managed-side

Before
public native boolean doCNSDKInit();

After
public native boolean doCNSDKInit(Activity activity);

Native-side

Before
Java_com_leia_cnsdkgettingstartedglandroidnative_MainActivity_doCNSDKInit(
        JNIEnv*,
        jobject activity)

After
Java_com_leia_cnsdkgettingstartedglandroidnative_MainActivity_doCNSDKInit(
        JNIEnv*,
        jobject jObj,
        jobject activity)

HTH