Android 高级开发 JNI & NDK 介绍与使用

前言

对于没接触过的领域,即是挑战也是机遇,不仅能够提升自己的能力。还能够学习到新的技术知识

而学习新的技术的时候,最好是从头开始按照体系学!比一直找快速解决的方法更好

就比如这次的 需要与八达通(.a 静态库 贼j8恶心)硬件交互就必须用 android 中的 NDK工具 ,使用 JNI 桥梁通讯技术 去实现底层 C/C++ 和本地 JAVA 的数据交互。
然而八达通不思进取,还没有提供Android 中的和八达通设备交互的SDK,有提供Window端的交互SDK ,之后采用的方案是通过 中间服务连接八达通 用接口的方式 来进行交互。 不过还是学习到了JNI 的一些知识还是不错的。

看技术资料的同时,一定要首先去看官方最新的文档!因为可能因为 IDE 的升级 会有不同的使用配置更新!

在Android studio中开发NDK,NDK是Android底层的 一套开发工具包 c/c++库,然而要在java中调用c/c++的原生功能,则需要使用JNI来实现。

什么是JNI

JNI (Java Native Interface) 是java本地接口,它主要是为了实现 Java 调用c、c++等本地代码所封装的一层接口。大家都知道java是跨平台开发语言,它的狂平台特性导致与本地交互的能力不够强大,一些和操作系统相关的特性Java无法完成,所以Java提供了JNI用于和Native代码进行交互。通过JNI,Java可以调用c、c++,相反,c、c++也可以调用Java的相关代码。

JNI 实现 Java 调用 C 层的方法流程:

图引用来自JNA和JNI的对比

为什么要使用 JNI?

  1. 通过JNI 技术可以拓展手机Wifi热点
  2. coder 执行高效; 大量的运算(极品飞车) ;万能解码(ffmpeg) ;Opengl(3D渲染)
  3. 代码的复用:ffmpeg,opencv(人脸识别库) ,7-zip
#include "com_atguigu_jnitests2_JNIS.h"
JNIEXPORT jstring JNICALL Java_com_atguigu_jnitests2_JNIS_helloJNI
(JNIEnv * env, jobject jobj) {return (*env)->NewStringUTF(env, "Hello from C");
}

怎么用Jni?

学习C语言-看懂代码

熟悉 Jni开发流程,在Android 熟悉使用 NDK

NDK介绍

定义:Native Development Kit,是 Android的一个工具开发包 NDK是属于 Android 的,与Java并无直接关系

作用:快速开发C、 C++的动态库,并自动将so和应用一起打包成 APK

即可通过 NDK在 Android中 使用 JNI与本地代码(如C、C++)交互

应用场景:在Android的场景下 使用JNI

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

JNI 是一种协议,相当于桥梁作用

​ Java Native Interface : java 本地开发接口

​ 通过JNI 可以让 java 与 C/C++ 代码实现互调

NDK 是Google 在Android 中提供的开发工具包

使用 NDK 编译代码主要有三种方法:

  • 基于 Make 的 ndk-build。
  • CMake。
  • 独立工具链,用于与其他编译系统集成,或与基于 configure 的项目搭配使用。

NDK开发流程

1、在java 里面编写 native 代码

2、在main 目录下创建 jni 目录 / 或者 cpp 文件夹 ,在内创建 .c 或.cpp 类文件 也就是 c/c++文件 ,可使用命令 生成头文件; (CMake 方式的话默认创建项目不会生成头文件)

3、配置动态链接库的名称

4、加载动态链接库

5、进行使用

NDK 常用的两种方式 nkd-build 和 CMake 编译代码的两种流程安装配置略有差异。


NDK开发流程 ndk-build 构建

1.安装配置NDK

​ 1). 解压NDK的zip包到非中文目录

​ 2). 配置path : 解压后NDK的根目录----->ndk-build

2. 给AS配置关联NDK

​ 1). local.properties中添加配置

​ ndk.dir=G:\android-ndk-r10

​ 2). gradle.properties中添加配置

​ android.useDeprecatedNdk=true

3. 编写native方法:
public class JNIS {public native String helloJNI();
}
4.定义对应的JNI

​ 1). 在main下创建jni文件夹

​ 2). 生成native方法对应的JNI函数声明头文件: 命令窗口中, 进入java文件夹

         执行命令: javah com.atguigu.jnitests2.JNIS生成头文件: com_atguigu_jnitests2_JNIS.h函数声明: JNIEXPORT jstring JNICALL Java_com_atguigu_jnitests2_JNIS_helloJNI(JNIEnv *, jobject);
4.1 生成头文件的两种方式

​ 1.在\NDKDemo\app\src\main\java

​ 执行命令:javah com.atguigu.ndkdemo.JNI (拷贝全类名,在文件中的 Class 名称右键 -> copy Reference 得到 com.thisfeng.ndkdemo2.JNI)

生成的 .h头文件 会在当前 java 目录,将其拷贝进 jni 目录 或者 cpp 目录和 C文件统一存放)

(其实在 CMake 构建的话,可以不生成头文件,直接可以通过IDE 快速创建 C 对应的方法)

