android SDK使用cygwin编译.so文件

来源:互联网 发布:梦幻古龙数据库 编辑:程序博客网 时间:2024/05/04 05:21

最近要使用JNI调用一个C库,所以就趁这个时候学习一下JNI在android中怎样使用。

一配置环境:

1、下载安装cygwin(cygwin的下载文件太大了将近6G,安装后的安装文件达到了将近20G),具体的下载安装步骤我记不贴出来了,比较简单。

2、测试cygwin,输入make -v,gcc -v,看是否正常运行。

3、配置cygwin。找到cygwin的安装路径下的 .bash_profile文件,我的路径是:C:\cygwin64\home\ASUS,使用记事本打开这个文件,然后

在文件的末尾加上这两段代码:(注意其中ANDK这个名字可以自己随便取,但是两行代码的ANDK必须相同)

ANDK=/cygdrive/e/doMyself/android-ndk-r6b-windows/android-ndk-r6b
export ANDK

这样cygwin便配置完成了,这一步的主要问题是cygwin实在是太难下载了,其他的都很简单。

二编写android工程以及C++代码

 

1、新建一个android工程,编写好native方法:

public class JNIMethod {public JNIMethod(){load();}private void load() {try {System.loadLibrary("MyJNIProject");} catch (Throwable e) {e.printStackTrace();}}private static JNIMethod jniMethod;public static JNIMethod Instance(){if(jniMethod == null)jniMethod = new JNIMethod();return jniMethod;}public native double power(double x,int n);public native int calculate(int x, int y);}

其实只要编写好native方法就行,其他的逻辑可以以后再加上。

2、使用javah工具将native方法编译生成.h头文件,步骤如下:

一、使用cmd进入到你所在的android项目bin目录下的classes文件夹下,然后执行命令:javah -jni [包名].[native方法所在的类名],如我根据我的包名

使用的就是这样的命令:javah -jni com.lonuery.jni.JNIMethod。生成了文件:com_lonuery_jni_JNIMethod.h,打开这个文件可以看见其代码如下:

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_lonuery_jni_JNIMethod */#ifndef _Included_com_lonuery_jni_JNIMethod#define _Included_com_lonuery_jni_JNIMethod#ifdef __cplusplusextern "C" {#endif/* * Class:     com_lonuery_jni_JNIMethod * Method:    power * Signature: (DI)D */JNIEXPORT jdouble JNICALL Java_com_lonuery_jni_JNIMethod_power  (JNIEnv *, jobject, jdouble, jint);/* * Class:     com_lonuery_jni_JNIMethod * Method:    calculate * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_lonuery_jni_JNIMethod_calculate  (JNIEnv *, jobject, jint, jint);#ifdef __cplusplus}#endif#endif


3、根据头文件编写.cpp文件,其实也可以先编写.cpp文件,然后根据头文件将.cpp文件的函数名称改变即可。我就是想编写好了.cpp文件,然后

对其进行的修改而已。编写好的.cpp文件代码如下:

#include <jni.h>#include <stdio.h>#include <stdlib.h>#include "com_lonuery_jni_JNIMethod.h"extern "C" {JNIEXPORT jdouble Java_com_lonuery_jni_JNIMethod_power(JNIEnv *env ,jobject thiz ,jdouble x ,jint n){double val = 1.0;while(n--){val*=x;}return val;}JNIEXPORT jint Java_com_lonuery_jni_JNIMethod_calculate(JNIEnv *env ,jobject thiz ,jint x,jint y){if(x>y){return x;}else{int result = x + y ;return result;}}}

这里要注意几点:

1.在头文件中只有参数类型而无参数,所以要自己手动加上参数名,如:x,n等等。

2.你会发现我的native方法只有两个参数,但是.h头文件却有4个参数了,这里前面两个参数是无用的(到底有什么作用以及怎么生成的我也不知道),

你只需要关心你native方法中定义的两个参数即可。所以在写.cpp文件时有一个简单的办法就是:将.h头文件的函数名称复制过来,然后手动加上

形参名称即可。

3.如果你使用的是C++语言写的,在.cpp文件中要使用extern "C"{.....}将C++代码括起来,具体如上面的代码所示。这样做是因为在所生成的二进制

文件中,c和C++的符号不同所造成的,JNI是按照c的规则去找函数,所以要加上extern c,让编译器按照C的规则去编译函数,这样JNI才能够被调

用。

 

4、在android工程项目的根目录下新建一个jni文件,将.h以及.cpp文件导入到这个文件夹下。

5、编写Android.mk文件内容如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := MyJNIProjectLOCAL_SRC_FILES := JniProject.cppinclude $(BUILD_SHARED_LIBRARY)

第一行代码:定位源文件的位置,必须处于最开始,他的作用是返回当前目录的路径。

第二行代码:清除一些变量的值,但是LOCAL_PATH除外。

第三行代码:用来指定当前待编译模块的名称,如这次我要编译的模块为即为我所创建的工程MyJNIProject

第四行代码:用来指定参与编译的源代码文件,这里我要编译即为之前编写的JniProject.cpp文件。

第五行代码:用来指示将当前模块编译为共享库,前缀为lib,后缀为.so。

6、编写Application.mk文件,其作用是描述在你应用中所需要的模块(动态库或者静态库),内容如下:

APP_PROJECT_PATH := $(call my-dir)/..APP_MODULE := MyJNIProjectAPP_ABI := armeabi

具体的编写规则以及每行代码的含义,请看下面这篇博客:Application.mk语法点点 

7、将编写好的Android.mk以及Application.mk文件放入之前所创建的jni文件夹中。

8、使用cygwin编译生成.so文件:

一、进入你所创建项目的根目录:cd /cygdrive/e/MyEclipse/MyJNIProject,记住:在cd命令前必须要加上cygdrive才能够进入,上面的命令必须一次性

输入。

二、输入命令:ANDK/ndk-build,这个ANDK就是之前.bash_profile配置文件中所设置的名称。

效果图如下:

编译好了之后,将会在项目的根目录下多出一个obj文件夹,在lib文件夹下会多出一个armeabi文件夹。

好了现在对native方法进行调用:

public class MainActivity extends Activity implements OnClickListener{TextView tv;Button btn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView)findViewById(R.id.tv);btn = (Button)findViewById(R.id.btn);btn.setOnClickListener(this);}@Overridepublic void onClick(View arg0) {int result = JNIMethod.Instance().calculate(5, 2);double power = JNIMethod.Instance().power(6, 3);tv.setText("result:"+result+" power:"+power);}}

效果如下:

至此android NDK调用C++源文件就介绍完成了。

0 0