Android的NDK java.lang.UnsatisfiedLinkError中样品HELLO-JNI [英] Android NDK java.lang.UnsatisfiedLinkError on sample hello-jni

查看:268
本文介绍了Android的NDK java.lang.UnsatisfiedLinkError中样品HELLO-JNI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要运行在Android上一些本地的C code和正在试图安装NDK的。我使用Android的工作室。

I need to run some native C code on android and am trying to setup the NDK. I am using Android studio.

我已经导入了HELLO-JNI样品,但根本不起作用。
我总是得到一个 java.lang.UnsatisfiedLinkError中错误。

I've imported the hello-jni sample, but it simply doesn't work. I always get a java.lang.UnsatisfiedLinkError error.

NDK的构建:

$ ndk-build
[arm64-v8a] Gdbserver      : [aarch64-linux-android-4.9] libs/arm64-v8a/gdbserver
[arm64-v8a] Gdbsetup       : libs/arm64-v8a/gdb.setup
[x86_64] Gdbserver      : [x86_64-4.9] libs/x86_64/gdbserver
[x86_64] Gdbsetup       : libs/x86_64/gdb.setup
[mips64] Gdbserver      : [mips64el-linux-android-4.9] libs/mips64/gdbserver
[mips64] Gdbsetup       : libs/mips64/gdb.setup
[armeabi-v7a] Gdbserver      : [arm-linux-androideabi-4.8] libs/armeabi-v7a/gdbserver
[armeabi-v7a] Gdbsetup       : libs/armeabi-v7a/gdb.setup
[armeabi] Gdbserver      : [arm-linux-androideabi-4.8] libs/armeabi/gdbserver
[armeabi] Gdbsetup       : libs/armeabi/gdb.setup
[x86] Gdbserver      : [x86-4.8] libs/x86/gdbserver
[x86] Gdbsetup       : libs/x86/gdb.setup
[mips] Gdbserver      : [mipsel-linux-android-4.8] libs/mips/gdbserver
[mips] Gdbsetup       : libs/mips/gdb.setup
[arm64-v8a] Compile        : hello-jni <= hello-jni.c
[arm64-v8a] SharedLibrary  : libhello-jni.so
[arm64-v8a] Install        : libhello-jni.so => libs/arm64-v8a/libhello-jni.so
[x86_64] Compile        : hello-jni <= hello-jni.c
[x86_64] SharedLibrary  : libhello-jni.so
[x86_64] Install        : libhello-jni.so => libs/x86_64/libhello-jni.so
[mips64] Compile        : hello-jni <= hello-jni.c
[mips64] SharedLibrary  : libhello-jni.so
[mips64] Install        : libhello-jni.so => libs/mips64/libhello-jni.so
[armeabi-v7a] Compile thumb  : hello-jni <= hello-jni.c
[armeabi-v7a] SharedLibrary  : libhello-jni.so
[armeabi-v7a] Install        : libhello-jni.so => libs/armeabi-v7a/libhello-jni.so
[armeabi] Compile thumb  : hello-jni <= hello-jni.c
[armeabi] SharedLibrary  : libhello-jni.so
[armeabi] Install        : libhello-jni.so => libs/armeabi/libhello-jni.so
[x86] Compile        : hello-jni <= hello-jni.c
[x86] SharedLibrary  : libhello-jni.so
[x86] Install        : libhello-jni.so => libs/x86/libhello-jni.so
[mips] Compile        : hello-jni <= hello-jni.c
[mips] SharedLibrary  : libhello-jni.so
[mips] Install        : libhello-jni.so => libs/mips/libhello-jni.so

JNI / Android.mk:

jni/Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hello-jni
LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

JNI / HELLO-jni.c:

jni/hello-jni.c:

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
#if defined(__arm__)
  #if defined(__ARM_ARCH_7A__)
    #if defined(__ARM_NEON__)
      #if defined(__ARM_PCS_VFP)
        #define ABI "armeabi-v7a/NEON (hard-float)"
      #else
        #define ABI "armeabi-v7a/NEON"
      #endif
    #else
      #if defined(__ARM_PCS_VFP)
        #define ABI "armeabi-v7a (hard-float)"
      #else
        #define ABI "armeabi-v7a"
      #endif
    #endif
  #else
   #define ABI "armeabi"
  #endif
#elif defined(__i386__)
   #define ABI "x86"
#elif defined(__x86_64__)
   #define ABI "x86_64"
#elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */
   #define ABI "mips64"
#elif defined(__mips__)
   #define ABI "mips"
#elif defined(__aarch64__)
   #define ABI "arm64-v8a"
#else
   #define ABI "unknown"
#endif

    return (*env)->NewStringUTF(env, "Hello from JNI !  Compiled with ABI " ABI ".");
}

com.example.hellojni.HelloJni:

com.example.hellojni.HelloJni:

public class HelloJni extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        /* Create a TextView and set its content.
         * the text is retrieved by calling a native
         * function.
         */
        TextView  tv = new TextView(this);
        tv.setText( stringFromJNI() );
        setContentView(tv);
    }

    /* A native method that is implemented by the
     * 'hello-jni' native library, which is packaged
     * with this application.
     */
    public native String  stringFromJNI();

    /* This is another native method declaration that is *not*
     * implemented by 'hello-jni'. This is simply to show that
     * you can declare as many native methods in your Java code
     * as you want, their implementation is searched in the
     * currently loaded native libraries only the first time
     * you call them.
     *
     * Trying to call this function will result in a
     * java.lang.UnsatisfiedLinkError exception !
     */
    public native String  unimplementedStringFromJNI();

    /* this is used to load the 'hello-jni' library on application
     * startup. The library has already been unpacked into
     * /data/data/com.example.hellojni/lib/libhello-jni.so at
     * installation time by the package manager.
     */
    static {
        System.loadLibrary("hello-jni");
    }
}

