Android JNI开发指南

来源:互联网 发布:网络冗余设计 编辑:程序博客网 时间:2024/06/08 18:15

一、NDK下载和Cygwin的下载和安装

1.NDK下载

其实国内很多网站都有提供下载,官网我们都知道国内封闭的厉害,需要翻墙,但是一般国内的一些网站都有提供下载,针对NDK包,下载完之后,我们解压完毕就行。
那么接下来我们重点说一下Cygwin的安装过程和配置过程。

2.Cygwin的下载和安装及配置

2.1 下载

Cygwin下载地址:https://cygwin.com/install.html
其是除了Cygwin的话,我们还可以使用GNUstep来替代Cygwin,用GNUstep其实也挺方便,下载和安装都很快,很方便。
GNUstp下载地址:http://www.gnustep.org/windows/installer.html
这里写图片描述
图上标记的部分时必须下载安装的,其他部分选择性安装。

2.2 安装

对于Cygwin的安装具体步骤就不详细说明了,安装过程中会有三个选项,一个是从网络下载并安装,一个是只下载不安装,还有一个是使用离线包(其实就是选择本地packages)进行安装,这里只针对一些重点的步骤进行说明,其实在安装过程中,如下【Select Packages】步骤会比较让人犹豫不决,不知道怎么选择和设置,那么这里我们其实只需要下载安装[Devel]和[Shells]就可以了,没必要全部下载和安装。
这里写图片描述

2.3 测试安装是否成功

Cygwin安装完毕之后,我们接下来就是对对Cygwin的配置了。
安装完毕之后,会在桌面创建一个快捷图标,我们双击这个快捷图标,然后输入make -v 和gcc -v测试是否安装成功,一般情况下,
安装成功会输出版本号,如下如所示:
这里写图片描述

2.4 配置NDK到Cygwin

把NDK包解压,比如我这里解压到了E:\android-ndk-r10c,然后解压后的目录结构是这样的:
这里写图片描述
Ok,NDK解压之后,接下来就是将NDK解压目录配置Cygwin中了,我们找到Cygwin的安装目录,在其安装目录下的etc目录下有一个profile配置文件,
我们使用记事本打开这个文件进行编辑,添加PATH环境变量:
PATH=”/usr/local/bin:/usr/bin:/cygdrive/e/android-ndk-r10c:${PATH}”

如果你不知道cygwin 模拟linux系统对应的目录和你本机系统目录的映射关系的话,可以执行mount命令来查看:
这里写图片描述
这样就可以了,但是需要注意的是/cygdrive是必须加上的,/e指的就是ndk所在盘符,/android-ndk-r10c就不多解释了。

如果是GNUstep的话,配置也差不多,在GNUstep安装目录的etc目录下也有一个profile配置文件,这个文件中也有一个path环境变量,将我们ndk的目录加行就行了。
这里写图片描述
不过这里加上ndk路径的时候就跟cygwin不一样的,不用加上/cygdrive前缀了,GNUstep是不需要的,同样,如果我们不知道盘符,也可以执行mount来查看。
这里写图片描述

2.5 测试Cygwin 和NDK集成配置是否成功

好了,我们配置好了之后,就直接保存关闭,然后退出cygwin模拟终端,然后重启双击进入,然后在任意目录下输入ndk-build,如果出现如下图所示信息,表明
配置成功:
这里写图片描述
然后我们来试试编译一个JNI工程试试,我们直接使用NDK包中自带的一个sample进行测试,我们使用ndk目录下的samples目录下的hello-jni工程进行测试,
在cygwin终端输入cd/cygdrive/e/android-ndk-r10c/samples/hello-jni进入该目录,输入ndk-build命令:
这里写图片描述
上面的是编译过程中输出的一些日志,好了,编译完毕了,我们再来看看有没有生成.so库文件呢?
我们到hello-jni工程的libs目录下,发现已经编译成功,生成了.so文件,最后我们可以直接将这个工程导入到集成开发环境eclipse中,
然后运行测试。

最后运行成功显示了”hello from JNI”。

二、安装CDT到Eclipse中

CDT:C/C++ Develop Tool,就是在eclipse中安装此插件,能够进行C/C++代码的开发,有提示和高亮显示功能,能够使得JNI工程在编译的时候除了工程本身能编译java代码外还能通过它编译C/C++代码。

1.下载

下载地址:http://www.eclipse.org/cdt/downloads.php
PS:其实我们如果是重头开始搭建android开发环境,可以考虑下载Eclipse C/C++ IDE Luna SR2版本的eclipse,这个版本自带了CDT开发环境。
下载离线包:cdt_8.6.0.zip

2.安装

下载完毕离线安装包之后,就直接安装了,安装嘛,使用eclipse的都不陌生,直接在Eclipse的菜单栏选择:
Help-> Install New Software,然后点击add。在弹出来的窗口name这个输入框中输入一个自定义的名字,
然后在Location这个输入框后面点击Archive这个按钮,添加我们刚刚下载好的离线包后,点击确定,然后会列出这个插件中几个可选的安装插件,一个是CDT Main Features 和CDT Option Features,我们只选择前者就可以了,还有一个是Contact all update sites… 这个先选就是联网更新,可以不用选,点击next,继续安装即可。

3.安装验证

点击Eclipse 菜单栏中的New->Project…->C/C++,如下图:
这里写图片描述
出现如上图所示,表示安装成功。

三、创建一个HelloJNI测试工程

