1. NDK简介
Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”

1.1 NDK产生的背景
Android平台从诞生起,就已经支持C、C++开发。
众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Java语言。
但这并不等同于“第三方应用只能使用Java”。
在Android SDK首次发布时,Google就宣称其虚拟机Dalvik支持JNI编程方式,
也就是第三方应用完全可以通过JNI调用自己的C动态库,
即在Android平台上,“Java+C”的编程方式是一直都可以实现的。

不过,Google也表示,使用原生SDK编程相比Dalvik虚拟机也有一些劣势,Android SDK文档里,找不到任何JNI方面的帮助。
即使第三方应用开发者使用JNI完成了自己的C动态链接库(so)开发,但是so如何和应用程序一起打包成apk并发布?
这里面也存在技术障碍。比如程序更加复杂,兼容性难以保障,无法访问Framework API,Debug难度更大等。
开发者需要自行斟酌使用。
 
于是NDK就应运而生了。NDK全称是Native Development Kit。
NDK的发布,使“Java+C”的开发方式终于转正,成为官方支持的开发方式。
NDK将是Android平台支持C开发的开端。

1.2 为什么使用NDK
    1.代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反编译难度较大。
    2.可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。
    3.提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
    4.便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。

1.3 NDK简介
1.NDK是一系列工具的集合
NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。
NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件
(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。
 
2.NDK提供了一份稳定、功能有限的API头文件声明
Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。
从该版本的NDK中看出,这些API支持的功能非常有限,
包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。

1.4 NDK的安装
见《 Ubuntu14.04下最新Android NDK安装 》

1.5 NDK的目录结构说明
 . build:    该目录存放的使用NDK的mk脚本,mk脚本指定了编译参数
 . docs:     该目录存放的是NDK的使用帮助文档
 . platforms:这里面存放的是与各个Android版本相关的平台(x86,arm,mips)相关C语言库和头文件
 . prebuilt: 预编译工作目录
 . samples:  存放的是演示程序
 . sources:  存放的是NDK工具链的C语言源码
 . tests:    测试相关的文件
 . toolchains:工具链,存放了三种架构的静态库等文件
 . ndk-build.cmd:Window平台使用NDK的命令
 . ndk-build:Linux平台使用NDK的命令

2. JNI入门
2.1 新建一个Android工程
这一步很简单,只需要命名下工程的名字,一路向下即可,最后编译并运行测试下;

2.2 修改 MainActivity.java文件
修改 app->src->main->java->MainActivity,
定义一个native方法:

...
public class MainAcitivity extends AppCompatActivity {
  // 新定义的native方法,意思是该方法的具体实现交给c语言实现
  public native String helloC();

...

2.3 创建jni目录及文件
切换到“Project”视图,
在 app->src->main下,右键选择“New->Directory”
填入目录名"jni", 并点击"OK".
在jni目录下创建hello.c源文件,代码清单如下:

// 引入头文件
#include <stdio.h>
#include <jni.h>
#include "hello.h"

// 定义在MainActivity.java类中的helloC对应的C语言函数
jstring Java_com_example_luis_jnihello_MainActivity_helloC(JNIEnv* env, jobject obj){
  char* str = "hello from C";

// 调用 jni.h中定义的创建字符串函数
  jstring string = (*(*env)).NewStringUTF(env, str);
  return string;
}

NOTE:
上面的代码虽然简单但是关于jni.h头文件和方法名必须单独说明;

JNI中C源文件方法名的命名规则
这里的命名规则指用于跟java文件中native方法对应的C语言方法,而C语言中的其他方法命名只要符合C语言规则就行。

jstring Java_com_example_luis_jnihello_MainActivity_helloC(JNIEnv* env, jobject obj) 中,
 . jstring是方法返回值类型,我们可以把jstring看成是java中String跟C语言中char*类型的一个中间转换类型,
   java跟C语言的数据类型是不一样的,他们之间要想互相调用就必须通过一种中介来实现,这个中介就是在jni.h头文件中定义的。

. 关于更多的转换类型,在本文档的第2章会有更详细的说明。

. 方法名第一个字母必须是Java,首单词大写,然后下划线_,
    然后是将该方法所在的包、类、方法用“_”连接起来,比如com.sample.luis.jnihello.MainActivity类中的helloC方法,
    转变成C语言中的方法名为Java_com_sample_luis_jnihello_MainActivity_helloC。
    方法的形参有两个是必须的也就是不管java中的方法是否有形参,但是C语言中对应的方法必须有JNIEnv* env,和jobject obj,
    如果java方法中还用其他形参,那么在C语言中严格按照顺序排在jobject obj参数的后面即可。

. 上面的env代表指向JVM的指针,obj是调用该方法的java对象。

2.4 使用NDK编译生成hello.so文件
从终端进入jni目录:
$ cd jni
$ ls
hello.c
hello.h

从NDK安装目录的sample/hello-jni/jni目录复制文件
$ cp /opt/android-ndk-r10e/samples/hello-jni/Application.mk ./
$ cp /opt/android-ndk-r10e/samples/hello-jni/Android.mk  ./

再在Android中修改Android.mk
修改后的Android.mk文件清单如下,
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello
LOCAL_SRC_FILES := hello.c

include $(BUILD_SHARED_LIBRARY)

我们只需要修改LOCAL_MODULE和LOCAL_SRC_FILES两个参数即可。
LOCAL_MODULE参数是指定编译后的目标文件的名称,其实编译好的目标文件名为libhello.so,
LOCAL_SRC_FILES指定了要编译的源文件。

还可以通过修改Application.mk文件来指定生成的动态库的类型:
如按以的修改则只会生成一种动态库:
# Build both ARMv5TE and ARMv7-A machine code.
APP_ABI := armeabi x86

也可所设置成生成所有平台都支持的动态库:
APP_ABI :=all

在终端运行命令:
$ ndk-build

命令运行后,它会

2.4 修改jni的库目录 
将app->src->main->libs改成
app->src->main->jniLibs

NOTE:
每次运行后ndk-build后,都需要修改这个目录名,否则对动态库的修改不会生效;

2.5 修改 gradle->gradle.properties
在文件的最末行添加:
android.useDeprecateNdk=true

2.6 配置项目NDK目录
选择菜单
File->Project Structure->Android NDK location:
填入NDK的安装路径;

2.7 在MainActivity.java中调用 C语言
代码清单如下:

...
public class MainAcitivity extends AppCompatActivity {
  // 新定义的native方法,意思是该方法的具体实现交给c语言实现
  public native String helloC();
  
  // 加载libhello.so动态库,但是我们在加载时必须去掉lib和后缀
  static {
    System.loadlibrary("hello");
  }

@Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

// 调用并显示
    TextView tv = new TextView(this);
    tv.setText(helloC());
    setContentView(tv);
  }

...

3. 编译运行
运行后,会显示:

hello from C

表示测试成功!

参考文档:
http://bbs.itheima.com/thread-189661-1-1.html

AndroidStudio实现JNI的示例详解的更多相关文章

  1. jquery移除、绑定、触发元素事件使用示例详解

    这篇文章主要介绍了jquery移除.绑定.触发元素事件使用示例详解,需要的朋友可以参考下. unbind(type [,data]) //data是要移除的函数 $('#btn').unbind(&q ...

  2. gcc与g++的编译链接的示例详解

    一.编译方式的示例详解 1. 编译C代码 代码如下:main.c /*!  ************************************************************** ...

  3. 史上最易懂——ReactNative分组列表SectionList使用详情及示例详解

    React Native系列 <逻辑性最强的React Native环境搭建与调试> <ReactNative开发工具有这一篇足矣> <解决React Native un ...

  4. Spring Boot 2.x 快速入门(下)HelloWorld示例详解

    上篇 Spring Boot 2.x 快速入门(上)HelloWorld示例 进行了Sprint Boot的快速入门,以实际的示例代码来练手,总比光看书要强很多嘛,最好的就是边看.边写.边记.边展示. ...

  5. VS2010 Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)

    步骤如下: 1. Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)" title="VS2010 Chart控件(一)Chart控件在ASP.NE ...

  6. socket编程的同步、异步与阻塞、非阻塞示例详解

     socket编程的同步.异步与阻塞.非阻塞示例详解之一  分类: 架构设计与优化 简介图 1. 基本 Linux I/O 模型的简单矩阵 每个 I/O 模型都有自己的使用模式,它们对于特定的应用程序 ...

  7. Android JNI作用及其详解

    Android JNI作用及其详解 Java Native Interface (JNI)标准是Java平台的一部分,它允许Java代码和其他语言写的代码进行交互.JNI 是本地编程接口,它使得在 J ...

  8. String.format()【示例详解】

    String.format()[示例详解] 整理者:Vashon 前言: String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.fo ...

  9. SpringBoot与PageHelper的整合示例详解

    SpringBoot与PageHelper的整合示例详解 1.PageHelper简介 PageHelper官网地址: https://pagehelper.github.io/ 摘要: com.gi ...

随机推荐

  1. Hadoop学习小结

    还在学校的时候,就知道Hadoop的存在了. 2012年在公司实习的时候,买了<Hadoop权威指南第2版>,大致看了下. 今年,抽空也大致喵了几眼. 最大的感悟就是:光看不做,还是不行. ...

  2. 【2017 Multi-University Training Contest - Team 6】Classes

    [链接]http://acm.hdu.edu.cn/showproblem.php?pid=6106 [题意] 给出选 A,B,C,AB,AC,BC,ABC 课程的学生,其中 AB 是 A 和 B 都 ...

  3. 【2017 Multi-University Training Contest - Team 9】FFF at Valentine

    [链接]http://acm.hdu.edu.cn/showproblem.php?pid=6165 [题意] 一张有向图,n个点,m条边,保证没有重边和自环.询问任意两个点能否满足任何一方能够到达另 ...

  4. session应用二

    从session中获取mapper对象,利用mapper对象进行增删改查 Date now = new Date(); SqlSession session = this.yangchebaoDbMa ...

  5. 洛谷——P3817 小A的糖果

    https://www.luogu.org/problem/show?pid=3817 题目描述 小A有N个糖果盒,第i个盒中有a[i]颗糖果. 小A每次可以从其中一盒糖果中吃掉一颗,他想知道,要让任 ...

  6. 3. Spring Boot Servlet

    转自:https://blog.csdn.net/catoop/article/details/50501686

  7. table嵌套table,jquery获取tr个数

    一.所有tr的个数 $("#tableId tr").length 二.所有一级tr的个数 1.$("#tableId > tr").length 2.$ ...

  8. Redis原理(二)

    运维 快照使用子进程是通过一个子进程完成, 它会比较的浪费资源的操作. 1.遍历整个内存,会增加系统负担. 2.io操作,降低redis性能. 一般都是主备,备用的进行持久化. Redis 4.0混合 ...

  9. Flask项目之手机端租房网站的实战开发(十)

    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...

  10. .v 和 .sdf

    DC输出的.v(网表?)和.sdf(储存的是延时的信息) 用于后仿真