JNI开发方案一 : cgwin+ndk



首先来看一下什么是NDK

NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将sojava应用一起打包成apk。这些工具对开发者的帮助是巨大的。
NDK
集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出哪些文件需要编译编译特性要求等),就可以创建出soNDK可以自动地将soJava应用一起打包,极大地减轻了开发人员的打包工作。比较简单的说,NDK是一套交叉编译工具,它可以帮你把你用CC++书写的代码,编译为.so(类似与win下的.dll)格式的文件,使你可以在你的Android程序当中用Java语言(JNI)调用这些代码

 

下面来看一下具体的操作步骤

 

第一步:搭建NDK环境

 

下载Android NDK。下载地址:http://developer.android.com/tools/sdk/ndk/index.html

下载放到指定的目录下,解压即可,这一步很简单的

 

 

第二步:下载安装cygwin

 

由于NDK编译代码时必须要用到makegcc,所以你必须先搭建一个linux环境,cygwin是一个在windows平台上运行的unix模拟环境,它对于学习unix/linux操作环境,或者从unixwindows的应用程序移植,非常有用。通过它,你就可以在不安装linux的情况下使用NDK来编译CC++代码了。下面我们一步一步的安装cygwin吧。 

下载地址:http://cygwin.com/install.html

1、 然后双击运行吧,运行后你将看到安装向导界面:

2、 点击下一步,此时让你选择安装方式:
1
Install from Internet:直接从Internet上下载并立即安装(安装完成后,下载好的安装文件并不会被删除,而是仍然被保留,以便下次再安装)。
2
Download Without Installing:只是将安装文件下载到本地,但暂时不安装。
3
Install from Local Directory:不下载安装文件,直接从本地某个含有安装文件的目录进行安装。

3、选择第一项,然后点击下一步:

4、选择要安装的目录,注意,最好不要放到有中文和空格的目录里,似乎会造成安装出问题,其它选项不用变,之后点下一步:

5、上一步是选择安装cygwin的目录,这个是选择你下载的安装包所在的目录,默认是你运行setup.exe的目录,直接点下一步就可以:

6、此时你共有三种连接方式选择:
1) Direct Connection
:直接连接。
2) Use IE5 Settings
:使用IE的连接参数设置进行连接。
3) Use HTTP/FTP Proxy
:使用HTTPFTP代理服务器进行连接(需要输入服务器地址、端口号)。
根据自己的网络连接的实情情况进行选择,一般正常情况下,均选择第一种,也就是直接连接方式。然后再点击“下一步”,

7、 这是选择要下载的站点,选择后点下一步.

8、 此时会下载加载安装包列表

9Search是可以输入你要下载的包的名称,能够快速筛选出你要下载的包。那四个单选按钮是选择下边树的样式,默认就行,不用动。View默认是Category,建议改成full显示全部包再查,省的一些包被隐藏掉。左下角那个复选框是是否隐藏过期包,默认打钩,不用管它就行,下边开始下载我们要安装的包吧,为了避免全部下载,这里列出了后面开发NDK用得着的包:autoconf2.1automake1.10binutilsgcc-coregcc-g++gcc4-coregcc4-g++gdbpcrepcre-develgawkmake12个包

10、然后开始选择安装这些包吧,点skip,把它变成数字版本格式,要确保Bin项变成叉号,而Src项是源码,这个就没必要选了。

11、下面测试一下cygwin是不是已经安装好了。
运行cygwin,在弹出的命令行窗口输入:cygcheck-c cygwin命令,会打印出当前cygwin的版本和运行状态,如果statusok的话,则cygwin运行正常。
然后依次输入gcc --versiong++--versionmakeversiongdb version进行测试,如果都打印出版本信息和一些描述信息,非常高兴的告诉你,你的cygwin安装完成了.

 

第三步:配置NDK环境变量

 

1、首先找到cygwin的安装目录,找到一个home\<你的用户名>\.bash_profile文件,我的是:c:\cygwin\home\Administrator\.bash_profile

2、打开bash_profile文件,添加NDK=/cygdrive/<你的盘符>/<android ndk 目录> ,就是第一步中下载下来的NDK解压的目录我的目录是:

例如:
NDK=/cygdrive/e/android-ndk-r9c
export NDKRoot

(NDKRoot这个名字是随便取的,为了方面以后使用方便,选个简短的名字,然后保存)

