Search code examples
androidstringkotlinandroid-ndkunsatisfiedlinkerror

java.lang.UnsatisfiedLinkError: No implementation found (NDK, Kotlin) - Fixed


The file that I have in C using the NDK is the following, I have reviewed the package name in Kotlin and the one in class C (NDK) and I do not see any difference:

 jstring Java_com_test1_app1_ui_BaseActivity_getLocalKeyOld(JNIEnv* env, jobject obj, jstring id) {
    const char *nativeString = (*env)->GetStringUTFChars(env, id, 0);

    char* deviceIdEncode = base64encode(nativeString);
    int lenght = strlen(deviceIdEncode);

    jstring result;
    if(lenght < 16) {
        result = (*env)->NewStringUTF(env,"+-0wef2ccfeqa0-+");
    } else if(lenght > 16) {
        char subbuff[17];
        memcpy( subbuff, &deviceIdEncode[0], 16 );
        subbuff[16] = '\0';
        result = (*env)->NewStringUTF(env,subbuff);
    } else {
        result = (*env)->NewStringUTF(env,deviceIdEncode);
    }
    return result;
}


jstring Java_com_test1_app1_ui_BaseActivity_getLocalKey(JNIEnv* env, jobject obj, jstring id) {
    const char *nativeString = (*env)->GetStringUTFChars(env, id, 0);

    char* deviceIdEncode = base64encodeNew(nativeString);
    int lenght = strlen(deviceIdEncode);

    jstring result;
    if(lenght < 16) {
        result = (*env)->NewStringUTF(env,"+-0wef2ccfeqa0-+");
    } else if(lenght > 16) {
        char subbuff[17];
        memcpy( subbuff, &deviceIdEncode[0], 16 );
        subbuff[16] = '\0';
        result = (*env)->NewStringUTF(env,subbuff);
    } else {
        result = (*env)->NewStringUTF(env,deviceIdEncode);
    }
    return result;
}

My Kotlin class package is package com.test1.app1.ui

I load the lib library using those lines:

abstract class BaseActivity : AppCompatActivity() {

    companion object {
        @JvmStatic
        external fun getLocalKey(id: String): String

        @JvmStatic
        external fun getLocalKeyOld(id: String): String
    }

I am using NDK and Kotlin. The app starts well, but when I put it in Background, open others apps and try to go to my app it crashes. I can get just the next information :

E/zygote: No implementation found for java.lang.String com.test1.app1.ui.BaseActivity.getLocalKey(java.lang.String) 
    (tried Java_com_test1_app1_ui_BaseActivity_getLocalKey and Java_com_test1_app1_ui_BaseActivity_getLocalKey__Ljava_lang_String_2)




    Process: com.testLab.app1, PID: 31409
        java.lang.UnsatisfiedLinkError: No implementation found 
        for java.lang.String com.test1.app1.ui.BaseActivity.getLocalKey(java.lang.String) (tried Java_com_test1_app1_ui_BaseActivity_getLocalKey and Java_com_test1_app1_ui_BaseActivity_getLocalKey__Ljava_lang_String_2)
            at com_test1_app1_ui_BaseActivity.getLocalKey(Native Method)
            at com.test1.app1.ui.BaseActivity$Companion.getLocalKey(BaseActivity.kt:1)
            at com.test1.app1.services.Utils.decryptLocal(Utils.kt:620)
            at com.test1.app1.services.Utils.getUserPhone(Utils.kt:352)
            at com.test1.app1.ui.login.LoginActivity.initActivity(LoginActivity.kt:77)
            at com.test1.app1.ui.login.WelcomeActivity.onCreate(WelcomeActivity.kt:24)
            at android.app.Activity.performCreate(Activity.java:7032)
            at android.app.Activity.performCreate(Activity.java:7023)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1236)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2814)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2943)
            at android.app.ActivityThread.-wrap11(Unknown Source:0)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1630)
            at android.os.Handler.dispatchMessage(Handler.java:106)
            at android.os.Looper.loop(Looper.java:164)
            at android.app.ActivityThread.main(ActivityThread.java:6626)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)

FIX (It worked for me)

I notify that I was calling System.loadLibrary("nameofyourCFile") at the SplashActivity (SplashActivity extends BaseActivity) but the rest of activities does not load the C file because when I was going to background and coming back the SplashActivity was not launch again, so my library was not being loaded from anywhere. I put the System.loadLibrary() inside of my BaseActivity and it works!

P.S. Thank you Mr. @GenoChen for you help and time!


Solution

  • A System.loadLibrary() (maybe inside init {} block in companion object {} block) is necessary for Java runtime to find where the native library (which contains the "core" of the function) is. Just a @JvmStatic external fun (which is just a "surface" or "interface") is not enough.

    If you called these external function before loading that library, you will get such an exception.

    A correct way maybe (direct copy from the template of a new Android Studio project):

    class MainActivity : Activity()
    {
    
        override fun onCreate(savedInstanceState: Bundle?)
        {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            // Example of a call to a native method
            sample_text.text = stringFromJNI()
        }
    
        /**
         * A native method that is implemented by the 'native-lib' native library,
         * which is packaged with this application.
         */
        external fun stringFromJNI(): String
    
        companion object
        {
    
            // Used to load the 'native-lib' library on application startup.
            init
            {
                System.loadLibrary("native-lib")
            }
        }
    }
    

    Moving the external fun inside companion object {} like the original question is OK.