0

Here is what I do :

  1. create a Native C++ project use android studio template
  2. create a class com.jnitest.app.JNIInterface
package com.jnitest.app;

public class JNIInterface {
    public static native String getString();
    public static native String getName();
}


with the native-lib.cpp

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_jnitest_app_JNIInterface_getString(JNIEnv *env, jclass thiz) {
    std::string name = "return String from JNIInterface";
    return env->NewStringUTF(name.c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_jnitest_app_JNIInterface_getName(JNIEnv *env, jclass clazz) {
    std::string name = "return name from JNIInterface";
    return env->NewStringUTF(name.c_str());
}
  1. create a test class com.jnitest.app.JNITest
package com.jnitest.app;

public class JNITest {
    {
        System.loadLibrary("app");
    }
    public static void main(String[] args) {
        System.out.println("Hello from JNITest");
        System.out.println("String from JNI: " + JNIInterface.getString());
    }
}

  1. build push and run
adb push .\build\intermediates\apk\debug\app-debug.apk /data/local/tmp/app-debug.jar 

adb shell CLASSPATH=/data/local/tmp/app-debug.jar  app_process ./ com.jnitest.app.JNITest
  1. get output
Hello from JNITest
Killed

Why I cannot get the right result ?

Lty
  • 1
  • 2
  • Possibly related: [How to execute the dex file in android with command?](https://stackoverflow.com/a/10200822/295004). As it is an old question, please read/follow comment threads. – Morrison Chang Apr 08 '22 at 04:43

2 Answers2

0

I had this problem too. Native library is not found by ClassLoader. Try the following.

  1. The useLegacyPackaging false needs to be added to build.gradle so that libs are not compressed and can be directly loaded from inside apk.
android {
    packagingOptions {
        jniLibs {
            useLegacyPackaging false
        }
    }
}
  1. Load your native library this way.
package com.jnitest.app;

public class JNITest {
    public static void main(String[] args) {
        System.out.println("Hello from JNITest");
        System.out.println("String from JNI: " + JNIInterface.getString());
    }
    static {
        String libPath = System.getenv("CLASSPATH") +
                "!/lib/" + Build.SUPPORTED_ABIS[0] +
                "/libapp.so";
        System.err.println("Loading shared library: " + libPath);
        System.load(libPath);
    }
}
Twaik Yont
  • 102
  • 10
0

I believe since in newer android version(>23), the so files inside apk will not be compressed at all for fewer space occupation after installation.

To make sure those so files will not be compressed, change the build.gradle script of the app module to this:

android {
    ...
    packagingOptions {
        jniLibs {
            useLegacyPackaging false
        }
    }
    ...
}

In my project, the gradle version I used is 6.7.1, and the corresponding com.android.tools.build version is 4.2.0. Other newer combination should also apply this jniLibs block.

After this, you could treat the apk or jar as a special folder by appending an exclamation mark(!).

If you want to access the content of the folder inside apk (a folder containing so files), you could run a command like:

LD_LIBRARY_PATH=/path/to/apk/temp.apk!/lib/abi CLASSPATH=/path/to/apk/temp.apk app_process /system/bin com.package.name.Main

Where the lib/abi inside temp.apk contains the so files you wanna use in com.package.name.Main.

A fantastic trick. Works like a charm.

yuhui su
  • 1
  • 1