Android JNI和NDK简单使用

一:JNI介绍

1.简介:Java Native Interface,即java本地接口,本地接口就是指用C和C++开发的接口。

2.由来:实际使用中,java需要与本地代码进行交互,因为java具备跨平台的特点,所以java与本地代码交互能力非常弱,所以采用JNI特性增强java与本地代码交互的能力。

3.作用:使得java与本地其他类型语言(如c、c++)交互,即在java代码里调用c、c++等语言的代码或c、c++代码调用java代码。

4.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程序。

5.注意点:(1) JNI是java调用Native语言的一种特性, (2) JNI是属于java的,与Android没有直接关联。

二:NDK介绍

1.简介:Native Development Kit,是Android的一个开发工具包,NDK是属于Android,与java没有直接关联

2.作用:快速开发c、c++的动态库,并自动将so和应用一起打包成APK即可通过NDK在android中,使用JNI与本地代码(如c、c++)交互。

3.应用场景:在Android的场景下使用JNI即Android开发的功能需要本地代码(c\c++)实现。

4.特点:用下面的图来直观的了解它的特点

5.使用流程:

(1) 配置Android NDK环境

(2) 创建Android项目,并于NDK关联

(3) 在Android项目中生命所需要调用的Native方法

(4) 使用Android需要交互的本地代码,实现在Android中声明的Native方法,比如Android需要与C++交互,那么就用C++实现Java的Native方法

(5) 通过ndk-build命令编译产生.so库文件

(6) 编译Android Studio工程,从而实现Android 调用本地代码

6.额外注意点:

三:NDK与JNI关系:

1.NDK与JNI关系:NDK可以为我们生成了C/C++的动态链接库,JNI是java和C/C++沟通过的接口,两者与android没有半毛钱关系,只因为安卓是java程序语言开发,然后通过JNI又能与C/C++沟通,所以我们可以使用NDK+JNI来实现Java+C的开发方式。

2.使用NDK开发的好处:

(1) 项目需要调用底层的一些C/C++的一些东西(java无法直接访问到操作系统底层(系统硬件等)),或者已经在C/C++环境下实现了功能代码(大部分现存的开源库都是用C/C++代码编写的。)直接使用即可

(2) 为了效率更加高效些。将要求高性能的应用逻辑使用C/C++开发,从而提高应用程序的执行效率。但是C/C++代码虽然是高效的,在java与C/C++相互调用时却增大了开销

(3) 基于安全性考虑。防止代码被反编译,为了安全起见,使用C/C++语言来编写重要的部分以增大系统的安全性,最后生成so库(用过第三方库的应该都不陌生)便于给人提供方便

(4) 便于移植。用C/C++写的库可以方便在其他的嵌入式平台上再次使用

四:配置及具体使用

1.下载安装NDK:NDK的下载方式有两种方式,可以直接去 https://developer.android.com/ndk/downloads?hl=zh-cn;另一种就是直接在我们的Android Studio中下载,打开我们Studio项目下的Project Structure界面,如下:

在SDK Location目录下,有SDK和NDK的路径,我这里已经安装NDK。如果还没有安装配置过NDK,Android Studio会提示下载Android NDK如下图:

点击Download Android NDK来进行下载。这里Android Studio会下载最新版本的NDK进行安装,默认会下载保存在SDK的路径下。我们在上图中还能看到有一段介绍文字,说SDK以及NDK的路径配置会保存在local.properties文件内,安装完成后我们刷新Project,进local.properties文件查看也能看到SDK与NDK的路径。

注意:以前有些版本需要在gradle.properties文件中加上一行  android.useDeprecatedNdk=true ,3.0版本不再支持了。

2.添加插件:为了省去控制台输入命令麻烦。我们借助强大的Android Studio的插件功能,在External Tools下配置两个非常有用的插件。进入Setting->Tools->ExternalTools,点击+号增加,如下图:

3.javah -jni命令:根据java文件生成.h头文件,会自动根据java文件中的类名(包含包名)与方法名生成对应的C/C++里面的方法名。

参数及其含义:

(1) Program:$JDKPath$\bin\javah\java.exe这里配置的是JDK目录下的javah.exe的路径

(2) Parametes:-classpath .-jni -d $ModuleFileDir$/src/main/jni $FileClass$ 这里$FileClass$指的是要执行操作的类名(类的全名(包名+类名))(即我们操作的文件),$ModuleFileDir$/src/main/jni表示生成的文件保存在这个module目录的src/main/jni目录下

(3) Working :$ModuleFileDir$\src\main\java表示module目录下的src\main\java目录。使用方式:选中java文件->右键->External Tools->javah -jni,将生成jni文件夹以及文件夹下的包名.类名的.h头文件(名字有点长,可以自己重命名)

