Android使用最新版本NDK开发步骤与环境配置

来源:互联网 发布:嵌入式软件面试题 编辑:程序博客网 时间:2024/05/22 09:46

       前言:Android NDK r7及以上的版本已经集成了Cygwin编译环境,即我们完全可以抛弃庞大的Cygwin了。


       Android NDK r6及以下版本,也可以抛弃几个G的完整版Cygwin,使用精简过的Mini-Cygwin来编译,解压后大小仅9M,但短小巧精悍,完全可以满足Android NDK的开发。


     下载地址:https://code.google.com/p/mini-cygwin/

      Eclipse集成Cygwin编译环境可以参考我的这篇贴:http://blog.csdn.net/codezjx/article/details/8858825



     下面进入正题,r7及以上版本,跟着下面的步骤完成环境配置的升级吧!!!

     参考官网:http://tools.android.com/recent/usingthendkplugin

    1、现在做Android开发的朋友们有许多在都在使用的Android studio这个google 开发的新工具,之前还不能集成NDK来开发,使用Android studio 的可以看这篇文章如何进行环境配置的:文章地址:http://www.dbmng.com/Article_1512.html



    2、使用Eclipse 开发的朋友,可以下载ADT Bundle, ADT Bundle包含了Eclipse、ADT插件和SDK Tools,是已经集成好的IDE,只需安装好Jdk即可开始开发,但是google的andorid官网已经不提供的它的下载了,只提供了AndroidStudio的下载,本文在此提供一个国内网站共大家的来下载(这个网站提供很多工具下载):http://www.androiddevtools.cn/



     3、下载NDK工具(也在这个网站):http://www.androiddevtools.cn/,我使用的是最新的android-ndk-r10e-windows-x86.exe,下载完后点击解压缩。

    4、Eclipse -> Window -> Preferences -> Android -> NDK,设置NDK为刚刚解压缩的工具包路径。

    注意:做到这里时,控制台报出了一个错误:“Unable to launch cygpath. Is Cygwin on the path”,因为ndk r7之前编译采用的是Cygwin模拟出linux 环境,使用ndk-build命令,而ndk r7之后集成了编译环境,能够在windows环境下就可以编译了,使用的命令试是ndk-build.cmd。解决如文章后面的(问题四)所写的方法:

               


    5、NDK环境基本上已经搭建好,新建一个普通Android项目测试NDK支持。项目右键->Android Tools->Add Native Support...,输入.so库名字(如 hello )后点击Finish ;(注意:若项目已经是一个Jni项目,例如NDK example里面的HelloJni,这一步中.so库名字不用填)

                                 

                      




     6、现在已经可以Build我们的Jni项目了,选择项目,Project->Build Project,编译我们的c/c++代码,此时项目结构如下,NDK plugin已经为我们添加好了include,已经为我们生成了相应的Android.mk以及 cpp文件。(注意:这里插件为我们生成的是cpp文件,若你不喜欢可以改回.c,并在mk文件中进行相应更改,c与c++在实现native 方法的语法上有一些区别)


                   




    7、这时,Android NDK环境已经完美搭建好,我们可以在cpp文件中流畅地书写我们的c/c++代码。

(而且当你Alt+/时,已经可以使用自动提示,各种爽歪歪有木有。若你不是用NDK plugin来构建JNI项目,而是选择手动方式,Alt+/是不会提示的)


                  




     8、关于编译,默认情况下:选择项目,Project->Build Project,来重新编译我们的代码。而且每次run项目的时候,也会自动编译.so库,第一次的所有的c或者cpp文件都需要编译,当文件很多时,第一次编译很慢,之后NDK编译器就只会编译你修改过的C或者Cpp的文件了,速度就很快了。


                                




      一些问题与解决方法:

      问题一:Android NDK: WARNING: APP_PLATFORM android-14 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml (这个是NDK工具的一个BUG,若build Target大于minSdkVersion,则会报这个警告,不影响编译)

排除警告的解决方法:android-ndk-r10e/build/core/add-application.mk(使用Notepad++打开)第93行把__ndk_warning改为__ndk_info;然后重新build一次项目即可消除错误。原文:this problem may be safely fixed by changing this line in add-application.mk from __ndk_warning to __ndk_info链接:https://code.google.com/p/android/issues/detail?id=39752(本人修改之后还是有这个警告 ) :



     问题二:使用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)

[java] view plaincopy

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++");
}

     原因是1:

      被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调用将可能找不到该函数。

     原因是2:

      可能是在so动态库没有加载,在代码中忘记在静态块调用加载了。


     问题三、在C 文件中出现这种带有下黄色下划线的提示 Unresolved inclusion: <jni.h>  ,这让看起来很不爽,一大推波浪线

       原因是:所需要的头文件声明没有加载到配置到环境变量。(但不影响的程序的编译和运行)  

    解决方法:

     .设置C/C++路径,将NDkproject properties->c/c++ general->paths and Symbol->include->include directories,

     然后点击Add添加NDK安装包下所有包含include文件目录(可以根据实际开发的需要添加头文件)

     我只添加两个目录如下:

1. C:\NDK\android-ndk-r10e\platforms\android-19\arch-arm\usr\include

2.C:\NDK\android-ndk-r10e\toolchains\mips64el-linux-android-4.9\prebuilt\windows-x86_64\lib\gcc\mips64el-linux-android\4.9\include




     问题四、控制台报出了一个错误:“Unable to launch cygpath. Is Cygwin on the path”

    1. 鼠标右击项目-------》点击Properties-----》点击C/C++build 出现如下图所示添加修改

    build command 处添加:${NDKROOT}/ndk-build.cmd

       


     2.添加NDK的路径

    


         5关于使用在C或者C++  代码中使用LOG,可以在Eclipse 的控制台中向Android log一样输出的的配置


          1.引入头文件 #include <android/log.h>

               2. 添加LOG 的宏定义

.                /**
                 *
                *      在调试环境下,LOG宏是一个变参输出宏,以自定义的格式输出;
               *       在发布环境下,LOG宏是一个空宏,不做任何事情。
               *       LOGD(...)的...表示可变参数
               */
 
             #ifdef DEBUG
             #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
             #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
             #else
             #define LOGI(...)//定义一个空宏
             #endif/**

             3.在Android.mk文件中添加  LOCAL_LDLIBS += -llog




最后另一篇博客关于NDK配置: http://blog.csdn.net/wangjianzhongfj/article/details/39139497







0 0