一、NDK

什么是NDK?

在Android OS上开发应用程序,Google提供了两种开发包:SDK和NDK。

NDK---全称:Native Develop Kit,是Android的一个工具开发包

Android的开发语言是Java,而且Android是基于Linux的,其核心库很多都是C/C++代码的一个工作。NDK其实本身其实就是一个交叉工作链,包含了Android上的一些库文件,而且NDK为了方便使用,提供了一些脚本,使得更容易编译C/C++代码。简单的来说,Android NDK就是一套工具集合,允许你使用C/C++语言来实现应用程序的部分功能。

为什么要使用NDK?NDK的优点?


NDK特点.png

作用

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

应用场景

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

额外注意

NDK提供了把.so和.apk打包的工具,而JNI开发没有,只是把.so文件放到文件按系统的特定位置

NDK提供的库有限,仅用于处理算法效率和处理敏感的问题

提供了交叉编译器,用于生成特定的CPU平台动态库

NDK到SO

因为C语言的不跨平台性,需要使用NDK编译Linux下能执行的函数库---so文件(其本质就是一堆C、C++的头文件和实现文件打包成一个库)目前Android系统支持以下七种不用的CPU架构,每一种对应着各自的应用程序二进制接口ABI:(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。对应关系如下:

ARMv5——armeabi

ARMv7 ——armeabi-v7a

ARMv8——arm64- v8a

x86——x86

MIPS ——mips

MIPS64——mips64

x86_64——x86_64


二、JNI

什么是JNI?

JNI,全称:Java Native Interfave,即Java本地接口,JNI是Java调用Native语言的一种特性。通过JNI可以使得Java与C/C++交互,即可以在Java代码中调用C/C++等语言的代码或者在C/C++代码中调用Java代码。

但是开发JNI程序会受到系统环境限制,因为用C/C++ 语言写出来的代码或模块,编译过程当中要依赖当前操作系统环境所提供的一些库函数,并和本地库链接在一起。而且编译后生成的二进制代码只能在本地操作系统环境下运行,因为不同的操作系统环境,有自己的本地库和CPU指令集,这个时候就需要NDK将本地代码在不同的操作系统平台下编译出相应的动态库。

为什么需要JNI

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

作用

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

JNI开发流程6步骤

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

特别注意

1.JNI是java调用Native语言的一种特性

2.JNI是属于java的,与Android无直接关系


三、在Android studio中配置---我使用的是Android studio3.4.1

1.下载NDK

首先找到studio右上角的SDK Manager 并点击

SDK Manager.png

然后找到下方的SDK tools,找到LLDB,CMake,NDK下载,然后apply 和OK 即可

NDK下载.png

接着找到我们的SDK location,然后将NDK的路径填写在红框中的地方,如果是studio中下载的SDK,路径就在配置的sdk文件夹中,配置好后点击OK 即可

配置NDK路径.png

SDK以及NDK的路径配置会保存在local.properties文件内,安装完成后刷新Project,进local.properties文件查看就能看到SDK与NDK的路径。

local.properties中查看NDK和SDK的路径.png

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

2.添加插件

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

javah -jni命令

Androidstudio添加插件.png javah -jni命令.png

javah -jni命令,根据java文件生成.h头文件,会自动根据java文件中的类名(包含包名)与方法名生成对应的C/C++里面的方法名。下面是参数配置及其含义:

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

2.Arguments:-classpath $ModuleFileDir$\src\main\java -jni -d $ModuleFileDir$\src\main\jni $FileClass$

注:在老版本的studio中没有Arguments,为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头文件(名字有点长,可以自己重命名)。

ndk -build命令

ndk -build命令.png

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

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

2.Working:$ModuleFileDir$\src\main\

使用方法:选中C/C++文件->右键->External Tools->ndk-build,将在main文件夹下生成libs文件夹以及多个so文件,我们可以移动至jniLibs目录下去。

四、简单使用

1.创建java类随意创建一个访问本地C/C++方法的java类,生成.h头文件,然后对该文件执行javah -jni操作,生成对应的.h头文件。

创建.h文件


生成的.h文件

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

2.创建c或c++文件

在jni文件夹下,新建一个.c(c语言)或者.cpp(C++)的文件,来实现.h文件里声明的方法:

把.h文件里面声明的方法拷贝到新建的c文件里面,然后在文件里面引入.h文件,如下图:

.c文件

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

Android.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文件

在一个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

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文件


生成so文件


so文件

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

在项目的build.gradle中配置app/gradle

配置so文件

调用

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

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

 static {  

       System.loadLibrary("myLib");

 }

使用

Android studio 下载NDK和构建工具

1.Android原生开发工具包(NDK):这套工具集允许您开发Android使用C和C++代码,并提供众多平台库,让您可以管理原生Activity和访问物理设备组件,例如传感器和触摸输入。

2.CMake:一款外部构建工具,可与Gradle搭配使用来构建原生库。如果您只计划使用ndk-build,则不需要此组件。

3.LLDB:一种调试程序,Android Studio使用它来调试原生代码。

注:在前面下载ndk的时候已经提示过如何下载

创建支持C/C++的新项目

创建支持原生代码的项目与创建任何其他Android Studio项目类似,不过支持原生代码的项目还需要额外几个步骤:

1.在向导的Configure your new project部分,选中Include C++ Support复选框。

2.点击Next。

3.正常填写所有其他字段并完成向导接下来的几个部分。

4.在向导的Customize C++ Support部分,您可以使用下列选项自定义项目


1.C++ Standard:使用下拉列表选择您希望使用哪种C++标准。选择 Toolchain Default 会使用默认的CMake 设置,这个选项如果你现在还不确定该选哪个,最好选择C++11的标准。

2.Exceptions Support:如果您希望启用对C++异常处理的支持,请选中此复选框。如果启用此复选框,Android Studio 会将 -fexceptions 标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake。

3.Runtime Type Information Support:如果您希望支持RTTI,请选中此复选框。如果启用此复选框,Android Studio 会将 -frtti 标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake。

更多相关文章

  1. 使用Kotlin:让Android与JS交互的详解
  2. 在Android中用纯Java代码布局
  3. Android(安卓)虚拟机Dalvik、Android各种java包功能、Android相
  4. 【Android(安卓)开发】: Android(安卓)消息处理机制之三: Handle
  5. android实现横竖屏不间断播放文件
  6. Android(安卓)mediaplayer 播放本地音乐文件
  7. Android(安卓)上实现水波特效二--优化
  8. Android(安卓)NDK开发(一)——ndk-build编译生成so库文件并使用
  9. NPM 和webpack 的基础使用

随机推荐

  1. Android UI - 带白边的自定义ImageView效
  2. android多媒体播放相关网址
  3. android中查看Activity的栈的的内容
  4. Android PhoneStateListener 问题
  5. Android开源项目第一篇——个性化控件(Vi
  6. Android获取本机局域网IP的方法
  7. Android中DIP与PX的转换
  8. Android Gesture 手势识别
  9. Android P 版本中支持全面屏检测的api
  10. Android 多线程2