Android NDK 开发跟其它开发一样,首先需要配置好开发环境,本文以 Ubuntu系统为例介绍如何进行 Android NDK 开发环境的配置。

1. 简介

什么是 Android NDK 呢? NDK(Native Development Kit) 是一个允许开发者用一些本地语言(C/C++)编写 Android App 的部分功能的工具集。对于一些特定的 App,NDK 非常有利于我们直接使用现成的用 C/C++ 编写的代码库(但对于大多数 App 来说,NDK 是没有必要的)。使用 NDK 进行 C/C++ Android 开发的基本结构和流程如下图(来自shihongzhi博客 ):

2.开发环境配置

NDK 开发过程中涉及到将 C/C++ 程序编译为动态库(.so文件),由于Ubuntu系统中已经安装有 C/C++ 的编译工具 gcc/g++,以及 make 工具,所以在此不作介绍。另外还需要安装 JDK,并配置 Java 的环境变量,这个不是本文重点,在此也不作介绍了。

下面重点讲讲 Android 相关 SDK 的安装和配置,主要涉及到 Android SDK,ADT,NDK等。要进行 Android 开发,首先需要安装 Android SDK,要在 Eclipse 中进行开发的话,还需在 Eclipse 中安装 ADT(Android Develop Tools),在 Android 官网上提供了 SDK 和 包含 ADT 的 Eclipse 的集成开发包,可以一起下载:adt-bundle-linux-x86-20140321.zip。另外,还需要安装 NDK,下载地址:android-ndk-r9d-linux-x86.tar.bz2。下载完这两个压缩包后解压并移动到 /usr/local 目录下:

(1)先下载安装NDK。
下载链接:http://developer.android.com/tools/sdk/ndk/index.html,下载后解压缩就可以用了。