错误:

11-13 22:38:40.227  19386-19386/com.example.hellojni E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.example.hellojni, PID: 19386
    java.lang.UnsatisfiedLinkError: Couldn't load hello-jni from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.hellojni-7.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.hellojni-7, /vendor/lib, /system/lib]]]: findLibrary returned null
            at java.lang.Runtime.loadLibrary(Runtime.java:358)
            at java.lang.System.loadLibrary(System.java:526)
            at com.example.hellojni.HelloJni.<clinit>(HelloJni.java:64)
            at java.lang.Class.newInstanceImpl(Native Method)
            at java.lang.Class.newInstance(Class.java:1208)
            at android.app.Instrumentation.newActivity(Instrumentation.java:1067)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2399)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2599)
            at android.app.ActivityThread.access$900(ActivityThread.java:174)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1321)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:146)
            at android.app.ActivityThread.main(ActivityThread.java:5748)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
            at dalvik.system.NativeStart.main(Native Method)

请,如果您有任何想法是什么原因造成这一点,帮助我。我已经浪费了这个已经是整个工作一天,我即将跳出窗口(以电脑与我)。

Please, if you have any idea what is causing this, help me. I've wasted a whole work day on this already and am about to jump out the window (taking the computer with me).

推荐答案

这是因为Android的工作室忽略你的Andr​​oid.mk和生成即时自己一个人,从剧本的gradle采取设置。所以,你应该不是在指定的gradle脚本正确的设置(由于Android Studio中不完全支持NDK只能在简单的情况下),或者完全禁用的Andr​​oid Studio的有限NDK支持和直接调用的gradle NDK的构建。

This is because Android Studio ignore your Android.mk and generate own one on-the-fly, taking settings from gradle script. So you should either specify correct settings in gradle script (which works only in simplest cases due to incomplete NDK support in Android Studio), or completely disable Android Studio's limited NDK support and call ndk-build directly from gradle.

要在指定的gradle脚本NDK相关的设置,添加以下部分:

To specify NDK-related settings in gradle script, add the following section:

defaultConfig {
    ...
    ndk {
        moduleName "my-module-name"
        cFlags "-std=c++11 -fexceptions"
        ldLibs "log"
        stl "gnustl_shared"
        abiFilter "armeabi-v7a"
    }
}

还有设置项目特定值。随后的And​​r​​oid Studio的插件的gradle将这些设置生效,并自动生成Android.mk使用这些设置上的动态。

And set your project specific values there. Android Studio's gradle plugin then will take those settings into account and auto-generate Android.mk on-the-fly with these settings.

请注意,然而,唯一可用的NDK选项是上面列出的那些。如果你有更复杂的NDK的设置(例如,几个NDK模块,这取决于每个其他,或者你想使用prebuilt库,或任何其他),你应该完全禁用的Andr​​oid Studio的有限NDK支持和直接调用NDK的构建从gradle这个。要做到这一点,首先禁用自动生成Android.mk的:

Note, however, that the only available NDK options are those listed above. If you have more complicated NDK setup (for example, several NDK modules, depending each on other, or you want use prebuilt libraries, or whatever else), you should completely disable Android Studio's limited NDK support and call ndk-build directly from gradle. To do that, first disable auto-generation of Android.mk:

android {
    .....
    // disable automatic ndk-build call, which ignore our Android.mk
    sourceSets.main.jni.srcDirs = []
}

然后加上下面几行:

Then add the following lines:

android {
    .....
    sourceSets.main.jniLibs.srcDir 'src/main/libs'

    // call regular ndk-build(.cmd) script from app directory
    task ndkBuild(type: Exec) {
        workingDir file('src/main')
        commandLine getNdkBuildCmd()
    }

    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }

    task cleanNative(type: Exec) {
        workingDir file('src/main')
        commandLine getNdkBuildCmd(), 'clean'
    }

    clean.dependsOn cleanNative
}

最后,添加辅助函数gradle这个脚本的末尾:

Finally, add helper functions to the end of gradle script:

def getNdkDir() {
    if (System.env.ANDROID_NDK_ROOT != null)
        return System.env.ANDROID_NDK_ROOT

    Properties properties = new Properties()
    properties.load(project.rootProject.file('local.properties').newDataInputStream())
    def ndkdir = properties.getProperty('ndk.dir', null)
    if (ndkdir == null)
        throw new GradleException("NDK location not found. Define location with ndk.dir in the local.properties file or with an ANDROID_NDK_ROOT environment variable.")

    return ndkdir
}

def getNdkBuildCmd() {
    def ndkbuild = getNdkDir() + "/ndk-build"
    if (Os.isFamily(Os.FAMILY_WINDOWS))
        ndkbuild += ".cmd"

    return ndkbuild
}

啊,不要忘了进口添加到脚本的gradle的开头:

Ah, and don't forget to add "import" to the beginning of the gradle script:

import org.apache.tools.ant.taskdefs.condition.Os

这里我描述它更详细。

这篇关于Android的NDK java.lang.UnsatisfiedLinkError中样品HELLO-JNI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