Android JNI/NDK

版权说明:本文为 开开向前冲 原创文章,转载请注明出处;
注:限于作者水平有限,文中有不对的地方还请指教。

文章参考:JNI参考手册Android官方NDK文档

一:概述

Android NDK 是一种允许将“本地代码”嵌入到 Android 应用中的一种工具,能在Android 应用中使用本地代码;

在Android 开发中我通常将Java 称为开发语言,而将C/C++ 语言称为本地语言,使用Java 能开发一个完整的APP,那使用纯C/C++ 或者Java+C/C++ 是否能开发APP 呢???
———— 答案是肯定的,实际中也是有很多APP 都是采用Java+C/C++ 的来实现;那我们是通过什么方式去实现的呢? ———— NDK

在学习NDK 之前我们我们需要了解JNI(Java Native Interface):JNI 是 Java 和 C++ 组件用以互相沟通的接口。很多和平台相关特性相关的库和很多优秀的库都是通过C/C++ 编写的,例如Android 系统中底层电源管理,FFMPEG ······;为了更好利用硬件特性和目前已经存在的库,我们就需要JNI 来实现Java 与C/C++通信;

JNI是什么?
JNI(Java Native Interface)意为Java本地接口,它允许Java代码和其他语言写的代码进行交互;
推荐一本JNI参考手册

NDK是什么?
Android NDK(Native Development Kit )是一套工具集合,允许你用像C/C++语言那样实现应用程序的一部分。
为什么要用NDK?
1、安全性,现在逆向很风行,纯Java的apk容易被反汇编后拿到源代码,使用C/C++会好很多。
2、效率,目前很多优秀的库都是通过C/C++开发,我们可以复用这些库,减少重复工作量。
3、平台特性,很多和平台硬件相关的功能都是需要底层驱动来实现功能,而我们的Java 目前还没办法做到。

JNI和NDK的区别?
从工具上说,NDK其实多了一个把.so和.apk打包的工具,而JNI开发并没有打包,只是把.so文件放到文件系统的特定位置。从编译库说,NDK开发C/C++只能能使用NDK自带的有限的头文件,而使用JNI则可以使用文件系统中带的头文件。编写方式一样。

JNI 开发步骤:

1、编写声明了native方法的Java类
2、将Java源代码编译成class字节码文件
3、用javah -jni命令生成.h头文件(javah是jdk自带的一个命令,-jni参数表示将class中用native声明的函数生成jni规则的函数)
4、用本地代码实现.h头文件中的函数
5、将本地代码编译成动态库(windows:***.dll**,linux/unix:***.so**,mac os x:***.jnilib**)
6、拷贝动态库至 java.library.path 本地库搜索目录下,并运行Java程序

下图是从《The Java™ Native Interface Programmer’s Guide and Specification》书中截取

figure1.png

下面将使用上述步骤编写一个HelloWorld程序:
1:编写声明了native 方法的Java类:HelloWorld.java

class HelloWorld {
private native void print();
public static void main(String[] args) {
     new HelloWorld().print();
}
static {
     System.loadLibrary("HelloWorld");
}
}

2:使用javac编译器编译Java源代码为class 文件:

javac HelloWorld.java;

3:使用javah工具将第二步生成的".class"文件生成JNI-Style的".h"文件:

javah -jni HelloWorld

该命令将生成HelloWorld.h文件,文件中声明的Java_HelloWorld_print方法就是HelloWorld.java 中print方法的本地声明;该文件中最重要的内容如下:

JNIEXPORT void JNICALL
Java_HelloWorld_print (JNIEnv *, jobject);

4:编写".C"程序实现上述".h" 文件:HelloWorld.c

#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
    printf("Hello World!\n");
    return;
}

5:将本地代码编译成动态库:
编译环境和工具可以参考一下编译环境配置,目前基本的IDE 都支持编译动态库,例如Android Studio
因为我是Win32操作系统,我的编译命令:

cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll

编译出的动态库文件需要放在一定的位置才能被程序识别,一般都是放到"PATH"环境变量中的某个目录,
只不过目前的JDK 版本都支持在运行时手动指定环境变量;如:

java -Djava.library.path=. HelloWorld
"-D"参数和"java.library.path=. "表示设置Java 虚拟机从当前目录搜索本地库文件;

6:运行程序;

java HelloWorld

你的控制台是否有显示 Hello World!

至此一个来自于C/C++的"HelloWorld"成功的在Java中代码中得到运行;

在JNI中需要清楚的概念:JNIEnv,jobject,java数据和JNI 数据映射,JNI数据与本地C/C++数据转换,java 方法的本地签名等

JNI参考手册中对JNIEnv 描述;

JNIEnv.png

JNIEnv与JavaVM 

JNIEnv 概念 : 是一个线程相关的结构体, 该结构体代表了 Java 在本线程的运行环境 ; 

JNIEnv 与 JavaVM : 注意区分这两个概念; 
-- JavaVM : JavaVM 是 Java虚拟机在 JNI 层的代表, JNI 全局只有一个;
-- JNIEnv : JavaVM 在线程中的代表, 每个线程都有一个, JNI 中可能有很多个 JNIEnv;

JNIEnv 作用 : 
-- 调用 Java 函数 : JNIEnv 代表 Java 运行环境, 可以使用 JNIEnv 调用 Java 中的代码;
-- 操作 Java 对象 : Java 对象传入 JNI 层就是 Jobject 对象, 需要使用 JNIEnv 来操作这个 Java 对象;

JNIEnv 体系结构 

线程相关 : JNIEnv 是线程相关的, 即 在 每个线程中 都有一个 JNIEnv 指针, 每个JNIEnv 都是线程专有的, 其它
线程不能使用本线程中的 JNIEnv, 线程 A 不能调用 线程 B 的 JNIEnv;

JNIEnv 不能跨线程 : 
-- 当前线程有效 : JNIEnv 只在当前线程有效, JNIEnv 不能在 线程之间进行传递, 在同一个线程中, 多次调用 JNI层方法, 传入的 JNIEnv 是相同的;
-- 本地方法匹配多JNIEnv : 在 Java 层定义的本地方法, 可以在不同的线程调用, 因此 可以接受不同的 JNIEnv;

JNIEnv 结构 : 由上面的代码可以得出, JNIEnv 是一个指针,  指向一个线程相关的结构, 线程相关结构指向 JNI 函数指针 数组,
 这个数组中存放了大量的 JNI 函数指针, 这些指针指向了具体的 JNI 函数; 

注意:JNIEnv只在当前线程中有效。本地方法不能将JNIEnv从一个线程传递到另一个线程中。相同的 Java 线程中对本地方法多次调用时,
传递给该本地方法的JNIEnv是相同的。但是,一个本地方法可被不同的 Java 线程所调用,因此可以接受不同的 JNIEnv。

jobject
即Java 对象在JNI 层的代表;

对于更多JNI 开发的知识,相信大家看完JNI参考手册 都会明白;

NDK

Android NDK 是一种允许将“本地代码”嵌入到 Android 应用中的一种工具,能在Android 应用中使用本地代码;
//关于ndk-build,CMake;
未完待续。。。。。。

参考资料:深入理解JNI

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容