​ 2.另外一种是在项目的build/intermaediates/classes/debug/下执行

​ 命令 : javah -classpath . -jni 类路径 JNI类

​ 3). 将生成的头文件转移到jni文件夹下 (AS CMake 构建的 方式应该统一存放在 cpp 文件目录)

​ 4). 在jni下定义对应的函数文件: test.c

#include "com_atguigu_jnitests2_JNIS.h"JNIEXPORT jstring JNICALL Java_com_atguigu_jnitests2_JNIS_helloJNI (JNIEnv * env, jobject jobj) { return (*env)->NewStringUTF(env, "Hello from C"); }

​ 5). 在jni文件夹下创建一个空的C文件: empty.c

​ 说明: 这是AS的bug, 必须至少2个C文件才能通过编译(如果出现可尝试)

5. 指定编译的不同CPU
defaultConfig {ndk{moduleName "HelloJni" //so文件: lib+moduleName+.so ( CMake 方式可不 定义? 但是会在 CMakeList 中去配置)abiFilters "armeabi", "armeabi-v7a", "x86" //cpu的类型}}
  1. 编译生成不同平台下的动态链接文件

    ​ 1). 执行rebuild, 生成so文件

    ​ 2). so文件目录: build\intermediates\ndk\debug\lib…

  2. 调用native方法:

    ​ 1). 在native方法所在的类中加载so文件

static {System.loadLibrary("HelloJni");}

​ 2). 在Activity中调用native方法:

String result = new JNIS().helloJNI();Log.e("TAG", "result="+result);

至此完成 ndk-build 的编译方式 配置到使用如上。下面来说下


NDK开发流程 CMake 构建

1. 介绍

Android NDK 支持使用 CMake 编译应用的 C 和 C++ 代码。 目前在 AS 中新创建的C/C++项目都是基于 CMake 进行构建的 ,下面记录如何将 CMake 用于 NDK。

目前不支持在同一模块中同时使用 CMake 和 ndk-build。

Android Studio 从2.2 版本起开始支持CMake ,可以通过CMake 和NDK 将C/C++ 代码编译成底层的库,然后再配合Gradle 的编译将库打包到APK 中。 CMake 是一个跨平台构建系统,在Android Studio 引入CMake 之前,它就已经被广泛运用了。

2. 安装和配置 NDK 和 CMake 点击官网查看

注意:如果您在 ndk-bundle 文件夹中安装了 NDK,它会显示在标签为 NDK 的列表中。如果您使用的是 Gradle 3.5 版或更高版本,则可以选中或取消选中该复选框。取消选中该复选框会卸载已安装的 NDK,释放磁盘空间,并使复选框从列表中消失。如果您卸载旧版 NDK,请从项目的 local.properties 文件中移除 ndk.dir 值,该值现已弃用。

3. 配置 CMake 点击官网查看

CMake 构建脚本是一个纯文本文件,您必须将其命名为 CMakeLists.txt,并在其中包含 CMake 构建您的 C/C++ 库时需要使用的命令。如果您的原生源代码文件还没有 CMake 构建脚本,您需要自行创建一个,并在其中包含适当的 CMake 命令。

当你下载了 NDK 和 CMake 配置之后 ,最好 手动去创建一个 C/C++项目 会得到一个完整的默认配置。

4. 将 Gradle 关联到您的原生库