(这里还要注意的是盘符是"/"而不是"\",因为cygwindLinux,不是windows)

3、打开cygwin,输入cd$NDK,如果输出上面配置的/cygdrive/e/android-ndk-r9c信息,则表明环境变量设置成功了。

 

 

第四步:用NDK来编译程序,测试功能是否可用

 

1、现在我们用安装好的NDK来编译一个简单的程序吧,我们选择ndk自带的例子hello-jni,我的位于E:\android-ndk-r9c\samples\hello-jni(根据你具体的安装位置而定).

2、运行cygwin,输入命令cd /cygdrive/e/android-ndk-r9c/samples/hello-jni,进入到E:\android-ndk-r9c\samples\hello-jni目录。

3、 输入$NDK/ndk-build,执行成功后,它会自动生成一个libs目录,把编译生成的.so文件放在里面。($NDK是调用我们之前配置好的环境变量,ndk-build是调用ndk的编译程序)

(早期NDK版本是make APP=hello-jni ,还要对应appsource2个目录的项目目录,现在改成了$NDK/ndk-build

 

 

第五步:开发一个简单的Android NDK例子

 

Eclipse中新建一个AndroidNDKDemo工程

其中JNI.java是定义的本地方法的类,代码如下:

[java]view plaincopyprint?在CODE上查看代码片派生到我的代码片

1.  package com.ndk.demo;  

2.  public class JNI {  

3.      //获取字符串  

4.      public native String getString();  

5.      //进行加法操作  

6.      public native int plus(int a,int b);  

7.  }  

package com.ndk.demo;

public class JNI {

  //获取字符串

  public native String getString();

  //进行加法操作

  public native int plus(int a,intb);

}

在来看一下AndroidNDKDemoActivity.java,主要是测试的Demo,代码如下:

[java]view plaincopyprint?在CODE上查看代码片派生到我的代码片

1.  package com.ndk.demo;  

2.    

3.  import android.app.Activity;  

4.  import android.os.Bundle;  

5.  import android.view.View;  

6.  import android.view.View.OnClickListener;  

7.  import android.widget.Button;  

8.  import android.widget.EditText;  

9.  import android.widget.Toast;  

10.   

11. import com.ndk.demo.R;  

12.   

13. public class AndroidNDKDemoActivity extends Activity {  

14.     //使用静态代码块加载类库  

15.     static{  

16.         System.loadLibrary("first_jni");//一定要注意名称没有“lib"  

17.     }  

18.     @Override  

19.     public void onCreate(Bundle savedInstanceState) {  

20.         super.onCreate(savedInstanceState);  

21.         setContentView(R.layout.main);  

22.         Button btn1 = (Button)findViewById(R.id.show_btn);  

23.         final EditText oneEdit = (EditText)findViewById(R.id.one_number);  

24.         final EditText twoEdit = (EditText)findViewById(R.id.two_number);  

25.         final Button btn2 = (Button)findViewById(R.id.calculate_btn);  

26.         //定义本地类  

27.         final JNI jni = new JNI();  

28.         btn1.setOnClickListener(new OnClickListener(){  

29.             public void onClick(View v) {  

30.                 //显示从C代码中返回的字符串  

31.                 Toast.makeText(getApplicationContext(), jni.getString(), 1500).show();  

32.             }});  

33.         btn2.setOnClickListener(new OnClickListener(){  

34.             public void onClick(View v) {  

35.                 //调用C代码中的加法操作  

36.                 String oneNumber = oneEdit.getText().toString();  

37.                 String twoNumber = twoEdit.getText().toString();  

38.                 int oneNumbers = Integer.valueOf(oneNumber);  

39.                 int twoNumbers = Integer.valueOf(twoNumber);  

40.                 btn2.setText(jni.plus(oneNumbers, twoNumbers)+"");  

41.             }});  

42.     }  

43. }  

package com.ndk.demo;

 

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.EditText;

import android.widget.Toast;

 

import com.ndk.demo.R;

 

public class AndroidNDKDemoActivity extends Activity {

  //使用静态代码块加载类库

   static{

      System.loadLibrary("first_jni");//一定要注意名称没有“lib"

   }

   @Override

   public void onCreate(BundlesavedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.main);

       Button btn1 =(Button)findViewById(R.id.show_btn);

       final EditText oneEdit =(EditText)findViewById(R.id.one_number);

       final EditText twoEdit =(EditText)findViewById(R.id.two_number);

       final Button btn2 =(Button)findViewById(R.id.calculate_btn);

       //定义本地类

       final JNI jni = new JNI();

       btn1.setOnClickListener(newOnClickListener(){

       public void onClick(View v) {

          //显示从C代码中返回的字符串

          Toast.makeText(getApplicationContext(),jni.getString(), 1500).show();

       }});

       btn2.setOnClickListener(newOnClickListener(){

       public void onClick(View v) {

          //调用C代码中的加法操作

            String oneNumber =oneEdit.getText().toString();

            String twoNumber =twoEdit.getText().toString();

            int oneNumbers = Integer.valueOf(oneNumber);

            int twoNumbers =Integer.valueOf(twoNumber);

          btn2.setText(jni.plus(oneNumbers,twoNumbers)+"");

       }});

   }

}

上面的工作搞定后,就生成c代码的头文件吧!具体操作,这里不再赘述,可以访问我的博客:

http://blog.csdn.net/jiangwei0910410003/article/details/17465085

同时使用VC6.0建一个NDKDemo.c代码,如下:

[cpp]view plaincopyprint?在CODE上查看代码片派生到我的代码片

1.  #include"jni.h"  

2.  /* 

3.   * Class:     com_ndk_demo_JNI 

4.   * Method:    getString 

5.   * Signature: ()Ljava/lang/String; 

6.   */  

7.  JNIEXPORT jstring JNICALL Java_com_ndk_demo_JNI_getString(JNIEnv* env, jobject obj)  

8.  {  

9.      //返回一个字符串  

10.     return (*env)->NewStringUTF(env,"Hello NDK!");  

11. }  

12.   

13. /* 

14.  * Class:     com_ndk_demo_JNI 

15.  * Method:    plus 

16.  * Signature: (II)I 

17.  */  

18. JNIEXPORT jint JNICALL Java_com_ndk_demo_JNI_plus(JNIEnv* env, jobject obj, jint a, jint b)  

19. {  

20.     //返回计算结果  

21.     return a+b;  

22. }  

#include"jni.h"

/*

 * Class:    com_ndk_demo_JNI

 * Method:   getString

 * Signature: ()Ljava/lang/String;

 */

JNIEXPORT jstring JNICALL Java_com_ndk_demo_JNI_getString(JNIEnv* env,jobject obj)

{

 //返回一个字符串

 return(*env)->NewStringUTF(env,"Hello NDK!");

}

 

/*

 * Class:    com_ndk_demo_JNI

 * Method:   plus

 * Signature: (II)I

 */

JNIEXPORT jint JNICALL Java_com_ndk_demo_JNI_plus(JNIEnv* env, jobjectobj, jint a, jint b)

{

 //返回计算结果

 return a+b;

}

到这一步,离成功就不远了,现在需要将NDKDemo.c编译成.so库,在目录中新建一个文件夹(这个目录是随便建立的),这里我为了方便就在AndroidNDKDemo工程的bin\classes目录中新建一个jni文件夹(这里一定要注意文件夹的名称一定是"jni",不然后面的编译会报错的),下面是我的目录图:

你同样可以在D盘下新建一个jni文件夹,或者其他的目录下都可以的,但是一定要注意文件夹的名称必须是"jni"


然后将生成的C代码的头文件和你刚刚新建的.c文件拷贝到jni文件夹下,(这里的NDKDemo.cpp不要管了,是C++代码文件)

下面接着新建一个Android.mk文件,文件内容如下:

LOCAL_PATH := $(call my-dir)
include$(CLEAR_VARS)
LOCAL_MODULE  := first_jni (最终so文件名是libfirst_jni.so
LOCAL_SRC_FILES :=NDKDemo.c (C代码)
include$(BUILD_SHARED_LIBRARY)

上面的准备工作都做完了,现在就开始编译吧:

打开cygwin,输入以下命令:

cd /cygdrive/e/workspace/AndroidNDKDemo/bin/classes  

进入到jni文件夹的根目录,这个是我的目录,你们要进入你们刚才新建的jni文件夹的根目录即可

然后输入命令:

$NDK/ndk-build

进行编译

上面说明编译成功,这时候到jni的根目录中可以看到多出两个文件夹,一个是libs,一个是obj,我们这里只关心libs中的文件

进入到lib文件夹下,看到有一个libfirst_jni.so文件,这时候,我们的编译工作全部搞定了,这时候只需要将libfirst_jni.so文件拷贝到AndroidNDKDemo工程中的libs文件夹下,如果libs下没有文件夹armeabi,就新建一个armeabi文件夹,将libfirst_jni.so文件放到armeabi文件夹中,加载库的代码具体可以看上面。

运行结果如下:

可以看到,成功的运行了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值