windows下android NDK 环境配置
0、下载jdk并配置环境变量
下载最新jdk,百度搜索“jdk”就有了。安装完成后,配置环境变量(网上一搜,一堆,我这里仅作简要叙述)
- 计算机→属性→高级系统设置→高级→环境变量。
- 系统变量→新建 JAVA_HOME 变量 。变量值填写jdk的安装目录(本人是 D:\Program Files\Java\jdk1.7.0_45)
-
系统变量→新建 CLASSPATH 变量
变量值填写 .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar(注意最前面有一点)
-
系统变量→寻找 Path 变量→编辑
在变量值最后输入 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
(注意原来Path的变量值末尾有没有;号,如果没有,先输入;号再输入上面的代码)
系统变量配置完毕
1、官网下载最新的ADT。 解压即可(eclipse最好自带ndk插件)
2、官网下载最新的NDK。解压即可(ndkr7以上有自带cygwin)
3、eclipse没有自带插件,则下载插件。
插件网上有,我作为自己学习,也在百度云共享了一份,下载地址:http://pan.baidu.com/s/1i3xImQp
下载好插件放到eclipse下的plugins文件夹下。重启eclipse。
4、重点开始
eclipse→window→preferences→Android→NDK
配置刚刚下载的ndk的路径
5、新建android 项目
右击→properties→C/C++ Build 。去掉默认的build command
设置成${NDKROOT}/ndk-build.cmd
再到build Variables 点击add。配置如图.name:NDKROOT value:你的ndk路径。点击确定。
6、项目右键->Android Tools->Add Native Support...,输入.so库名字后点击Finish
7、现在已经可以Build我们的Jni项目了,选择项目,Project->Build Project,编译我们的c/c++代码,此时项目结构如下,NDK plugin已经为我们添加好了include,已经为我们生成了相应的Android.mk以及 cpp文件。(注意:这里插件为我们生成的是cpp文件,若你不喜欢可以改回.c,并在mk文件中进行相应更改)
8、可以运行我们的Jni项目了。
遇到的问题
1、运行c++生成的.so库,若报以下错误:(既找不到函数)
No implementation found for native Lcom/example/hellojni/MainActivity;.stringFromJNI ()Ljava/lang/String;
java.lang.UnsatisfiedLinkError: stringFromJNI
at com.example.hellojni.MainActivity.stringFromJNI(Native Method)
解决方法:
为供Java调用的c++函数前加入extern "C" 修饰,如:(NDK example里面的cpp文件也是这么声明的,参考hello-gl2)
- extern "C" {
- JNIEXPORT jstring JNICALL Java_com_dgut_android_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz );
- }
- JNIEXPORT jstring JNICALL Java_com_dgut_android_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz )
- {
- return env->NewStringUTF("Hello from JNI bear c++");
- }
原因是:
被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。
首先看看C++中对类似C的函数是怎样编译的:作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:void foo( int x, int y );该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数voidfoo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。
同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。
因此,若我们没有使用extern "C"修饰函数,按照C语言方式编译和连接,Jni调用将可能找不到该函数。