build.gradle 文件中引用

   android {...defaultConfig {...}buildTypes {...}// Encapsulates your external native build configurations.externalNativeBuild {// Encapsulates your CMake build configurations.cmake {// Provides a relative path to your CMake build script.path "CMakeLists.txt"}}}

5. 遇到的问题

如果您不小心卸载过之前的旧版 NDK,请从项目的 local.properties 文件中移除 ndk.dir 值,该值现已弃用。

否则会直build 报错不通过是因为。找原来的 NDK 去了

报错如下:

A problem occurred configuring project ':app'. \> NDK not configured. Download it with SDK manager. Preferred NDK version is '20.0.5594570'. Log: /Users/thisfeng/Android/MyDemos/NewNDKDemo2/app/.cxx/ndk_locator_record.json

​ 所以要使用下载 特定的 NDK(side by side)

​ 这个意思是 需要你安装 指定版本的 NDK version is ’20.0.5594570’ , 如上图 所示,点击 右下角 show Packge details .

​ 而使用 ndk-build 方式 在 as 中 AS ,NDK一定要配置 local.properties 文件 配置:

ndk.dir=/Users/thisfeng/Library/Android/sdk/ndk-bundle

并且 3.5 之后 一定要 在 local.properties 文件中移除 ndk.dir 值,该值现已弃用。

两种构建方式脚本文件对应:

​ CMake CMakeLists.txt

​ ndk-build Android.mk

注意:AS 如果老版本的 NDK 被弃用(Obsolete)了后, 需要使用新的。重新下载,主要要用梯子!更新


CMake 构建生成的 .so 文件 在此。 在安装时 会自动打进 apk包

.so 文件是动态库(一般第三方SDK 接入时都需要在 libs 引入对应不同架构的 .so 文件,此文件就是第三方SDK内部所使用到的一些和C/C++的函数交互库 )

.a 文件是静态库 (有些第三方会提供一个头文件 和 .a 的静态库给你,一脸懵逼的不知道如何使用)

(cmake配置.a库)


以上是 两种构建方式,现在默认官方创建新的 C/C++项目的都是用 CMake 进行构建,建议采用 CMake 。

Android 高级开发 JNI NDK 介绍与使用相关推荐

  1. Android高级开发专题晋升班

    Android高级开发专题晋升班 适用人群:1-3年以上经验的开发者丨学员平均薪酬20K/月 转载于:https://www.cnblogs.com/lythonliu/p/6285531.html

  2. android高级开发面试!五年Android开发者小米、阿里面经,Android篇

    最近我在接受采访时被问到我关于成为一名伟大的程序员见解.这是一个有趣的问题,我认为我们都可以是伟大的程序员,无论我们的天赋如何,如果我们遵循一些规则的话--我相信--这应该是常识.实际上,这些规则并不 ...

  3. Android studio下JNI(NDK)开发

    玩智能手机的都说android手机体验.流畅差苹果太远了,一方面是苹果的硬件确实牛逼,另一个原因在于开发语言上的选择,苹果使用了Objective-C来开发,而android使用了java.程序员都知 ...

  4. android高级开发强化实战,高级Android开发强化实战[PDF][215.59MB]

    内容简介 本书收集了约20个关于高级Android开发的进阶实例,这些实例都是对在日常开发中遇到的问题的抽象,涉及整个Android开发的各个技术栈.本书从常见的问题入手,引导读者逐步地掌握进阶的各个 ...

  5. android期末考试选择题,轻松拿到了阿里Android高级开发工程师的offer

    前言 在这个网络发展快速的时代,我想问为什么你选择做程序员?有人说因为不善交际,也有人说最火的行业互联网,最好的职业程序员.确实在这个繁荣的行业,只要你自己不下船技术不水,就可以衣食无忧,努力努力说不 ...

  6. android高级开发面试!一次哔哩哔哩面试经历,知乎上已获万赞

    Android面试相关整理 最近有一点找工作的打算,想补下面试题.但是发现网上面试相关的文章特别多,不知道从何看起,所以简单的总结了一下我有印象的一些,方便自己随时查看,本想带下个人评价,但有些没有仔 ...

  7. Android高级开发书籍

    程序设计 一.java (a)基本语法(如继承.异常.引用.泛型等) Java核心技术 卷I(适合入门) 进阶 Effective Java中文版(如何写好的Java代码) Java解惑 (介绍烂Ja ...

  8. Android高级开发第二讲--Android中API翻译之Activity

    博客出自:刘兆贤的博客_CSDN博客-Java高级,Android旅行,Android基础领域博主,转载注明出处! All Rights Reserved ! Activity主要用来展示给用户,让用 ...

  9. Android高级开发面试题目,再也不用担心不能升职加薪了。

    Java基础 1.内部类的作用 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立. 在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类. 创 ...

最新文章

  1. 建堆 java_堆排序就这么简单
  2. Science:纽约西奈山医学院房刚组定量分析真核生物DNA 6mA解析细菌污染的影响...
  3. Python地图可视化三大秘密武器
  4. PHP区域联动后端接口与数据表设计
  5. mysql的cpu飙升到500_[MySQLCPU]线上飙升800%,load达到12的解决过程
  6. 全网首秀,我用动画展现Pycharm十大实用技巧
  7. 浅谈!important对CSS的重要性
  8. 你真的了解JavaScript的Promise吗?
  9. vs2005下,回发或回调参数无效的解决方法
  10. 通过ip查询详细地址
  11. WebRTC NAT穿透服务器 coturn服务搭建
  12. 基于DDPG的智能交通灯控制算法
  13. mysql中怎样把字段名改为中文_mysql修改字段名-Mysql,修改
  14. AD5933的直流偏置和量程自动切换问题
  15. 在word中公式太长,用公式编辑器怎样设置才能自动换行?
  16. java毕业设计汽车客运站票务管理系统源码+lw文档+mybatis+系统+mysql数据库+调试
  17. 习题 3.12 给出一个不多于5位的正整数,要求:1. 求出它是几位数;2. 分别打印出每一位数字;3. 按逆序打印出各位数字,例如原数位321,应输出123。
  18. js 购物车数量增减,总价格联动变化
  19. python web实战视频教程_2018Python Flask打造一个视频网站实战视频教程
  20. 【C/C++】龙格库塔+亚当姆斯求解数值微分初值问题

热门文章

  1. 机器学习基础(六)贝叶斯统计
  2. ospf(开放式最短路径优先协议)
  3. 1103 Integer Factorization (30分)
  4. uva11401:Triangle Counting 递推 数学
  5. python计算复数的辐角,(Python 3)1051复数乘法(15分),python31051
  6. PAT 1003 我要通过! python
  7. ckplayer播放线上视频问题
  8. 小米台灯、小米插线板 接入Home Assistant平台 让天猫精灵音箱控制
  9. 《计算机是怎样跑起来的》读书笔记
  10. C语言实现简易五子棋