我们在Eclipse中创建一个工程,叫做HelloJni,然后创建一个MainActivity.java,
然后我们的MainActivity.java的代码如下:

package com.example.hellojni;import android.app.Activity;import android.os.Bundle;import android.widget.TextView;public class MainActivity extends Activity {    private TextView mTv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main_activity);        mTv = (TextView) findViewById(R.id.text);        mTv.setText(sayHello());    }    public native String sayHello();}

我们在MainActivity中声明了我们的native方法,名称为sayHello();
方法声明完毕之后,我们在工程目录下创建一个jni文件夹,然后我们打开CMD命令行窗口,将目录切换到工程的src目录下,然后执行如下命令生成.h头文件:
javah com.example.hellojni.MainActivity
上面命令执行之后,就会在src目录下生成一个名为com_example_hellojni_MainActivity.h的c头文件。
这个文件的具体代码如下:

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_hellojni_MainActivity */#ifndef _Included_com_example_hellojni_MainActivity#define _Included_com_example_hellojni_MainActivity#ifdef __cplusplusextern "C" {#endif/* * Class:     com_example_hellojni_MainActivity * Method:    sayHello * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_example_hellojni_MainActivity_sayHello  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif

然后我们在工程的jni目录下创建一个.c的文件,名字和自定义,我这里叫做HelloJni.c,然后打开这个.c文件,进行代码书写和编辑,我们将上面生成的头文件中的方法部分copy到我们的我们创建的HelloJni.c文件中,注意JNIEXPROT这个关键字可以不用copy。
然后我们的HelloJni.c这个文件的具体代码如下:

#include <string.h>#include <jni.h>jstring Java_com_example_hellojni_MainActivity_sayHello(JNIEnv* env , jobject obj){    return (*env)->NewStringUTF(env,"Hello,this is JNI test demo~");}

这里要注意的是这个方法中的两个参数,copy过来的时候,要进行修改,原本它copy来是如下这个样子:
(JNIEnv *, jobject)
他这里只有类型,没有变量名,我们copy到.c文件中之后,应该进行修改,具体应该修改成如下方式:
jstring Java_com_example_hellojni_MainActivity_sayHello(JNIEnv* env , jobject obj){
return (*env)->NewStringUTF(env,”Hello,this is JNI test demo~”);
}
而且,JNIEnv * 中间没有了空格,应该是连在一块的。
OK,C代码也写完了,我们就开些mk文件了,我们在jni目录下创建一个Android.mk文件,然后进行编辑如下:
PS:如果不知道mk文件的格式应该是什么样子的话,我们可以在ndk的目录的samples下找到hello-jni项目下的jni目录下找打Android.mk文件,copy其代码到我们Android.mk文件中进行改改就可以了,这里我们要注意的是,我们创建的的.mk文件首字母应该大写,最后我们编辑后的Android.mk文件代码如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := helloLOCAL_SRC_FILES := HelloJni.cinclude $(BUILD_SHARED_LIBRARY)

针对上面的代码,我们只需要修改LOCAL_MODULE和LOCAL_SRC_FILES两个属性,分别对这两个属性说明如下:
LOCAL_MODULE:这个指定的是我们在java代码中loadlibrary的时候,指定的库名就是这个属性的值,我们这里是hello,而且最后编译生成的.so文件名就是libhello.so(lib+LOCAL_MODULE名)
LOCAL_SRC_FILES:这个肯定没的说,就是指向我们将要编译的那个.c文件。
这个Android.mk写完之后,我们还需要写一个Application.mk文件,这个文件其实很简单,只需要在这个文件中加上一句话:
APP_ABI := all
加上这句话的意思是,会一次编译出来多个平台(arm型号)对应的.so出来。
到这里我们直接打开cygwin,进入到这个工程目录下面,输入ndk-build回车后就直接编译这个库了。

OK,我们编译成功了,很明显看到,输出了libhello.so文件。
我们来看看现在的工程目录结构:
这里写图片描述
这里写图片描述
我么可以看到,工程libs目录下多了很多平台的.so文件,obj文件夹也是自动生成的,也多了一些文件。
最后我们就可以在我们的java代码中进行加载库,进行对本地方法的调用了:

package com.example.hellojni;import android.app.Activity;import android.os.Bundle;import android.widget.TextView;public class MainActivity extends Activity {    private TextView mTv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main_activity);        mTv = (TextView) findViewById(R.id.text);        mTv.setText(sayHello());    }    public native String sayHello();    static{        System.loadLibrary("hello");    }}

我们使用System.loadLirbrary(“hello”);方法加载可libhello.so库,这里要注意的是,代码中不能写成System.loadLirbrary(“libhello”);这样是错误的,应该写你在Android.mk文件中指定的LOCAL_MODULE是什么值就填写什么。
还有就是在工作中,我们经常要用到C/C++工程师提供的.so库,这时候C/C++代码并不是我们自己开发的,这个时候如果要用别人的库,那么你定义的Native方法所在的完整的包名和类名必须要和别人提供的.so对应的包名和类名一样才能正常加载调用。
OK,最后我们来运行一下我们的工程试试看:
这里写图片描述
ok,这样一个简单JNI项目就完成了。

四、C调用Java

C在调用java中的方法的时候,其实就类似java中的反射,jni.h中定义了,映射出来一些函数用来反射java中的方法,具体的映射关系请参考NDK目录下的jni.h:
E:\android-ndk-r10c\platforms\android-8\arch-arm\usr\include\jni.h

0 0
原创粉丝点击