NDK与JNI开发(1)ndk_build方式开发

简介: NDK与JNI开发(1)ndk_build方式开发

一:概述

Android的开发主要是基于java语言进行开发的,所以导致了用Android SDK进行开发的工程师们都必须使用Java语言。但是Android 平台从一开就已经支持了C/C++了,Google从一开始就说明Android也支持JNI编程方式,也就是第三方应用完全可以通过JNI调用自己的C动态库。

二:NDK

1.什么是ndk

ndk官网的描述如下

关键字: Android NDK 是一套允许您使用原生代码语言(例如C和C++) 实现部分应用的工具集。在开发某些类型应用时,这有助于您重复使用以这些语言编写的代码库

简单来说: Android NDK 就是一套工具集合,允许你使用C/C++语言来实现应用程序的部分功能

NDK 是Native Develop Kit的含义,从含义很容易理解,本地开发。大家都知道,Android 开发语言是Java,不过我们也知道,Android是基于Linux的,其核心库很多都是C/C++的,比如Webkit等。那么NDK的作用,就是Google为了提供给开发者一个在Java中调用C/C++代码的一个工作。NDK本身其实就是一个交叉工作链,包含了Android上的一些库文件,然后,NDK为了方便使用,提供了一些脚本,使得更容易的编译C/C++代码。总之,在Android的SDK之外,有一个工具就是NDK,用于进行C/C++的开发。一般情况,是用NDK工具把C/C++编译为.co文件,然后在Java中调用。

NDK不适用于大多数初学的Android工程师,对于许多类型的Android应用没有什么价值。因为它不可避免地会增加开发过程的复杂性,所以一般很少使用。那为什么Google还提供NDK,我们就一起研究下

2.为什么使用NDK

1、在平台之间移植其应用

2、重复使用现在库,或者提供其自己的库重复使用

3、在某些情况下提性能,特别是像游戏这种计算密集型应用

4、使用第三方库,现在许多第三方库都是由C/C++库编写的,比如Ffmpeg这样库。

5、不依赖于Dalvik Java虚拟机的设计

6、代码的保护。由于APK的Java层代码很容易被反编译,而C/C++库反编译难度大。

3.NDK到so

从上图这个Android系统框架来看,我们上层通过JNI来调用NDK层的,使用这个工具可以很方便的编写和调试JNI的代码。因为C语言的不跨平台,在Mac系统的下使用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

4.ndk环境搭建

第一种:下载好ndk,然后再as项目中配置

ndk下载地址: https://developer.android.google.cn/ndk/downloads/

选择适合自己需求的ndk,下载解压到指定目录,路径不要出现空格和中文。也可配置到全局路径path中方便全局使用命令

打开电脑属性

配置环境变量

注意:我这里是在用户变量里面配置的,当然你也可以在系统变量中配置

打开cmd输入ndk-build,配置成功

 

接下来就是给开发工具AS关联NDK

打开as在项目的local.properties配置文件中增加下面代码

ndk.dir=D\:\\android-ndk-r20

在gradle.properties中配置如下代码 用于兼容旧版本的NDK

android.useDeprecatedNdk=true

第二种:在AS中直接指定路径配置

在Studio中下载与配置NDK:Settings–Appearance & Behavior–System Settings–Android SDK–SDK Tools。

自此ndk环境配置完成,接下来就是编写ndk开发流程以及JNI结合,详见下文

三:JNI

1.什么是JNI

JNI(Java Native Interface,JNI)java本地开接口。相当于桥梁,是一种协议,通过jni可以达到java调用c/c++,c/c++调用java,即在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行互操作。它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。通俗来说,就是JAVA调用C/C++函数的接口.如果你要想调用C系列的函数,你就必须遵守这样的约定.JNI 最重要的好处是它没有对底层 Java 虚拟机的实现施加任何限制。因此,Java 虚拟机厂商可以在不影响虚拟机其它部分的情况下添加对 JNI 的支持。程序员只需编写一种版本的本地应用程序或库,就能够与所有支持 JNI 的 Java 虚拟机协同工作。

提高效率:加密算法、图像处理、机器视觉等需要大量计算的逻辑,可以在C/C++中实现;

扩展JVM:扩展JVM的功能;

代码复用:复用C/C++平台上的代码,避免重复在Java上重复造轮子;

四:ndk+JNI开发

在NDK的开发过程中,有两种形式——ndk-build和CMake,其实两种方式最终的目的都是一样,将C 或 C++(“原生代码”)嵌入到 Android 应用。只是CMake使用起来更加方便,同时Android官方也推荐在Android Studio 2.2及以上使用CMake。工具的本质就是方便人们进行日常活动,对比一下两者流程,方便开发过程进行技术选型。

ndk-build方式进行ndk和jni开发

a. java目录下的java类中写native方法

public class JNI {
    static {
        System.loadLibrary("hello");
    }
    /**
     * 在java类中定义一个native方法
     * native 方法书写方式,类似于接口,但需要有关键字 native
     * @return
     */
    public static native String sayHello();
}

b. src---> main 下创建 jni 文件夹,并在其下创建三个文件

