JNI学习之一:怪异的JNI报错:Caused by: java.lang.UnsatisfiedLinkError

最近开始研究Android NDK了,参照教程一步一步写:

(吐个槽:貌似AndroidStudio还不能用来做JNI,于是只好又回到我的eclipse平台上来,谷歌的工程师么,你们倒是赶紧的给studio加上这个功能啊)

1、新建一个工程NDKHelloWorld

2、新建一个folder,名称jni,在其中新建一个c代码文件,Hello.c。

3、Hello.c的内容:

#include <stdio.h>
#include <jni.h>

jstring Java_sungoku_ndkhelloworld_DemoActivity_helloFromJni(JNIEnv* env, jobject obj) {

	return (*(*env)).NewStringUTF(env, "hello world, jni.");
}

就是大家都喜闻乐见的helloworld。。。注意那个奇怪无比的函数名,开头必须是Java,然后是程序的包名,然后是调用函数的那个Activity名,最后是函数真正的名字。

4、添加Android.mk文件,内容如下:

   LOCAL_PATH := $(call my-dir)

   include $(CLEAR_VARS)

   LOCAL_MODULE    := Hello
   LOCAL_SRC_FILES := Hello.c

   include $(BUILD_SHARED_LIBRARY)

这里指定模块名称是Hello,要编译的源文件是Hello.c,注意大小写。

5、好了,赶紧用ndk-build命令交叉编译一下,嗯,还好,编译通过,比较顺利啊。这时,工程目录下的libs目录里面应该出现armeabi目录,可以看到我们的JNI模块已经被编译成了libHello.so,是个二进制文件。这个模块的文件名字就是根据mk中指定的模块名,加上lib前缀和.so扩展名组成的。

6、接下来,回到Android的Java代码部分,在DemoActivity中加入静态代码块,加载刚刚编译好的本地库,并且声明一下本地方法,注意方法名称的一致。

	static{//libHello.so
		System.loadLibrary("Hello");
	}
	
	public native String helloFromJni();

7、添加一个Button,让应用点击这个按钮就调用本地方法,显示一个Toast:

Toast.makeText(this, helloFromJni(), Toast.LENGTH_LONG).show();
好了,该部署测试一下了。嗯???模拟器运行应用报错了。

10-06 01:48:38.507: ERROR/AndroidRuntime(1442): Caused by: java.lang.UnsatisfiedLinkError: Couldn't load Hello: findLibrary returned null
神马情况?仔细检查了一下,木有问题啊。于是我想到导入NDK的示例代码试试。导入那个hellojni的示例代码。run as android application,神奇的事情发生了,编译就报错了。
[2014-10-06 10:19:57 - Dex Loader] Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
[2014-10-06 10:19:57 - HelloJni] Conversion to Dalvik format failed: Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.

我心里千万只草泥马奔腾而过。。。

这个意思似乎是说eclipse出错,缓冲区溢出?经过折腾以及百度之后,好吧,导入的工程出这个问题,从build path中去掉AndroidDependences就好了。不过我自己实验发现在工程属性中把buildTarget改成4.4也行。

然后,再次编译,运行。呃!!!还是出错!!!

和我之前自己一步一步写的工程一样的错误,加载本地库时找不到本地库。我看了看hellojni工程目录,发现了问题,没有生成那个libs/armeabi目录,也就是说没有对本地代码部分编译。难道Eclipse的build project不能自动编译工程的JNI代码?那我就手动吧,ndk-build一下。

然后,我再颤抖着点下运行,你能相信我看到模拟器运行出错,还是提示找不到本地库的时候,我的心情吗?大概相当于被无限的草泥马踩踏至死的感觉吧。

为毛?!?!没有那里出问题,怎么就是不行?

好吧,我去问问度娘。度娘的回答基本上属于就是名称写错啊,编译不对啊等等之类的,后来记不清在哪里看到一个提问者提描述问题时提到自己的模拟器用的x86镜像,我顿时心中闪过一道闪电啊,万千草泥马都被这道闪电劈死了有木有。

是啊,为了让模拟器运行快一点,我一直以来都是用的x86镜像,加上intel的HAX加速。而现在我用ndk-build出来的本地库是基于arm平台的运行库啊,我应该切换到armeabi镜像的模拟器运行才是。

想到就赶紧尝试。

这回终于都好了。忍不住狂笑一声,记录下来这个过程吧,希望能让同我一样遭遇的哥们有个提示就好。


=========================================================补充内容的分割线==================================================
如果就想编译出x86架构的运行库怎么办呢?两个方法:

1、编写application.mk文件,在其中的APP_ABI 行加入 x86这个选项。

例如:APP_ABI := armeabi armeabi-v7a x86   这里是可以添加好几个选项的,如果不添加这个APP_ABI选项,默认编译的是armeabi平台。
2、如果只是简单的程序,那么也可以不用编写完整的application.mk文件,在使用ndk-build命令的时候加入这个参数:
> ndk-build   APP_ABI="armeabi armeabi-v7a x86"
然后同样会编译生成3中平台的本地库。
=========================================================补充内容的结束线==================================================

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
`java.lang.UnsatisfiedLinkError`是一个Java运行时异常,通常表示在加载本地库(Native Library)时出现问题。 Java程序可以使用Java Native Interface(JNI)来与本地代码进行交互。当Java程序调用本地库时,会尝试加载与该库关联的本地代码。如果在加载过程中发生错误,就会抛出`java.lang.UnsatisfiedLinkError`异常。 这个异常通常有以下几种可能的原因: 1. 本地库文件(通常是`.dll`或`.so`文件)无法找到或加载。在加载本地库时,Java虚拟机会搜索指定的路径,如`java.library.path`系统属性或通过`System.loadLibrary()`方法指定的路径。如果找不到或无法加载本地库文件,就会抛出该异常。 2. 本地库文件与Java程序之间的兼容性问题。本地库可能依赖于特定的操作系统、硬件架构或其他环境参数。如果本地库与当前运行的Java程序不兼容,也会导致该异常。 3. 本地库文件损坏或版本不匹配。如果本地库文件被破坏或其版本与Java程序不匹配,也可能导致该异常。 要解决这个问题,你可以尝试以下几个步骤: 1. 确保本地库文件存在并位于正确的位置。检查文件路径和名称是否正确,并确保文件可访问。 2. 检查本地库文件的兼容性。确保本地库与Java程序的操作系统、硬件架构等参数兼容。 3. 检查本地库文件的完整性和版本。如果文件损坏或版本不匹配,尝试重新下载或更新本地库文件。 4. 检查Java虚拟机的配置。确保`java.library.path`系统属性配置正确,并且指定的路径包含本地库文件。 如果仍然无法解决问题,可能需要进一步调查具体的错误信息和上下文,以确定导致`java.lang.UnsatisfiedLinkError`异常的确切原因。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值