当前位置: 首页 > 编程日记 > 正文

Android:JNI 与 NDK到底是什么

前言

  • Android开发中,使用 NDK开发的需求正逐渐增大
  • 但很多人却搞不懂 JNI 与 NDK 到底是怎么回事
  • 今天,我将先介绍JNI 与 NDK & 之间的区别,手把手进行 NDK的使用教学,希望你们会喜欢

目录

目录


1. JNI介绍

1.1 简介

  • 定义:Java Native Interface,即 Java本地接口
  • 作用: 使得Java 与 本地其他类型语言(如C、C++)交互

    即在 Java代码 里调用 C、C++等语言的代码 或 C、C++代码调用 Java 代码

  • 特别注意:

    1. JNI是 Java 调用 Native 语言的一种特性
    2. JNI 是属于 Java 的,与 Android 无直接关系

1.2 为什么要有 JNI

  • 背景:实际使用中,Java 需要与 本地代码 进行交互
  • 问题:因为 Java 具备跨平台的特点,所以Java 与 本地代码交互的能力非常弱
  • 解决方案: 采用 JNI特性 增强 Java 与 本地代码交互的能力

1.3 实现步骤

  1. Java中声明Native方法(即需要调用的本地方法)
  2. 编译上述 Java源文件javac(得到 .class文件)
  3. 通过 javah 命令导出JNI的头文件(.h文件)
  4. 使用 Java需要交互的本地代码 实现在 Java中声明的Native方法

    如 Java 需要与 C++ 交互,那么就用C++实现 JavaNative方法

  5. 编译.so库文件
  6. 通过Java命令执行 Java程序,最终实现Java调用本地代码


更加详细过程请参考本文第4节:具体使用


2. NDK介绍

2.1 简介

  • 定义:Native Development Kit,是 Android的一个工具开发包

    NDK是属于 Android 的,与Java并无直接关系

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

    即 Android开发的功能需要本地代码(C/C++)实现

  • 特点

示意图

  • 额外注意

示意图

2.2 使用步骤

  1. 配置 Android NDK环境
  2. 创建 Android 项目,并与 NDK进行关联
  3. 在 Android 项目中声明所需要调用的 Native方法
  4. 使用 Android需要交互的本地代码 实现在Android中声明的Native方法

    比如 Android 需要与 C++ 交互,那么就用C++ 实现 JavaNative方法

  5. 通过 ndk - bulid 命令编译产生.so库文件
  6. 编译 Android Studio 工程,从而实现 Android 调用本地代码


更加详细过程请参考本文第4节:具体使用


3. NDK与JNI关系

示意图


4. 具体使用

本文根据版本的不同介绍了两种在Android Studio中实现 NDK的方法:Android Studio2.2 以下 & 2.2以上

4.1 Android Studio2.2 以下实现NDK

  • 步骤如下

    1. 配置 Android NDK环境
    2. 关联 Andorid Studio项目 与 NDK
    3. 创建本地代码文件(即需要在 Android项目中调用的本地代码文件)
    4. 创建 Android.mk文件 & Application.mk文件
    5. 编译上述文件,生成.so库文件,并放入到工程文件中
    6. 在 Andoird Studio项目中使用 NDK实现 JNI 功能
  • 步骤详解

步骤1:配置 Android NDK环境

具体请看文章手把手教你配置Android NDK环境

步骤2: 关联Andorid Studio项目 与 NDK

  • 当你的项目每次需要使用 NDK 时,都需要将该项目关联到 NDK

    1. 此处使用的是Andorid Studio,与Eclipse不同
    2. 还在使用Eclipse的同学请自行查找资料配置
  • 具体配置如下

a. 在Gradle的 local.properties中添加配置

ndk.dir=/Users/Carson_Ho/Library/Android/sdk/ndk-bundle
  • 1

ndk目录存放在SDK的目录中,并命名为ndk-bundle,则该配置自动添加

示意图

b. 在Gradle的 gradle.properties中添加配置

android.useDeprecatedNdk=true 
// 对旧版本的NDK支持

示意图

c. 在Gradle的build.gradle添加ndk节点

示意图

  • 至此,将Andorid Studio的项目 与 NDK 关联完毕
  • 下面,将真正开始讲解如何在项目中使用NDK

步骤3:创建本地代码文件

  • 即需要在Android项目中调用的本地代码文件

    此处采用 C++作为展示


test.cpp