4.ndk-build命令:

ndk -build命令,是根据C/C++文件生成so文件的,具体参数配置及其含义:

(1) Program:F:\apk\sdk\ndk-bundle\ndk-build.cmd这里配置的是ndk下的ndk-build.cmd的路径(根据实际情况填写)

(2) Working:$ModuleFileDir$\src\main\

5.使用方法:选中C/C++文件->右键->External Tools->ndk-build,将在main文件夹下生成libs文件夹以及多个so文件,我们可以移动至jniLibs目录下去,接下来通过一个简单的实例来了解它的使用。

(1) 创建Java类:随意创建一个访问本地C/C++方法的java类:

        public class JniTest {

        /** * 将用C++代码实现,在android代码中调用的方法:获取一段文字 */ public static native String        getStrFromC();

        /** * 配置加载的so库的文件名字===>如 :libmyLib.so */

        static { 

        System.loadLibrary("myLib");

            }

        }

(2) 该类的getStrFromC会报错提示,不用管。

生成.h头文件:对该文件执行javah -jni操作,生成对应的.h头文件。

如图,已经根据我们的java类在jni文件夹下生成了对应的.h文件,文件名为包名类名.h,我们可以手动改.h文件名,里面只有一个方法,返回值为String(jstring),方法名为java类的包名类名方法名(包名中的分级不是用.而是_),前面两个参数是C++里面必须有的(JNIEnv代表指向JVM的指针,jclass是调用该方法的java对象),第三个jobject就是我们java类的方法里面的参数Object。注意,这是java函数与C++函数对应的静态注册方法,即通过特定的规则来写。此处方法名可以随意起名字,然后还可以用动态注册的方式关联两个方法。

(3) 创建C或C++文件:在jni文件夹下,新建一个.c(c语言)或者.cpp(C++)的文件,来实现.h文件里声明的方法:把.h文件里面声明的方法拷贝到新建的c文件里面,然后在文件里面引入.h文件,如下图:

至此,.h文件和c++文件已完成,想生成so文件还需要在这个jni目录下增加两个文件,Android.mk和Application.mk。

注意LOCAL_MODULE的值与之前的java类中设置要生成so库的名字相对应,LOCAL_SRC_FILES的值写C++文件的名字,这两个值成对设置,可设置多组。(:=是赋值的意思,$是引用某变量的值)

LOCAL_PATH := $(call my-dir)    // 设置当前的编译目录(Android.mk所在的目录)

include $(CLEAR_VARS)            // 清除LOCAL_XX变量(LOCAL_PATH除外)

LOCAL_MODULE := myLib // 指定当前编译模块的名称 

LOCAL_SRC_FILES := jnittest.c    // 编译模块需要的源文件

include $(BUILD_SHARED_LIBRARY)

// 指定编译出的库类型,BUILD_SHARED_LIBRARY:动态库;BUILD_STATIC_LIBRARY:静态库, BUILD_EXECUTEABLE指:可执行文件

在一个Android.mk文件中配置多个Module的方式如下(include $(CLEAR_VARS)、include $(BUILD_SHARED_LIBRARY)两个语句也需要加上)

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := myLib

LOCAL_SRC_FILES := jnittest.c

include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := myLib2

LOCAL_SRC_FILES := jnittest2.c

include $(BUILD_SHARED_LIBRARY)

Application.mk,APP_ABI有四种类型(默认armeabi),armeabi、armeabi-v7a、x86、mips,设置时以空格隔开,all表示所有。该文件中有个可选配置的APP_MODULES,类似于上面Android.mk文件中的LOCAL_MODUEL,以空格隔开,且会覆盖掉Android.mk文件中的LOCAL_MODULE设置(比如Android.mk文件中的写了两个jni库的配置,LOCAL_MODULE:=JNI1、LOCAL_MODULE:=JNI2,而Application.mk中设置的APP_MODULES:=JNI1,则只能生成JNI1的so文件,要生成JNI2的so文件的时候会报错,除非写成APP_MODULE:=JNI1 JNI2,这里我们直接省略默认使用Android.mk中的)

APP_ABI := all,生成so文件对C++文件执行ndk-build操作,生成相应的so文件

如图,在main/libs目录下生成了多个so文件,名字为lib+我们指定的库名(同时还生成了obj文件夹,中间文件)。这时候我们可以生成的main/libs文件夹内的东西复制到app/libs下,并删除main下新生成的jni、libs、obj三个文件夹。

配置app/gradle:

调用在Activity中测试调用,在TextView上显示我们通过C++代码实现的方法getStrFromC获取字符串。

                                                如有侵权,请及时于我联系

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

推荐阅读更多精彩内容