前几天研究了JNI技术后,想在Android上试一试研究结果,查阅了很多资料后,总结如下步骤:

首先来看一下什么是NDK:

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


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

第一步:搭建NDK环境

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

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


第二步:下载安装cygwin

由于NDK编译代码时必须要用到make和gcc,所以你必须先搭建一个linux环境,cygwin是一个在windows平台上运行的unix模拟环境,它对于学习unix/linux操作环境,或者从unix到windows的应用程序移植,非常有用。通过它,你就可以在不安装linux的情况下使用NDK来编译C、C++代码了。下面我们一步一步的安装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:使用HTTP或FTP代理服务器进行连接(需要输入服务器地址、端口号)。
  根据自己的网络连接的实情情况进行选择,一般正常情况下,均选择第一种,也就是直接连接方式。然后再点击“下一步”,
7、 这是选择要下载的站点,选择后点下一步.
8、 此时会下载加载安装包列表
9、Search是可以输入你要下载的包的名称,能够快速筛选出你要下载的包。那四个单选按钮是选择下边树的样式,默认就行,不用动。View默认是Category,建议改成full显示全部包再查,省的一些包被隐藏掉。左下角那个复选框是是否隐藏过期包,默认打钩,不用管它就行,下边开始下载我们要安装的包吧,为了避免全部下载,这里列出了后面开发NDK用得着的包:autoconf2.1、automake1.10、binutils、gcc-core、gcc-g++、gcc4-core、gcc4-g++、gdb、pcre、pcre-devel、gawk、make共12个包
10、然后开始选择安装这些包吧,点skip,把它变成数字版本格式,要确保Bin项变成叉号,而Src项是源码,这个就没必要选了。
11、下面测试一下cygwin是不是已经安装好了。
运行cygwin,在弹出的命令行窗口输入:cygcheck -c cygwin命令,会打印出当前cygwin的版本和运行状态,如果status是ok的话,则cygwin运行正常。
然后依次输入gcc --version,g++ --version,make –version,gdb –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这个名字是随便取的,为了方面以后使用方便,选个简短的名字,然后保存)

(这里还要注意的是盘符是"/"而不是"\",因为cygwind是Linux,不是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 ,还要对应app和source2个目录的项目目录,现在改成了$NDK/ndk-build)


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

在Eclipse中新建一个AndroidNDKDemo工程


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

package com.ndk.demo;public class JNI {//获取字符串public native String getString();//进行加法操作public native int plus(int a,int b);}
在来看一下AndroidNDKDemoActivity.java,主要是测试的Demo,代码如下:

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(Bundle savedInstanceState) {        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(new OnClickListener(){public void onClick(View v) {//显示从C代码中返回的字符串Toast.makeText(getApplicationContext(), jni.getString(), 1500).show();}});        btn2.setOnClickListener(new OnClickListener(){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代码,如下:

#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, jobject obj, 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文件夹中,加载库的代码具体可以看上面。

运行结果如下:


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


问题

就是我这里面使用了C代码测试的,其实我开始的时候是用C++代码测试的,就是上面的NDKDemo.cpp文件:代码如下:

#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("Hello NDK!");}/* * Class:     com_ndk_demo_JNI * Method:    plus * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_ndk_demo_JNI_plus(JNIEnv* env, jobject obj, jint a, jint b){//计算结果return a+b;}
这里面就是方法:JNICALL Java_com_ndk_demo_JNI_getString不一样

C代码中是:

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

C++代码是:

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

但是使用C++代码的话,在Eclipse中编译报错,很是纠结,现在还没有解决,如果哪位大神能够告诉我一下,本人将不胜感激!


Demo的下载的地址:

http://download.csdn.net/detail/jiangwei0910410003/7594551



更多相关文章

  1. Android(安卓)Studio错误代码不提示问题解决
  2. android 获取网络图片缓存(内存—>文件—>网络)
  3. 混合开发H5页面嵌入ios/Android及echarts图表问题总结
  4. android中实现暗码启动apk【一】
  5. 两分钟搞定android JNI
  6. Android(安卓)ndk探索之一(利用Android(安卓)Studio和ndk编译c)
  7. Android应用程序访问linux驱动第一步:实现并测试Linux驱动
  8. android eclipse 混淆jar代码
  9. android文件选择、读取、浏览器的实现(音乐文件)

随机推荐

  1. android故障与Log的对应
  2. Android(安卓)Studio 自动代码提示设置
  3. android 用shape oval属性画圆环变成黑圆
  4. 在xml文件的Preference标签中,用给标签加
  5. Android(安卓)Netroid解析之——断点续传
  6. Android(安卓)adb.exe程序启动不起来处理
  7. Android(安卓)跨进程通信(一)
  8. Android(安卓)Listview多次调用相同的add
  9. Android(安卓)studio的安装、环境配置和
  10. android SDK启动的错误