手把手教你搭建NDK开发环境以及基于JNI开发的简单DEMO

1.什么是NDK

NDK全称:Native Development Kit :原生库开发工具包。 

1.1 NDK是一系列工具的集合。 

NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,

并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。 

NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,

开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。 

NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。 

1.2 NDK提供了一份稳定、功能有限的API头文件声明。 

Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。

从该版本的NDK中看出,这些API支持的功能非常有限,

包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。

大家可以自行百度,以免被我粗浅的见解所影响。话不多说,接下来开始从配置环境到撸代码跑通。


2.安装NDK

对于Windows环境下NDK的开发,如果使用的NDK是r7之前的版本,必须要安装Cygwin才能使用NDK,

所以为Eclipse需要配置的builder,其实是执行Cygwin,然后传递ndk-build作为参数。

在NDKr7开始,Google的Windows版的NDK提供了一个ndk-build.cmd的脚本,

这样,就可以直接利用这个脚本编译,而不需要使用Cygwin了。

只需要为Eclipse Android工程添加一个Builders,就能让Eclipse自动编译NDK。


注:本文是讲述NDK-r10e下的实现实例。

接下来是使用NDK-r7在windows下配置自动编译的builders的过程。

(实际上对于Linux系统,只需要修改ndk-build.cmd为ndk-build就可以了)

2.1下载安装Ndk_r10e。

下载地址:

win_64:https://dl.google.com/android/ndk/android-ndk-r10e-windows-x86_64.exe

win_32:https://dl.google.com/android/ndk/android-ndk-r10e-windows-x86.exe

linux_64:https://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin

linux_32:https://dl.google.com/android/ndk/android-ndk-r10e-linux-x86.bin

Mac OS X 64:https://dl.google.com/android/ndk/android-ndk-r10e-darwin-x86_64.bin


2.2新建项目

我的项目名:NdkTest  / 包名:com.andy.ndktest (仅做参考,所有用到的地方请根据自己的修改)

然后在工程目录NdkTest  下新建jni文件夹,该文件夹就用来保存NDK需要编译的文件代码等。

2.3新建并配置Builder:

 (a)Project->Properties->Builders->New,新建一个Builder。 

 (b)在弹出的【Choose configuration type】对话框,选择【Program】,点击【OK】: 

 (c)在弹出的【Edit Configuration】对话框中,配置选项卡【Main】。

 在“Name“中输入新builders的名称(我取名为Ndk_Builder)。

 在“Location”中输入nkd-build.cmd的路径。 (我的是E:\android-ndk-r10e\ndk-build.cmd,

 根据各自的ndk解压之后存放的路径设置, 也可以点击“Browser File System…”来选取这个路径)。

 在“Working Diretcoty”中输入${workspace_loc:/NdkTest  } (也可以点击“Browse Workspace”来选取NdkTest  目录)。

 (d)【Edit Configuration】对话框中,配置选项卡【Refresh】。

 勾选“Refresh resources upon completion”, 勾选“The entire workspace”, 勾选“Recuresively include sub-folders”。

 (e)【Edit Configuration】对话框中,配置选项卡【Build options】。

 勾选“After a “Clean””, 勾选“During manual builds”, 勾选“During auto builds”, 勾选“Specify working set of relevant resources”。

 点击“Specify Resources…”, 勾选TestNdk工程的“jni“目录,点击”finish“。  点击“OK“,完成配置。

 OK,到这里Eclipse就能够自动调用NDK编译jin目录下的C/C++代码了。


3.撸代码

3.1 在NdkTest工程中新建一个JniClient.java(为了调用C/C++代码),其内容如下:

package com.andy.jni;
public class JniClient {
    static public native String ShowStr();
    static public native int AddInt(int a, int b);
}


3.2 android studio:用cmd命令定位到JniClient.java 所在目录,输入“javac JniClient.java“后回车,

生成JniClinet.class文件,将JniClinet.class拷贝到NdkTest\bin\classes\com\andy\jni目录。

Eclipse:在NdkTest\bin\classes\com\andy\jni目录下就已经有JniClinet.class文件了。

3.3将cmd命令定位到NdkTest\bin\classes目录,输入”javah com.andy.jni.JniClient“后回车,

在NdkTest\bin\classes目录下就生成了C++头文件com_andy_jni_JniClient.h。

com_andy_jni_JniClient.h的文件内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class com_andy_jni_JniClient */

#ifndef _Included_com_andy_jni_JniClient
#define _Included_com_andy_jni_JniClient
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_andy_jni_JniClient
 * Method:    ShowStr
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_andy_jni_JniClient_ShowStr
  (JNIEnv *, jclass);

/*
 * Class:     com_andy_jni_JniClient
 * Method:    AddInt
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_andy_jni_JniClient_AddInt
  (JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

3.4在jni目录下新建一个Android.mk文件,其内容如下:

LOCAL_PATH := $(call my-dir) //编译路径,该工程的根目录
include $(CLEAR_VARS)
LOCAL_MODULE := NdkTest//编译后的模块名字,会自动添加lib前缀和.so后缀
LOCAL_SRC_FILES := com_andy_jni_JniClient.c //需要编译的.c文件
include $(BUILD_SHARED_LIBRARY) //编译成模块


3.5将com_andy_jni_JniClient.h拷贝到NdkTest工程的jni目录下, 

然后新建一个com_andy_jni_JniClient.c文件完成头文件中函数的实现,
其内容如下:

#include "com_andy_jni_JniClient.h"
#include 
#include 

#ifdef __cplusplus
extern "C"
{
#endif
/*
 * Class:     com_andy_jni_JniClient
 * Method:    ShowStr
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_andy_jni_JniClient_ShowStr
  (JNIEnv *env, jclass arg)
{
    jstring str = (*env)->NewStringUTF(env, "HelloWorld from JNI !");
    return str;
}

/*
* Class:     com_ndk_test_JniClient
* Method:    AddInt
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_andy_jni_JniClient_AddInt
  (JNIEnv *env, jclass arg, jint a, jint b)
{
    return a + b;
}

#ifdef __cplusplus
}
#endif

编辑com_andy_jni_JniClient.c并保存后,

可以看到NdkTest工程下的obj/local/armeabi目录下将自动生成libNdkTest.so库。

3.6在MainActivity.java中完成对JniClient.java中函数的调用:

package com.andy.ndktest;  
  
import com.andy.jni.JniClient;  
import android.app.Activity;  
import android.os.Bundle;  
import android.widget.TextView;  
  
public class MainActivity extends Activity {  
  
  @Override  
  protected void onCreate(Bundle savedInstanceState) {  
      super.onCreate(savedInstanceState);  
//    setContentView(R.layout.activity_main);  
  
      String str = JniClient.ShowStr();     
      int iSum = JniClient.AddInt(13, 14);          
      String strSum = "13 + 14 = " + iSum;  
              TextView tv1 = new TextView(this);  
          tv1.setText(str + "\n" + strSum);  
          setContentView(tv1);  
  }  
    
  //静态方法块,加载.so文件  
  static {  
      System.loadLibrary("NdkTest");  
  }  
}  

3.7运行NdkTest工程

在设备或者模拟器中可以看到界面输出来自com_ndk_test_JniClient.c 文件中的“HelloWorld from JNI ! “以及加法运算结果。


OK,NDK实例到此完成。

后续就可以深入的学习NDK/JNI了,比如C/C++与Java的数据类型转换,Android.mk文件的编写格式等。

欢迎各位大牛批阅指正,谢谢!



你可能感兴趣的:(Android)