c. 编写 .c或.cpp文件

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
/*返回类型:返回java中对应的类型,
*类名:Java_全路径_方法名
参数:JNIEnv *env 里面有很多方法,jobject obj表示谁调用这个方法就是谁的实例 当前是JNI.this
*/
//其中extern “C” 声明,是为了说明可能会用到 C 的代码
extern "C" {
/*
(1)函数名:JNIEXPORT + 返回类型 + JNICALL Java_+包名 + 类型 + 函数名(java中声明的),以下划线连接
(2)返回值类型,是 jni 中的数据类型,若没有返回类型,则使用 void
(3)默认传入两个参数 JNIEnv* env(jvm运行环境), jobject obj(调用这个函数的Java对象)
*/
  JNIEXPORT jstring JNICALL Java_com_javayihao_demo_JNI_sayHello(JNIEnv *env,jobject obj){
     const char* text="hello jni";
      return (*env)->NewStringUTF(env,text);
  }
}

 

d. 配置编译环境

(1)Android.mk文件
.cpp 文件为 hello.cpp,对应的库的名字为  hello ,即生成的 so 为  hello .so

LOCAL_PATH := $(call my-dir) 指定cpp文件位置
 
include $(CLEAR_VARS) #编译时清除旧库
 
LOCAL_MODULE    := lib
LOCAL_PATH := $(call my-dir) 指定cpp文件位置
 
include $(CLEAR_VARS) #编译时清除旧库
 
LOCAL_MODULE    := libhello #生成so的名字,前面加lib
LOCAL_SRC_FILES := hello.cpp #需要编译的cpp文件
 
include $(BUILD_SHARED_LIBRARY) #注明生成动态库 #生成so的名字,前面加lib
LOCAL_SRC_FILES := hello.cpp #需要编译的cpp文件
 
include $(BUILD_SHARED_LIBRARY) #注明生成动态库

 

(2)Application.mk文件

这个文件中一般进行ABI管理,告诉ndk-build生成适用于那些CPU指令集的库文件,=all就是编译生成所有CPU指令集的库文件

APP_ABI :=all

 

(3)build.gradle 配置

Android{
 
  ...
 
  externalNativeBuild{
        //指定Android.mk文件
        ndkBuild{
            path 'src/main/jni/Android.mk'
        }
    }
 
    //生成so到指定路径下
    sourceSets{
        main{
            jni.srcDirs = []
            jniLibs.srcDirs = ['libs']
        }
    }
}

 

 

 

 

 


相关文章
|
6月前
|
Java API Android开发
[NDK/JNI系列01] NDK与JNI的基本概念与使用场景
[NDK/JNI系列01] NDK与JNI的基本概念与使用场景
68 0
|
1月前
|
编译器 Android开发
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
|
6月前
|
传感器 Java 开发工具
[NDK/JNI系列03] Android Studio集成NDK开发环境
[NDK/JNI系列03] Android Studio集成NDK开发环境
64 0
|
Android开发 C语言
Android Studio NDK 代码 Source Insight调试 (NDK 目前开发方案 | NDK 编译 | 导入 so 库 | 项目编码转换)(一)
Android Studio NDK 代码 Source Insight调试 (NDK 目前开发方案 | NDK 编译 | 导入 so 库 | 项目编码转换)(一)
366 0
Android Studio NDK 代码 Source Insight调试 (NDK 目前开发方案 | NDK 编译 | 导入 so 库 | 项目编码转换)(一)
|
Android开发
【Android NDK 开发】Android Studio 使用 CMake 导入静态库 ( CMake 简介 | 构建脚本路径配置 | 引入静态库 | 指定静态库路径 | 链接动态库 )(二)
【Android NDK 开发】Android Studio 使用 CMake 导入静态库 ( CMake 简介 | 构建脚本路径配置 | 引入静态库 | 指定静态库路径 | 链接动态库 )(二)
399 0
|
Android开发 C++
【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 拷贝 lib7zr.so 动态库到 Android Studio 工程 | 配置 build.gradle 构建脚本 )
【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 拷贝 lib7zr.so 动态库到 Android Studio 工程 | 配置 build.gradle 构建脚本 )
154 0
【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 拷贝 lib7zr.so 动态库到 Android Studio 工程 | 配置 build.gradle 构建脚本 )
|
Java Android开发 C++
【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )(一)
【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )(一)
333 0
【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )(一)
|
Java 编译器 Linux
【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )(二)
【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )(二)
314 0
【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )(二)
|
Android开发 C++
【Android FFMPEG 开发】Android Studio 工程配置 FFMPEG ( 动态库打包 | 头文件与函数库拷贝 | CMake 脚本配置 )(二)
【Android FFMPEG 开发】Android Studio 工程配置 FFMPEG ( 动态库打包 | 头文件与函数库拷贝 | CMake 脚本配置 )(二)
222 0
【Android FFMPEG 开发】Android Studio 工程配置 FFMPEG ( 动态库打包 | 头文件与函数库拷贝 | CMake 脚本配置 )(二)
|
Ubuntu 编译器 Android开发
【Android FFMPEG 开发】Android Studio 工程配置 FFMPEG ( 动态库打包 | 头文件与函数库拷贝 | CMake 脚本配置 )(一)
【Android FFMPEG 开发】Android Studio 工程配置 FFMPEG ( 动态库打包 | 头文件与函数库拷贝 | CMake 脚本配置 )(一)
223 0
【Android FFMPEG 开发】Android Studio 工程配置 FFMPEG ( 动态库打包 | 头文件与函数库拷贝 | CMake 脚本配置 )(一)