Android NDK开发

安稳与你 提交于 2020-02-05 02:48:45

Android NDK 开发教程(极客学院)

 

一、Android NDK环境搭建

      使用最新ndk,直接抛弃cygwin,以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin(模拟Linux环境用的),下载CDT(Eclipse C/C++开发插件),还要配置编译器,环境变量,特别麻烦,新版就不需要了。

方法/步骤

  1. Android官网下载Android的开发工具ADT(Android Development Tool的缩写),该工具集成了最新的ADT和NDK插件以及Eclipse,还有一个最新版本SDK,解压之后就可以用了。
  2. ADT插件:管理Android SDK和相关的开发工具的

     ;

    NDK插件:用于开发Android NDK的插件,ADT版本在20以上,就能安装NDK插件,另外NDK集成了CDT插件 。下载链接见:http://developer.android.com/sdk/index.html
  3. Android官网下载最新的NDK,注:NDK版本在r7以上之后就集成了Cygwin,而且还是十分精简版。

     

    下载链接见:http://developer.android.com/tools/sdk/ndk/index.html

eclipse配置

解压ndk并配置环境变量:添加系统环境变量NDK_ROOT为: D:\Android\android-ndk-r10d。

  1. 打开Eclipse,点Window->Preferences->Android->NDK,设置NDK路径,例如Shamoo的是E:\android-ndk-r9c

     

    (如果没有ndk选项,则可能是因为没有ndk插件,自行下载一个放入\eclipse\plugins\下重启即可)

     
     
     
     
  2. 新建一个Android工程,在工程上右键点击Android Tools->Add Native Support...,然后给我们的.so文件取个名字,例如:my-ndk

     
    这时候工程就会多一个jni的文件夹,jni下有Android.mk和my-ndk.cpp文件。Android.mk是NDK工程的Makefile,my-ndk.cpp就是NDK的源文件。
     
  3. 接下来仿着NDK的demo,Hello-JNI工程写一下。使用Alt + '/'可以代码提示!很爽!有木有?

     

     

  4. JNI接口的命名规范是:Java_ + 调用该方法的包名(包名的点用_代替) + _ + 调用该接口的类名 + _ + 方法名,对于实例方法,有两个参数是必要的,一个JNI的环境指针JNIEnv *

     
     
     
  5. 完成了,然后运行。运行之前先编译NDK,然后在编译JAVA代码。

 

 

二、开发中遇到的问题

问题一、编译也许会遇到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) 

[java] view plaincopy
 
  1. extern "C" {
    JNIEXPORT jstring JNICALL ava_com_wytiger_jnidemo_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz);
    }; 

  2.   
  3. JNIEXPORT jstring JNICALL ava_com_wytiger_jnidemo_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz )  
  4. {  
  5.     return env->NewStringUTF("Hello from JNI bear c++");  
  6. }  

原因是: 

        被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

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!