JNI 与 NDK 入门(一)

JNI 与 NDK 入门(一),快醒醒吧 } } } dependencies { implementation fileTree(dir: ‘libs’, include: [’*.jar’]) implementation ‘com.android.support:appcompat-v7:27.1.1’ implementation ‘com.android.support.constraint:constraint-layout:1.1.3’ testImplementation ‘junit:junit:4.12’ androidTest 阅读详情

JNI

概念

JNI是Java Native Interface的简写,它可以使Java与其他语言(如C、C++)进行交互。

它是Java调用Native语言的一种特性,属于Java语言的范畴,与Android无关。

为何需要JNI

  • Java的源文件非常容易被反编译,而通过Native语言生成的.so库文件则不容易被反编译。
  • 有时我们使用Java时需要使用到一些库来实现功能,但这些库仅仅提供了一些Native语言的接口。
  • 使用Native语言编写的代码运行效率高,尤其体现在音频视频图片的处理等需要大量复杂运算的操作上。充分利用了硬件的性能。

由于上述原因,此时我们就需要让Java与Native语言交互。而由于Java的特点,与Native语言的交互能力很弱。因此在此时,我们就需要用到JNI特性增强Java与Native方法的交互能力。

实现的步骤

  1. 在Java中声明Native方法(需要调用的本地方法)
  2. 通过 javac 编译 Java源文件( 生成.class文件)
  3. 通过 javah 命令生成JNI头文件(生成.h文件)
  4. 通过Native语言实现在Java源码中声明的Native方法
  5. 编译成.so库文件
  6. 通过Java命令执行 Java程序,最终实现Java调用本地代码(借助so库文件)

NDK

概念

Native是Native Development Kit的简写,是Android的开发工具包,属于Android,与Java无关系。

它可以快速开发C/C++的动态库,自动将.so和应用一起打包为APK。因此我们可以通过NDK来在Android开发中通过JNI与Native方法交互。

使用方式

  1. 配置 Android NDK环境(在SDK Manager中下载NDK、CMake、LLDB)
  2. 创建 Android 项目,与 NDK进行关联(创建项目时选择C++ support)
  3. 在 Android 项目中声明所需要调用的 Native方法
  4. 用Native语言实现在Android中声明的Native方法
  5. 通过 ndk-bulid 命令编译产生.so库文件

将Android项目与NDK关联

配置NDK路径

在local.properties中加入如下一行即可

ndk.dir=<ndk路径>

添加配置

在Gradle的 gradle.properties中加入如下一行,目的是对旧版本的NDK支持

android.useDeprecatedNdk=true

添加ndk节点

在build.gradle中的defaultConfig和android中加入如下的externalNativeBuild节点

apply plugin: 'com.android.application'

android {

    compileSdkVersion 27

    defaultConfig {

        applicationId "com.n0texpecterr0r.ndkdemo"

        minSdkVersion 19

        targetSdkVersion 27

        versionCode 1

        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        externalNativeBuild {

            cmake {

                cppFlags ""

            }

        }

    }

    buildTypes {

        release {

            minifyEnabled false

            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }

    }

    externalNativeBuild {

        cmake {

            path "CMakeLists.txt"

        }

    }

}

dependencies {

    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'com.android.support:appcompat-v7:27.1.1'

    implementation 'com.android.support.constraint:constraint-layout:1.1.3'

    testImplementation 'junit:junit:4.12'

    androidTestImplementation 'com.android.support.test<span class="emoji emoji-sizer" style="background-image:url(/emoji-data/img-apple-64/1f3c3.png)" data-codepoints="1f3c3"></span>1.0.2'

    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

}

开发Native代码

在Java文件中声明native方法

我们首先需要在Java代码的类中通过static块来加载我们的Native库。可以通过如下代码,其中loadLibrary的参数是在CMakeList.txt中定义的Native库的名称

static {

    System.loadLibrary("native-lib");

}

之后,我们便可以在这个类中声明Native方法

public native String getStringFromJNI();

创建CMakeList.txt

我们还需要在src中创建一个CMakeList.txt文件,这个文件约束了Native语言源文件的编译规则。比如下面

cmake_minimum_required(VERSION 3.4.1)

add_library(native-lib SHARED src/main/cpp/native-lib.cpp)

find_library(log-lib log)

target_link_libraries(native-lib ${log-lib})

add_library方法中定义了一个so库,它的名称是native-lib,也就是我们在Java文件中用到的字符串,而后面则跟着这个库对应的Native文件的路径

find_library则是定义了一个路径变量,经过了这个方法,log-lib这个变量中的值就是Android中log库的路径

target_link_libraries则是将native-lib这个库和log库连接了起来,这样我们就能在native-lib中使用log库的方法。

创建Native方法文件

在前面的CMake文件中可以看到,我们把文件放在了src/main/cpp/,因此我们创建cpp这个目录,在里面创建C++源文件native-lib.cpp。

然后, 我们便可以开始编写如下的代码:

#include <jni.h>

#include <string>

extern "C"{

  JNIEXPORT jstring JNICALL

  Java_com_n0texpecterr0r_ndkdemo_MainActivity_getStringFromJNI(

      JNIEnv* env,

      jobject) {

    std::string hello = "IG牛逼";

    return env->NewStringUTF(hello.c_str());

  }

}

此处我们使用的是C++语言,让我们来看看具体的代码。

首先我们引入了jni需要的jni.h,这个头文件中声明了各个jni需要用到的函数。同时我们引入了C++中的string.h。

然后我们看到extern "C"。为了了解这里为什么使用了extern "C",我们首先需要知道下面的知识:

在C中,编译时的函数签名仅仅是包含了函数的名称,因此不同参数的函数都是同样的签名。这也就是为什么C不支持重载。

而C++为了支持重载,在编译的时候函数的签名除了包含函数的名称,还携带了函数的参数及返回类型等等。

试想此时我们有个C的函数库要给C++调用,会因为签名的不同而找不到对应的函数。因此,我们需要使用extern "C"来告诉编译器使用编译C的方式来连接。

接下来我们看看JNIEXPORT和JNICALL关键字,这两个关键字是两个宏定义,他主要的作用就是说明该函数为JNI函数。

而jstring则对应了Java中的String类,JNI中有很多类似jstring的类来对应Java中的类,下面是Java中的类与JNI类型的对照表

我们继续看到函数名Java_com_n0texpecterr0r_ndkdemo_MainActivity_getStringFromJNI。其实函数名中的_相当于Java中的 . 也就是这个函数名代表了java.com.n0texpecterr0r.ndkdemo.MainActivity.java中的getStringFromJNI方法,也就是我们之前定义的native方法。

格式大概如下:

Java_包名_类名_需要调用的方法名

其中,Java必须大写,包名里的.要改成_,_要改成_1

接下来我们看到这个函数的两个参数:

  • JNIEnv* env:代表了JVM的环境,Native方法可以通过这个指针来调用Java代码
  • jobject obj:它就相当于定义了这个JNI方法的类 (MainActivity) 的this引用

然后可以看到后面我们创建了一个string hello,之后通过env->NewStringUTF(hello.c_str())方法创建了一个jstring类型的变量并返回。

在Java代码中调用native方法

接着,我们便可以在MainActivty中像调用Java方法一样调用这个native方法

TextView tv = findViewById(R.id.sample_text);

tv.setText(getStringFromJNI());

我们尝试运行,可以看到,我们成功用C++构建了一个字符串并返回给Java调用:

[图片上传失败...(image-cf0641-1628687485525)]

CMake

我们在NDK开发中使用CMake的语法来编写简单的代码描述编译的过程,由于这篇文章是讲NDK的,所以关于CMake的语法就不再赘述了。。。如果想要了解CMake语法可以学习这本书《CMake Practice》

JNI与Java代码交互

方法签名

概念

在我们JNI层调用一个方法时,需要传递一个参数——方法签名。

为什么要使用方法签名呢?因为在Java中的方法是可以重载的,两个方法可能名称相同而参数不同。为了区分调用的方法,就引入了方法签名的概念。

签名规则

对于基本类型的参数,每个类型对应了一个不同的字母:

  • boolean Z
  • byte B
  • char C
  • short S
  • int I
  • long J
  • float F
  • double D
  • void V

对于类,则使用 L+类名 的方式,其中(.)用(/)代替,最后加上分号

比如 java.lang.String就是 Ljava/lang/String;

对于数组,则在前面加 [ ,然后加类型的签名,几维数组就加几个。

比如 int[]对应的就是[I , boolean[][]对应的则是[[Z,而java.lang.String[]就是[Ljava/lang/String;

打印方法签名

我们可以通过 javap -s 命令来打印方法的签名。

例子

比如下面的方法

public native String getMessage();

public native String getMessage(String id,long i);

对应的方法签名分别为:

()Ljava/lang/String;

(Ljava/long/String;J)Ljava/lang/String;

可以看到,前面括号中表示的是方法的参数列表,后面表示的则是返回值。

今天就先肝这么多,明天再说

文章每周持续更新,可以微信搜索「 程序员喵大人 」第一时间阅读和催更(比博客早一到两篇哟),本文GitHub已经收录,有一线大厂面试点思维导图,也整理了很多我的文档,欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。

Android Studio NDK开发案例一 JNI开发入门         最近在做Android的项目,用到了JNI,现将NDK的开发流程和方法整理出来,希望能够让刚接触的小伙伴们少走一些弯路。 NDK         Native Development Kit(NDK)是一系列工具的集合。它提供了一系列的工具,帮助开发者快速开发C/C++的动态库,并能自动将so和java一起打包成apk。 JNI         Java Native In... 阅读详情

相关推荐

Android Studio中NDK与JNI开发入门指南

Java Native Interface (JNI) 是一个编程框架,允许Java代码和其他语言写的代码(主要是C和C++)进行交互。其定义了一个标准的编程接口,使得Java虚拟机(JVM)中的Java代码能够调用本地应用程序接口(API)中的本地方法(用C、C++或其他语言实现的方法),以及反过来实现本地方法调用Java对象和其方法。JNI不仅提供了一种机制来调用本地方法,同时也需要一种方式来处理不同数据类型之间的转换。

weixin_32099703的博客 1310

[转]Android:JNI 与 NDK到底是什么?(含实例教学)

在Android开发中,使用NDK开发的需求正逐渐增大但很多人却搞不懂JNI与NDK到底是怎么回事今天,我将先介绍JNI与NDK& 之间的区别,手把手进行NDK的使用教学,希望你们会喜欢,即Java本地接口作用: 使得Java与 本地其他类型语言(如C、C++)交互即在Java代码 里调用C、C++等语言的代码 或C、C++代码调用Java代码特别注意:JNI是Java调用Native语言的一种特性JNI是属于Java的,与Android无直接关系,是Android的一个工具开发包。

空名先生 1319

从零搭建医疗化验单识别系统:深度学习+OCR实战教程(附数据集)

本文详细介绍了如何从零开始构建一个医疗化验单智能识别系统。通过融合深度学习和OCR技术,系统能够应对版式多样、内容专业的医疗单据,实现从文本检测、识别到关键信息结构化抽取的全流程。文章提供了数据集处理、模型选型、训练微调及工程化部署的实战指南,并分享了避坑经验与性能优化策略,为开发者解决医疗信息化痛点提供了完整的技术方案。

k9l0m1的博客 492

音视频开发(十五):JNI与NDK的学习和使用

目录 什么是JNI、NDK? Java和Native交互流程 通过AS创建Native CPP简单的项目 JNI基础知识介绍 实现JAVA和Native的相互调用 一、什么是JNI、NDK? JNI:Java Native Interface(java本地接口),使得Java与本地语言( C、CPP)相互调用 NDK:Native Development Kit,是Android的一个工具开发包,帮助开发者快速开发C、CPP动态库,自动将动态库打包进入A

m0_60259116的博客 3621

告别手动调参!PSCAD 4.2的Multiple-Run功能,5分钟搞定交流故障批量仿真

本文详细介绍了PSCAD 4.2的Multiple-Run功能如何高效处理交流故障批量仿真,告别传统手动调参的低效模式。通过五步配置法,工程师可在5分钟内完成数百次参数组合的仿真,显著提升电力系统分析效率。文章还包含工业级应用案例和高级调试技巧,助力实现故障仿真的自动化与智能化。

weixin_42552716的博客 275

Chapter2、HDR流水线

HDR内容的获取(不同曝光时间的图片合成) 相机响应函数 HDR视频

qq_55621259的博客 2597

Android Studio 进行NDK开发,实现JNI,以及编写C++与Java交互(Java调用本地函数)并编译出本地so动态库

NDK集成了交叉编译器(交叉编译器需要UNIX或LINUX系统环境),并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。就会生成两个文件这几个so文件,如下图一,然后就能正常获取到C++文件(也就是cpp文件)中的数据了,还可以把so动态库提供给第三方使用,具体方式详见。在android的JNI中,要先将相应的C/C++打包成so库,然后导入到lib文件夹中供java调用。(5)安卓中的so文件是什么?

UrasakiNakajima的博客 8428

UniApp实战:从文件下载到本地保存与预览的一站式解决方案

本文深入解析了UniApp开发中文件下载、保存与预览的完整流程,提供了基于uni.downloadFile、uni.saveFile和uni.openDocument API的一站式实战解决方案。文章详细拆解了核心API的使用方法、多平台(App、H5)的兼容性处理、常见坑点(如文件路径、权限、格式支持)以及进阶优化技巧(如进度提示、文件管理),旨在帮助开发者构建健壮、用户体验良好的跨平台文件处理功能。

d3e4f的博客 614

【Android】之【NDK】【JNI】

Android NDK&JNI 实践

Crazy程序猿 999

损失函数大汇总(五十九)(TopoInteraction Loss附公式推导与代码)

本文介绍了TopoInteraction Loss,一种用于多类别分割任务的拓扑交互约束损失函数。不同于传统拓扑损失关注单类别的连通性和孔洞数量,该损失重点约束不同类别之间的空间关系,包括互斥(exclusion)和包含(containment)两种典型拓扑关系。通过将全局拓扑约束转化为局部邻接检测,该损失能准确定位破坏预设拓扑关系的像素,并针对性施加惩罚。关键创新点在于:1)将包含关系转化为互斥约束;2)使用卷积运算高效检测非法邻接;3)仅对违规像素施加损失。实验表明,该方法能有效纠正类别间的错误接触,特

悦学共鸣,温柔以待,汇聚光芒,共同成长 350

Maestro 薛定谔软件简单分子对接案例

#参考:Maestro 薛定谔软件使用:Maestro 薛定谔对接:sid=287811。

weixin_42357472的博客 1万+

JNI和NDK的详解(上)

前言 1.什么是JNI? Java本地开发接口 英文全称是 Java native interface jni是一个协议。这个协议用来沟通Java代码和外部的本地代码(c/c++),通过这个协议 ,Java代码可以外部的c/c代码 ,外部的c/c代码也可以 调用本地的Java代码。 由于java代码运行和执行都是基于虚拟机的。 了解一下JVM虚拟机 我们都知道:.java源文件都需要通...

拉莫帅的博客 2234

基于深度学习的X光安检危险品检测系统(YOLOv8 + UI界面 + 数据集)

随着全球安全形势的变化,机场、车站、地铁等场所的安检工作日益重要。X光安检系统已经成为现代公共安全领域中不可或缺的部分,能够有效地检测物品的内部结构,识别潜在的危险品。然而,传统的X光图像分析方法仍然依赖人工操作,检测效率较低,并且易受到人为因素的影响。近年来,深度学习技术的应用在图像分析领域取得了显著的突破,特别是在目标检测任务中,YOLO(You Only Look Once)模型因其高效性和精度,成为了许多目标检测任务的首选模型。

YOLO 1060

JNI 与 NDK 入门(一),原生Android开发的路该怎么走

这里我特地整理了一份《Android开发核心知识点笔记》,里面就包含了自定义View相关的内容除了这份笔记,还给大家分享Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。分享上面这些资源,希望可以帮助到大家提升进阶,如果你觉得还算有用的话,不妨把它们推荐给你的朋友~喜欢本文的话,给我点个小赞、评论区留言或者转发支持一下呗~一个人可以走的很快,但一群人才能走的更远。

m0_61549953的博客 378

海康DS-7604N-K1/RTB固件包

【摘要】海康DS-7604N-K1/RTB萤石云设备发布V4.30.091版本升级程序(2022.09.19),仅适用于指定型号。升级前需先升级至V3.4.106基础版本,刷机会重置设备为未激活状态,需重新设置admin密码。该机型支持密码/手势登录,无密码时可通过U盘升级。注意事项:升级存在风险,需确认程序适用性;升级过程严禁断电;必须阅读压缩包内的刷机说明。此为定制机型,非必要不建议升级。(150字)

海康威视技术支持 1572

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

NDK 入门(一)—— JNI 初探

宏是预处理器的一个重要概念,它是一种简单的文本替换机制。宏定义使用#define关键字,将一个标识符与一个文本片段关联起来。当源代码中出现宏标识符时,预处理器会将其替换为与之关联的文本片段。以下是一些常见的宏使用示例:// 定义 PI 为常量#define PI3.14159// 定义 PI 为常量 # define PI 3.14159 // 定义 MAX(a, b) 为宏函数 # define MAX(a , b)((a) >(b)?(a) :(b))

tmacfrank 1550

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

NDK 入门(三)—— JNI 注册与 JNI 线程

在 Native 方法中把 JNIEnv 和 jobject 封装在 MyContext 中,然后把 MyContext 传入 pthread_create() 的第四个参数,在 线程的入口方法 task 中接收 MyContext 使用两个封装的参数回调上层方法。默认的注册方式就是静态注册,上面提到的模板方法 stringFromJNI() 就是通过静态注册生成的 JNI 函数 Java_com_jni_register_MainActivity_stringFromJNI()。

tmacfrank 2145

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

JNI/NDK入门指南之正确姿势了解JNI和NDK

         你真的了解Android中JNI/NDK吗?    随着Android生态的发展,越来越多的行业开始使用Android操作系统,这就造就了对Android设备的应用性能和安全要求越来越高,随之而来的对JNI/NDK开发的需求也越来越大。虽然网上或者很多书籍都有关于此方面的讲解,但是都是上来直奔主题说怎么使用JNI/NDK,而没有将啥是JNI和NDK讲解清楚。所以导致很...

IT先森 3569

Android JNI(一)——NDK与JNI基础

Java调用C/C++在Java语言里面本来就有的,并非Android自创的,即JNI。JNI就是Java调用C++的规范。当然,一般的Java程序使用的JNI标准可能和android不一样,Android的JNI更简单。

hirezy 3306

Android:JNI 与 NDK

在Android开发中,使用NDK开发的需求正逐渐增大但很多人却搞不懂JNI与NDK到底是怎么回事今天,我将先介绍JNI与NDK& 之间的区别,手把手进行NDK的使用教学,希望你们会喜欢,即Java本地接口作用: 使得Java与 本地其他类型语言(如C、C++)交互即在Java代码 里调用C、C++等语言的代码 或C、C++代码调用Java代码特别注意:JNI是Java调用Native语言的一种特性JNI是属于Java的,与Android无直接关系,是Android的一个工具开发包。

u013250861的博客 1509

Android中JNI&NDK入门(一) 之 初识NDK和JNI

1 NDK NDK全称是Native Develop Kit,翻译作原生开发工具包。它允许你为Android使用C/C++代码来实现应用程序的功能。换言之Android的SDK之外,有一个工具叫NDK,用于进行C/C++的开发。一般情况,是用NDK工具把C/C++编译为.co文件,然后在Java中调用。NDK 可能不适合大多数 Android 编程初学者,这些初学者只需使用 Java 代码和框架...

子云心的博客 2151

[NDK/JNI系列01] NDK与JNI的基本概念与使用场景

介绍是NDK和JNI,它们有什么作用和优势 使用场景和案例 , Android系统服务与JNI的通讯

我其实什么都不会 6767

NDK探究之旅《一》——对jni和NDK的认识

最近在学习NDK开发,这是NDK篇的第一节。对jni和ndk的基本认识。 JNI的基本概念? jni是一个协议。这个协议用来沟通Java代码和外部的本地代码(c/c++),通过这个协议 ,Java代码可以外部的c/c代码 ,外部的c/c代码也可以 调用本地的Java代码。 欢迎关注我的博文:http://blog.youkuaiyun.com/androidstarjack。 欢迎关注公众号: 终端研发部。一块学习

这个时代,作为程序员可能要学习小程序 5788

JNI 与 NDK

JNI 与 NDK JNI 定义:Java Native Interface,即 Java本地接口 作用: 使得Java 与 本地其他类型语言(如C、C++)交互,Java代码与C,C++语言代码相互调用 注意: JNI是 Java 调用 Native 语言的一种特性 JNI 是属于 Java 的,与 Android 无直接关系 背景:Java 具备跨平台的特点,所以Java 与 本地代码交互...

mLuoya的博客 5083
上一篇: 别再问Android开发前景了,现状分析给你看了,难道还要让我教你怎么做?
下一篇: 近两年来的一些Android面试总结,以及常见的一些面试题
懂你的大海
博客等级 码龄6年 9049粉丝 1381原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值