(2)打开Eclipse,点Window->Preferences->Android->NDK,设置NDK路径(如果没有NDK选项,可按照http://jingyan.baidu.com/article/4d58d5413000a09dd4e9c0fe.html进行设置),如下图所示:


(3)新建一个Android工程(这里为AntiVirus),在工程上右键点击Android Tools->Add Native Support...,然后给我们的.so文件取个名字,例如本例中的:HelloJni。这时候工程就会多一个jni的文件夹,jni下有Android.mk和HelloJni.cpp文件。Android.mk是NDK工程的Makefile,HelloJni.cpp就是NDK的源文件。

(4)新建并配置一个Builder:
  (a)Project->Properties->Builders->New,新建一个Builder。
  (b)在弹出的【Choose configuration type】对话框,选择【Program】,点击【OK】:
  (c)在弹出的【Edit Configuration】对话框中,配置选项卡【Main】。
       在“Name“中输入新builders的名称(这里为Ndk_Builder)。
       在“Location”中输入nkd-build(windows为nkd-build.cmd)的路径。
      (我的是/usr/local/android-ndk-r10/ndk-build,根据各自的ndk路径设置,也可以点击“Browser File System…”来选取这个路径)。
       在“Working Diretcoty”中输入${workspace_loc:/AntiVirus}(也可以点击“Browse Workspace”来选取AntiVirus目录)。
 
  (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…”,勾选AntiVirus工程的“jni“目录,点击”finish“。点击“OK“,完成配置。到这里Eclipse就能够自动调用NDK编译jni目录下的C/C++代码了。
(5)在AntiVirus工程中新建一个TestJni.java类(为了调用C/C++代码),其内容如下:

 package com.wat.antivirus;

 public class TestJni {
static {
System.loadLibrary("HelloJni"); // //加载相应的动态库,相对路径,src的根目录,库名必须是libxxx.so
} public native String helloSay(); // 返回字符串,使用JNI的关键字native
public native int helloAdd(int a,int b); // 两个整数相加
public native int helloSub(int a,int b); // 两个整数相减
public native int helloMul(int a,int b); // 两个整数相乘
public native int helloDiv(int a,int b); // 两个整数相除
}

(6)在 Eclipse 中 build 一下生成对应 .class 文件,然后使用 javah 工具根据该 class 文件自动生成 jni API 的头文件。在 AntiVirus工程根目录下执行如下命令:

javah -classpath ./bin/classes -d jni com.wat.antivirus.TestJni

其中 -classpath ./bin/classes 表示类的路径,-d jni 表示生成的头文件存放的目录, com.wat.antivirus.TestJni 则是完整类名。

注意生成的头文件命名采用:包名+类名

JNI头文件一般由三部分组成:

  • 头文件
  • 本地方法的注释
  • 本地方法在头文件中的表示

执行命令后,在 ~/workspace/AntiVirus/jni 目录下生成了C++头文件 com_wat_antivirus_TestJni.h ,文件内容如下:

 /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_wat_antivirus_TestJni */ #ifndef _Included_com_wat_antivirus_TestJni
#define _Included_com_wat_antivirus_TestJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_wat_antivirus_TestJni
* Method: helloSay
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_wat_antivirus_TestJni_helloSay
(JNIEnv *, jobject); /*
* Class: com_wat_antivirus_TestJni
* Method: helloAdd
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_wat_antivirus_TestJni_helloAdd
(JNIEnv *, jobject, jint, jint); /*
* Class: com_wat_antivirus_TestJni
* Method: helloSub
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_wat_antivirus_TestJni_helloSub
(JNIEnv *, jobject, jint, jint); /*
* Class: com_wat_antivirus_TestJni
* Method: helloMul
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_wat_antivirus_TestJni_helloMul
(JNIEnv *, jobject, jint, jint); /*
* Class: com_wat_antivirus_TestJni
* Method: helloDiv
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_wat_antivirus_TestJni_helloDiv
(JNIEnv *, jobject, jint, jint); #ifdef __cplusplus
}
#endif
#endif

我们拿其中一个方法作具体说明:

JNIEXPORT jint JNICALL Java_com_wat_antivirus_TestJni_helloAdd(JNIEnv *, jobject, jint, jint);

1、JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。

2、jint本地方法返回的数据类型,表示的是java下面的int类型

3、Java_com_wat_antivirus_TestJni_helloAdd 这个就是被JNICALL调用的部分,也就是Java中的native 方法名,这里起名字的方式比较特别,是:包名+类名+方法名。(Java_为JNI中标识此方法来源于java的标识头)

注意:类名千万别加下划线,Test_Jni

4、JNIEnv *  它是一个接口指针,用于定位函数表中的函数,jni.h头文件中存在着大量被封装好的函数,这些函数也是JNI编程中经常被使用到的,要想调用这些函数就需要使用JNIEnv这个对象

5、jobject  两种情况

类 对象 实例    TestJni tj  = new TestJni();     tj.helloAdd(10,20);

  • 上述中helloAdd方法是一个非静态方法,在Java中要想调用它必须先实例化对象,然后再用对象调用它,那这个时候jobject就可以看做Java类的一个实例化对象,也就是在本地方法实现上 jobject thiz  这个thiz参数就是指的tj
  • 如果helloAdd是一个静态方法,那么在Java中,它不是属于一个对象的,而是属于一个类的,Java中用TestJni .helloAdd()这样的方式来调用,这个时候jobject就可以看做是java类的本身,也就是说thiz就是TestJni.class

(7)编辑Android.mk文件,其内容如下:

 #返回当前mk的路径,宏函数’my-dir’, 由编译系统提供
LOCAL_PATH := $(call my-dir)
#CLEAR_VARS由编译系统提供,让GNU MAKEFILE为你清除LOCAL_XXX变量
include $(CLEAR_VARS)
#生成动态库名
LOCAL_MODULE := HelloJni
#添加源文件、头文件
LOCAL_SRC_FILES := HelloJni.c
#生成动态库
include $(BUILD_SHARED_LIBRARY)

补充说明:

 #增加所需的库
LOCAL_LDLIBS := -llog
链接的库不产生依赖关系,一般用于不需要重新编译的库,如库不存在,则会报错找不到。默认的路径/android-ndk-r6b/platforms/android-/arch-arm/usr/lib 链接的都是系统的库
LOCAL_SHARED_LIBRARIES := libexpat libcurl
会生成依赖关系,当库不存在时会去编译这个库。一般用于编译第三方提供的库
#生成动态库
include $(BUILD_SHARED_LIBRARY)
#生成静态库
#include $(BUILD_STATIC_LIBRARY)
#生成应用程序
#include $(BUILD_EXECUTABLE)

(8)将com_wat_antivirus_TestJni.h拷贝到AntiVirus工程的jni目录下, 然后在HelloJni.c文件中完成头文件中函数的实现,其内容如下:

 #include <string.h>
#include <jni.h> jstring
Java_com_wat_antivirus_TestJni_helloSay( JNIEnv* env,
jobject thiz )
{
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a/NEON (hard-float)"
#else
#define ABI "armeabi-v7a/NEON"
#endif
#else
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a (hard-float)"
#else
#define ABI "armeabi-v7a"
#endif
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__x86_64__)
#define ABI "x86_64"
#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */
#define ABI "mips64"
#elif defined(__mips__)
#define ABI "mips"
#elif defined(__aarch64__)
#define ABI "arm64-v8a"
#else
#define ABI "unknown"
#endif return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI ".");
}

编辑HelloJni.c并保存后,可以看到AntiVirus工程下的obj/local/armeabi目录下将自动生成libAntiVirus.so库。

(9)在AntiVirus.java中完成对TestJni.java中函数的调用:

 package com.wat.antivirus;

 import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); Button btn = (Button)findViewById(R.id.btn_cal);
btn.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
TextView tv1 = (TextView) findViewById(R.id.textView1);
TextView tv2 = (TextView) findViewById(R.id.textView2);
TextView tv3 = (TextView) findViewById(R.id.textView3); int a = Integer.parseInt(tv1.getText().toString());
int b = Integer.parseInt(tv2.getText().toString());
TestJni tj = new TestJni();
int c = tj.helloAdd(a,b);
String str = tj.helloSay();
tv3.setText(str + Integer.toString(c));
}
});
}
}