# include <jni.h>
# include <stdio.h>extern "C"
{JNIEXPORT jstring JNICALL Java_scut_carson_1ho_ndk_1demo_MainActivity_getFromJNI(JNIEnv *env, jobject obj ){// 参数说明// 1. JNIEnv:代表了VM里面的环境,本地的代码可以通过该参数与Java代码进行操作// 2. obj:定义JNI方法的类的一个本地引用(this)return env -> NewStringUTF("Hello i am from JNI!");// 上述代码是返回一个String类型的"Hello i am from JNI!"字符串}
}

此处需要注意:

  • 如果本地代码是C++.cpp或者.cc),要使用extern "C" { }把本地方法括进去
  • JNIEXPORT jstring JNICALL中的JNIEXPORT 和 JNICALL不能省
  • 关于方法名Java_scut_carson_1ho_ndk_1demo_MainActivity_getFromJNI
    1. 格式 = Java _包名 _ 类名_Java需要调用的方法名
    2. Java必须大写
    3. 对于包名,包名里的.要改成__要改成_1

如我的包名是:scut.carson_ho.ndk_demo,则需要改成scut_carson_1ho_ndk_1demo 
最后,将创建好的test.cpp文件放入到工程文件目录中的src/main/jni文件夹 
若无jni文件夹,则手动创建。

下面我讲解一下JNI类型与Java类型对应的关系介绍 
如下图

步骤4:创建Android.mk文件

  • 作用:指定源码编译的配置信息

    如工作目录,编译模块的名称,参与编译的文件等

  • 具体使用


Android.mk

LOCAL_PATH       :=  $(call my-dir)
// 设置工作目录,而my-dir则会返回Android.mk文件所在的目录include              $(CLEAR_VARS)
// 清除几乎所有以LOCAL——PATH开头的变量(不包括LOCAL_PATH)LOCAL_MODULE     :=  hello_jni
// 设置模块的名称,即编译出来.so文件名
// 注,要和上述步骤中build.gradle中NDK节点设置的名字相同LOCAL_SRC_FILES  :=  test.cpp
// 指定参与模块编译的C/C++源文件名include              $(BUILD_SHARED_LIBRARY)
// 指定生成的静态库或者共享库在运行时依赖的共享库模块列表。

最后,将上述文件同样放在`src/main/jni`文件夹中。

步骤5:创建Application.mk文件

  • 作用:配置编译平台相关内容
  • 具体使用

*Application.mk*

APP_ABI := armeabi
// 最常用的APP_ABI字段:指定需要基于哪些CPU平台的.so文件
// 常见的平台有armeabi x86 mips,其中移动设备主要是armeabi平台
// 默认情况下,Android平台会生成所有平台的.so文件,即同APP_ABI := armeabi x86 mips
// 指定CPU平台类型后,就只会生成该平台的.so文件,即上述语句只会生成armeabi平台的.so文件

最后,将上述文件同样放在`src/main/jni`文件夹中

步骤6:编译上述文件,生成.so库文件

  • 经过上述步骤,在src/main/jni文件夹中已经有3个文件

示意图

  • 打开终端,输入以下命令
// 步骤1:进入该文件夹
cd /Users/Carson_Ho/AndroidStudioProjects/NDK_Demo/app/src/main/jni 
// 步骤2:运行NDK编译命令
ndk-build

示意图

  • 编译成功后,在src/main/会多了两个文件夹libs & obj,其中libs下存放的是.so库文件

示意图

步骤7:在src/main/中创建一个名为jniLibs的文件夹,并将上述生成的so文件夹放到该目录下

  1. 要把名为 CPU平台的文件夹放进去,而不是把.so文件放进去
  2. 如果本来就有.so文件,那么就直接创建名为jniLibs的文件夹并放进去就可以

示意图

步骤8:在Andoird Studio项目中使用NDK实现JNI功能

  • 此时,我们已经将本地代码文件编译成.so库文件并放入到工程文件中
  • Java代码中调用本地代码中的方法,具体代码如下:

MainActivity.java

public class MainActivity extends AppCompatActivity  {// 步骤1:加载生成的so库文件// 注意要跟.so库文件名相同static {System.loadLibrary("hello_jni");}// 步骤2:定义在JNI中实现的方法public native String getFromJNI();// 此处设置了一个按钮用于触发JNI方法private Button Button;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 通过Button调用JNI中的方法Button = (Button) findViewById(R.id.button);Button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Button.setText(getFromJNI());}});}

主布局文件:activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="scut.carson_ho.ndk_demo.MainActivity">// 此处设置了一个按钮用于触发JNI方法<Buttonandroid:id="@+id/button"android:layout_centerInParent="true"android:layout_width="300dp"android:layout_height="50dp"android:text="调用JNI代码" /></RelativeLayout>


结果展示

结果展示


源码地址

Carson-Ho的Github地址:NDK_Demo


4.2 Android Studio2.2 以上实现NDK

