Android NDK 开发教程(极客学院)
一、Android NDK环境搭建
使用最新ndk,直接抛弃cygwin,以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin(模拟Linux环境用的),下载CDT(Eclipse C/C++开发插件),还要配置编译器,环境变量,特别麻烦,新版就不需要了。
方法/步骤
- Android官网下载最新的NDK,注:NDK版本在r7以上之后就集成了Cygwin,而且还是十分精简版。
二、开发中遇到的问题
问题一、编译也许会遇到Unable to launch cygpath. Is Cygwin on the path?错误,解决办法如下:
1.工程右键,点Properties->C/C++ Build的Building Settings中去掉Use default build command,然后输入${NDKROOT}/ndk-build.cmd
(注意:这里是正斜杠/)
2.在C/C++ Build中点击Environment,点Add...添加环境变量NDKROOT,值为NDK的根目录.(注意:这里是反斜杠)
3.再编译,问题就解决啦!
问题二、使用c++来编写本地库,会有一些兼容问题。
(1)直接黏贴HelloJni的stringFromJNI函数过来测试,提示Method 'NewStringUTF' could not be resolved
解决方法:将(*env)->NewStringUTF(env, "Hello from JNI !")改为return env->NewStringUTF("Hello from JNI !")即可
原因是:NDK plugin默认为我们生成的是cpp文件,而C与C++调用函数的参数不一致,因此找不到函数,具体参考jni.h中的定义。cpp文件中形如(*env)->Method(env, XXX)改成env->Method(XXX)即可。
(2)运行c++生成的.so库,若报以下错误:(既找不到函数)
No implementation found for native Lcom/dgut/android/MainActivity;.stringFromJNI ()Ljava/lang/String;
java.lang.UnsatisfiedLinkError: stringFromJNI
at com.dgut.android.MainActivity.stringFromJNI(Native Method)
解决方法:
为供Java调用的c++函数前加入extern "C" 修饰,如:(NDK example里面的cpp文件也是这么声明的,参考hello-gl2)
-
extern "C" {
JNIEXPORT jstring JNICALL ava_com_wytiger_jnidemo_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz);
}; - JNIEXPORT jstring JNICALL ava_com_wytiger_jnidemo_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调用将可能找不到该函数。
问题三、Android NDK: WARNING: APP_PLATFORM android-14 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml (这个是NDK工具的一个BUG,若build Target大于minSdkVersion,则会报这个错误,导致无法运行)
解决方法:在Application.mk文件中添加APP_PLATFORM := android-8
问题四、Type 'jint' could not be resolved, and JNIEnv, jclass
Project Properties -> C/C++ General -> Path and Symbols,选择include标签,Add -> $Android_NDK_HOME/platforms/android-14/arch-arm/usr/include
选中All languages. 最后Apply -> OK