(10)运行AntiVirus工程,在模拟器中可以看到界面输出来自HelloJni.c 文件中的“HelloWorld from JNI ! “。

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

跟我学Android NDK开发(一)的更多相关文章

  1. android NDK开发在本地C/C++源码中设置断点单步调试具体教程

    近期在学android NDK开发,折腾了一天,最终可以成功在ADT中设置断点单步调试本地C/C++源码了.网上关于这方面的资料太少了,并且大都不全,并且调试过程中会出现各种各样的问题,真是非常磨人. ...

  2. Android NDK 开发(二) -- 从Hlello World学起【转】

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/41805719  上篇文章讲述了Android NDK开发的一些基本概念,以及NDK ...

  3. Android学Jni/Ndk 开发记录(一)

      治疗拖延症的唯一办法就是:一想起些什么 / 要做些什么就 TM 立马去做! 是的,突然想起我不会 JNI.NDK 开发.解决办法:立马去学! 一:配置 NDK 环境 下载 NDK 写入到配置文件 ...

  4. Android NDK开发初识

    神秘的Android NDK开发往往众多程序员感到兴奋,但又不知它为何物,由于近期开发应用时,为了是开发的.apk文件不被他人解读(反编译),查阅了很多资料,其中有提到使用NDK开发,怀着好奇的心理, ...

  5. Android NDK开发Hello Word!

    在之前的博客中已经为大家介绍了,如何在win环境下配置DNK程序,本篇我将带大家实现一个简单的Hello jni程序,让大家真正感受一下NDK开发的魅力.这里我们选择使用C+JAVA开发Android ...

  6. Android NDK开发

    Android NDK 开发教程(极客学院) 一.Android NDK环境搭建 使用最新ndk,直接抛弃cygwin,以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin( ...

  7. Android NDK 开发(四)java传递数据到C【转】

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/41845701 前面几篇文章介绍了Android NDK开发的简单概念.常见错误及处 ...

  8. Android NDK 开发(三)--常见错误锦集合Log的使用【转】

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/41826511  Android NDK开发经常因某些因素会出现一些意想不到的错误, ...

  9. android NDK开发环境搭建

    android NDK开发环境搭建 2012-05-14 00:13:58 分类: 嵌入式 基于 Android NDK 的学习之旅-----环境搭建 工欲善其事必先利其器 , 下面介绍下 Eclip ...

随机推荐

  1. MaxScript与外部程序通讯

    最近项目要求通过java给max发送任务指令,max接收指令执行任务,并且返回执行的结果.不管为什么会有这样的需求,有就要去实现. 1.OLE开启 Max本身提供了一个方式,它可以将自己注册成一个Ol ...

  2. Visual Studio Code必备插件

    HTML Snippets: 超级实用且初级的 H5代码片段以及提示 HTMLHint: html代码检测 HTML CSS Support : 让 html 标签上写class 智能提示当前项目所支 ...

  3. nginx www解析失败问题解决

    nginx www解析失败: nginx代理IIS下域名时 xxxx.xxx可以解析 但www.xxxx.xxx解析失败 IIS增加ip解析:配置下127.0.0.1就可以解析了.

  4. Intellij IDEA创建javaweb步骤详解

    一.创建并设置javaweb工程 1.创建javaweb工程File --> New --> Project... 设置工程名字: 创建完成后工程结构如下: 2. Web工程设置2.1 在 ...

  5. Java虚拟机(三)垃圾标记算法与Java对象的生命周期

    前言 这一节我们来简单的介绍垃圾收集器,并学习垃圾标记的算法:引用计数算法和根搜索算法,为了更好的理解根搜索算法,会在文章的最后介绍Java对象在虚拟机中的生命周期. 1.垃圾收集器概述 垃圾收集器( ...

  6. Java标识符

    相关内容: JAVA标识符: 定义 组成规则 常见的命名规则 包 类和接口 方法.变量 常量 首发时间:2017-06-22 20:40 修改时间: 2018-03-16 14:01 :修改了标题,修 ...

  7. 国内使用kubeadm部署kubernetes的完整流程

    使用阿里云的镜像安装kubeadm和kubectl cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Ku ...

  8. C#多线程的用法6-线程间的协作Mutex

    Mutex在线程协作的过程中起互斥的左右,效果与线程锁类似. /// <summary> /// 多线程协作-Mutex /// </summary> private stat ...

  9. django直接操作MySQL,中文乱码

    sql_insert = '''insert into sinfors_hvvms values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)''' c ...

  10. MySQL压缩包zip安装

    看了网上好多种教程,自己尝试失败了好多次,最后总算弄好了,具体如下 zip下载地址:https://dev.mysql.com/downloads/mysql/ 之后点击No thanks, just ...