  • 如果你的Android Studio是2.2以上的,那么请采用下述方法

    因为Android Studio2.2以上已经内部集成 NDK,所以只需要在Android Studio内部进行配置就可以

  • 步骤讲解

步骤1:按提示创建工程

在创建工程时,需要配置 NDK,根据提示一步步安装即可。

示意图

步骤2:根据需求使用NDK

  • 配置好NDK后,Android Studio会自动生成C++文件并设置好调用的代码
  • 你只需要根据需求修改C++文件 & Android就可以使用了。

示意图


5. 总结

  • 本文主要讲解 Java的 JNI与 AndroidNDK相关知识
  • 下面我将继续对 Android中的NDK进行深入讲解 ,有兴趣可以继续关注Carson_Ho的安卓开发笔记
  • 转载自:https://blog.csdn.net/carson_ho/article/details/73250163

相关文章:

【ACM】LightOJ - 1008 Fibsieve`s Fantabulous Birthday (找规律,找...)

https://vjudge.net/problem/LightOJ-1008 题目很好理解&#xff0c;第一行表示测试样例的个数&#xff0c;接下来输入一个大于等于1的数&#xff0c;按照格式输出这个数的坐标 蓝色的是 奇数的平方&#xff1b; 红色的是 偶数的平方&#xff1b; 黄色的是对角线&#xff1a…

Computed property XXX was assigned to but it has no setter

报错视图&#xff1a; 原因&#xff1a; 组件中v-model“XXX”&#xff0c;而XXX是vuex state中的某个变量vuex中是单项流&#xff0c;v-model是vue中的双向绑定&#xff0c;但是在computed中只通过get获取参数值&#xff0c;没有set无法改变参数值解决方法&#xff1a; 1.在co…

OpenGL 矩阵变换

origin refer :http://www.songho.ca/opengl/gl_transform.html#modelviewOpenGL 矩阵变换Related Topics: OpenGL Pipeline, OpenGL Projection Matrix, OpenGL Matrix Class Download: matrixModelView.zip, matrixProjection.zipOverviewOpenGL Transform MatrixExample: GL…

2016.8.11 DataTable合并及排除重复方法

合并&#xff1a; DataTable prosxxx; DataTable pstaryyy; //将两张DataTable合成一张 foreach (DataRow dr in pstar.Rows) { pros.ImportRow(dr); } DataTable设置主键&#xff0c;并判断重复 DataTable allpros xxx; 单列设为主键&#xff1a; //设置第某列为主键 allpros.…

【ACM】LightOJ - 1010 Knights in Chessboard(不是搜索...)

https://vjudge.net/problem/LightOJ-1010 给定一个mn的棋盘&#xff0c;你想把棋子放在哪里。你必须找到棋盘上最多可以放置的骑士数量&#xff0c;这样就不会有两个骑士互相攻击。不熟悉棋手的注意&#xff0c;棋手可以在棋盘上攻击8个位置&#xff0c;如下图所示。 不论输入…

webpack-dev-server 和webapck --watch的区别

webpack-dev-server 和webapck --watch 都可以监测到代码变化 &#xff0c; 区别是&#xff1a;webpack-der-server 监测到代码变化后&#xff0c;浏览器可以看到及时更新的效果&#xff0c;但是并没有自动打包修改的代码&#xff1b; webpack --watch 在监测到代码变化后自动打…

Android 应用进行性能分析/APP/系统性能分析

如何对 Android 应用进行性能分析记录一下自己在使用DDMS的过程&#xff1a;开启AS&#xff0c;打开并运行项目 找到TOOL/选择Android Device Monitor一款 App 流畅与否安装在自己的真机里&#xff0c;玩几天就能有个大概的感性认识。不过通过专业的分析工具可以使我们更好的分…

公钥与私钥,HTTPS详解

1.公钥与私钥原理1)鲍勃有两把钥匙&#xff0c;一把是公钥&#xff0c;另一把是私钥2)鲍勃把公钥送给他的朋友们----帕蒂、道格、苏珊----每人一把。3)苏珊要给鲍勃写一封保密的信。她写完后用鲍勃的公钥加密&#xff0c;就可以达到保密的效果。4)鲍勃收信后&#xff0c;用私钥…

【ACM】杭电OJ 4704 Sum (隔板原理+组合数求和公式+费马小定理+快速幂)

http://acm.hdu.edu.cn/showproblem.php?pid4704 1.隔板原理 1~N有N个元素&#xff0c;每个元素代表一个1.分成K个数&#xff0c;即在(N-1)个空挡里放置&#xff08;K-1&#xff09;块隔板 即求组合数C(N-1,0)C(N-1,1)...C(N-1&#xff0c;N-1) 2.组合数求和公式 C(n,0)C(…

Vue 中 CSS 动画原理

下面这段代码&#xff0c;是点击按钮实现hello world显示与隐藏 <div id"root"><div v-if"show">hello world</div><button click"handleClick">按钮</button> </div> let vm new Vue({el: #root,data: {s…

【ACM】UVA - 340 Master-Mind Hints(一定要好好学英语...)

https://vjudge.net/problem/UVA-340 N 表示 密码的个数 第一行是正确的密码 下面的行直到N个0之前&#xff0c;都是猜测的序列&#xff0c;输出的括号&#xff08;A&#xff0c;B&#xff09; A表示对应位置与密码相符合的个数&#xff0c;B表示出现在序列中的数字但是位…

SLAM的前世今生

SLAM的前世 从研究生开始切入到视觉SLAM领域&#xff0c;应用背景为AR中的视觉导航与定位。 定位、定向、测速、授时是人们惆怅千年都未能完全解决的问题&#xff0c;最早的时候&#xff0c;古人只能靠夜观天象和司南来做简单的定向。直至元代&#xff0c;出于对定位的需求&a…

No resource found that matches the given name '@style/Theme.AppCompat.Light'

为什么80%的码农都做不了架构师&#xff1f;>>> Android导入项目时出现此问题的解决办法&#xff1a; 1.查看是否存在此目录&#xff08;D:\android-sdk\extras\android\support\v7\appcompat&#xff09;&#xff0c;若没有此目录&#xff0c;在项目右键Android T…

极限编程 (Extreme Programming) - 迭代计划 (Iterative Planning)

(Source: XP - Iteration Planning) 在每次迭代开始时调用迭代计划会议&#xff0c;以生成该迭代的编程任务计划。每次迭代为1到3周。 客户从发布计划中按照对客户最有价值的顺序选择用户故事进行此次迭代。还选择了要修复的失败验收测试。客户选择的用户故事的估计总计达到上次…

VINS-mono详细解读与实现

VINS-mono详细解读 VINS-mono详细解读 前言 Vins-mono是香港科技大学开源的一个VIO算法&#xff0c;https://github.com/HKUST-Aerial-Robotics/VINS-Mono&#xff0c;是用紧耦合方法实现的&#xff0c;通过单目IMU恢复出尺度&#xff0c;效果非常棒。 感谢他们开源&#x…

mysql+mycat搭建稳定高可用集群,负载均衡,主备复制,读写分离

数据库性能优化普遍采用集群方式&#xff0c;oracle集群软硬件投入昂贵&#xff0c;今天花了一天时间搭建基于mysql的集群环境。 主要思路 简单说&#xff0c;实现mysql主备复制-->利用mycat实现负载均衡。 比较了常用的读写分离方式&#xff0c;推荐mycat&#xff0c;社区活…

【UVA/Codeforces】1584 Circular Sequence / 792B Counting-out Rhyme(就是一个圈儿...)

https://vjudge.net/problem/UVA-1584 1584 Circular Sequence 输入一个字符串&#xff0c;可以以字符串中任意一个字母作为起始&#xff0c;输出字典序最小的那个字符串 两种方法&#xff0c;一种是设两个标记 【样例输入】CGAGTCAGCT 【样例输出】AGCTCGAGTC 一开始 an…

一个free异常引发的异常

有同事反馈说自己的线程不工作&#xff0c;查看堆栈发现其打印如下&#xff1a; #0 0x00007f291f72e7be in __lll_lock_wait_private () from /lib64/libc.so.6 #1 0x00007f291f6c2e4e in _L_lock_9925 () from /lib64/libc.so.6 #2 0x00007f291f6c1101 in free () from /li…

欧拉角和旋转矩阵相互转换

目录 1.参考资料 2.变换矩阵/F/H的svd分解或者旋转矩阵、平移矩阵求解 3. 欧拉角和旋转矩阵可同样表示刚体在三维空间的旋转&#xff0c;下面分享这两者互相转换的方法和核心代码 1.参考资料 2.变换矩阵/F/H的svd分解或者旋转矩阵、平移矩阵求解 欧拉角转旋转矩阵 欧拉角…

【Codeforces】 2A - Winner (map)

http://codeforces.com/problemset/problem/2/A So, if two or more players have the maximum number of points (say, it equals to m) at the end of the game, than wins the one of them who scored at least m points first. 所以只有一个只有一个map不行&#xff0c;…

[译]Godot系列教程一 - 场景与节点

场景(Scene)与节点(Node) 简介 先设想有那么一瞬间你自己不再是一名游戏开发者了&#xff0c;而是一名大厨&#xff01; 你的装备换成了一套大厨的制服。不要考虑制作游戏的事情&#xff0c;你现在的职责是为你的顾客创建新的可口的食谱。 那么&#xff0c;大厨是怎样创建食谱的…

EOS与以太坊有哪些区别?

想知道更多关于区块链技术知识&#xff0c;请百度【链客区块链技术问答社区】 链客&#xff0c;有问必答&#xff01;&#xff01;EOS与以太坊有哪些区别&#xff1f; 以太坊是一个专门为开发和运行去中心化应用&#xff08;DAPP&#xff09;搭建的智能合约平台&#xff1b;EOS…

图像特征点检测与匹配评价准则——量化

欢迎转载&#xff0c;转载请注明出处&#xff0c;谢谢&#xff01; 目前图像匹配中&#xff0c;局部特征匹配占据了绝大部分&#xff0c;常用的局部特征匹配方法有Harris、SIFT、SURF、ORB等等&#xff0c;不同的特征点检测和匹配方法尤其独特的优势和不足&#xff1b; 特征点匹…

path,classpath

1.path作用. 在环境变量里面配置 winr 打开cmd qq窗口就弹开了。 2.classpath是java里的选项。 java执行java类的时候&#xff0c;会去看这个java类是否在classpath路径下。不在就不能编译转载于:https://www.cnblogs.com/shapeOfMyHeart/p/5975686.html

【Codeforces】401C Team (01010110...)

http://codeforces.com/contest/401/problem/C 题目中&#xff0c;n表示0的个数&#xff0c;m表示1的个数&#xff0c;要求两个0不能连续&#xff0c;三个1不能连续 还要判断能否输出满足要求的序列&#xff0c;不满足输出-1 满足条件以后徐瑶分情况讨论 当1比0多&#xff…

表白这件事,比解 bug 要难多少?

情人节快乐&#xff01;我是可爱无敌的阿里妹。 今天是个粉红色日子&#xff0c;我们来聊聊和技术无关的“技术活”&#xff0c;比如&#xff1a; “如何表白&#xff1f;” 当技术人碰上动心的姑娘&#xff0c;他的浪漫开关就打开了。 在代码王国里劈荆斩刺的王子&#xff0c;…

特征点匹配+特征检测方法汇总

特征点匹配特征检测方法汇总特征提取与匹配---SURF&#xff1b;SIFT&#xff1b;ORB&#xff1b;FAST&#xff1b;Harris角点匹配方法匹配函数1. OpenCV提供了两种Matching方式&#xff1a;• Brute-force matcher (cv::BFMatcher) //暴力方法找到点集1中每个descriptor在点…

元数据驱动的微服务架构(上)

本次分享有两个部分&#xff1a; 微服务架构需要元数据 介绍微服务与元数据的关系。 一、微服务架构需要元数据 企业IT架构已经发展了多个阶段&#xff0c;一方面是服务化架构的发展&#xff0c;在SOA阶段主要解决应用间集成问题&#xff0c;但随着企业业务的发展&#xff0c;…

【Codeforces】427B Prison Transfer(别让罪犯跑了...)

http://codeforces.com/problemset/problem/427/B 从一串数字中选出连续的长度为c的子串&#xff0c;且子串中的每一个数都不能大于t&#xff0c;问这样的子串有多少个 TLE&#xff0c;看看n的范围就知道了&#xff0c;哎呀呀&#xff0c;有点chun #include <iostream>…

PHPUnit实践三(构建模块化的测试单元)

本系列教程所有的PHPUnit测试基于PHPUnit6.5.9版本&#xff0c;Lumen 5.5框架 目录结构 模块下的目录是符合Lumen的模块结构的如&#xff1a;Controllers、Models、Logics等是Lumen模块目录下的结构目录如果有自己的目录同级分配即可&#xff0c;如我这里的Requests 整体结构 ├…