弓背霞明剑照霜,秋风走马出咸阳。这篇文章主要讲述Android studio 下 JNI 开发实例相关的知识,希望能为你提供帮助。
在AS中进行 NDK 开发之前,我们先来简单的介绍几个大家都容易搞懵的概念:
-
到底什么是JNI,什么是NDK?
-
何为“交叉编译”?
文章图片
在上图中,上层绿色的部分一般都是用 Java 代码写的,下层橘黄色的部分一般都是用 C/C++ 代码写的。可以看出,正式由于有了中间 JNI 的存在我们才可以在 Application 层通过 JNI 调用下层中的一些东西。了解了JNI 的概念后,我们再看看 NDK,NDK(Native Development Kit)就比较好理解了,它就是一个本地开发的“工具包”。Java 开发要用到 JDK,android 开发要用到 SDK,那我们在 Android 中要进行 native 开发,也要用到它对应的工具包,即 NDK。通俗的来讲,NDK 就是帮助我们可以在Android应用中使用 C/C++ 来完成特定功能的一套工具。 NDK的作用有很多,我们简单的列举两个,比如:
1. 首先 NDK 可以帮助开发者“快速”开发 C(或C++) 的动态库。
2. 其次,NDK 集成了“交叉编译器”。使用 NDK,我们可以将要求高性能的应用逻辑使用 C 开发,从而提高应用程序的执行效率。
上面提到了“交叉编译”,我们最后再解释一下什么是交叉编译。大家都知道编译器在将中间代码连接成当前计算机可执行的二进制程序时,连接程序会根据当前计算机的 CPU、操作系统的类型来转换。而根据运行的设备的不同,CPU 的架构也是不同,大体有如下三种常见的 CUP 架构:
- arm 结构 :主要在移动手持、嵌入式设备上。我们的手机几乎都是使用的这种 CUP 架构。
- x86 结构 : 主要在台式机、笔记本上使用。如 Intel 和 AMD 的 CPU 。
- MIPS 架构:多用在网关、猫、机顶盒等设备。
- NDK:通过 NDK-build 方法来使用本地库
- CMake:通过 CMake 方法来使用本地库
- LLDB:用来调试 C/C++ 的工具
文章图片
编写代码 配置好 NDK 开发环境之后,在项目的布局文件添加一个 TextView,通过调用底层自己写好的 C/C++ 代码来返回一个字符串,最后呈现在 TextView上。
具体代码内容如下:
public class MainActivity extends AppCompatActivity {@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = findViewById(R.id.text); textView.setText(JNIUtils.getString()); } }
其中的 JNIUtils 下面马上就会提到。接下去,在 MainActivity 同级,新建一个类,包含一个 native 方法。
public class JNIUtils {
public static native String getString(); }
但是,会发现,方法名是飘红的,说明还没有被识别:
文章图片
把鼠标放到上面,它会提示我们对应的JNI头文件没有查找到。那么接下来我们要做的就是去生成与这个 getString() 方法所对应的头文件。
文章图片
生成 .h 头文件在 AS 自带的 Terminal 命令行窗口中输入如下几条指令,回车:
cd app cd src/main/java javah -classpath . -jni com.example.shenjiaqi.myapplication.JNIUtils
使用 javac 命令将 JNIUtils
.java
进行编译,然后使用 javah -jni 命令编译获取 jni 所需要的头文件。这里我们采用如下命令:
// javah -classpath . -jni 包名.类名。 javah -classpath . -jni com.example.shenjiaqi.myapplication.JNIUtils
注意编译命令一定得在 java 目录下下运行。编译成功没有遇到坑的话,你就可以在
···\\src\\main\\java
目录下看到一个.h文件。文章图片
接下来在项目中创建一个 jni 目录,并将刚生成的 .h 文件剪切至这个目录:
文章图片
我们先来查看一下这个 .h 文件的内容。这里面用 java 的概念来说就相当于接口内的抽象方法,需要我们创建 .c 文件来实现这些方法同时也就将我们的定义的 native 方法实现了:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include < jni.h> /* Header for class com_example_shenjiaqi_myapplication_JNIUtils */#ifndef _Included_com_example_shenjiaqi_myapplication_JNIUtils #define _Included_com_example_shenjiaqi_myapplication_JNIUtils #ifdef __cplusplus extern "C" { #endif /* * Class:com_example_shenjiaqi_myapplication_JNIUtils * Method:getString * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_shenjiaqi_myapplication_JNIUtils_getString (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
接着,新建一个 c++ 的文件,在 jni 目录下创建一个 JNIHello.cpp
文件来实现 .h 文件中的抽象方法:#include "com_example_shenjiaqi_myapplication_JNIUtils.h" JNIEXPORT jstring JNICALL Java_com_example_shenjiaqi_myapplication_JNIUtils_getString (JNIEnv *env, jclass jclass){ return env-> NewStringUTF("Hello World From JNI!!!!!"); }
可以看到我们首先需要把原来生成的 JNIUtlis 对应的头文件引入进来,下面的代码基本都是从 com_example_shenjiaqi_myapplication_JNIUtils.h 中复制粘贴过来的一部分,然后稍加修改。修改的地方主要有 getString 的两个参数和里面的简单实现,参数方面就是加了 env 和 jclass 两个字段。函数里面的实现呢,就是简单的返回一个字符串 “Hello World From JNI!!!!!” , 大家现在就需要知道如果要在这里返回一个字符串就必须要通过 env-> NewStringUTF("xxxxxx"); 这行代码
目录结构如下图:
文章图片
NDK 配置接下来我们在
build.gradle
中添加 ndk 配置:文章图片
运行项目了,发现报错:
文章图片
不要慌,说是让我们采用 CMake 或者 ndk-build 方式来捷成。这时候我们打开 build 目录,如下图:
文章图片
其中,有个文件叫做 Android.mk ,需要这个来为我们生成 .so 文件,操作步骤如下,先把目录切换到 Android 视角下,不然会没有 Link C++ Project with Gradle 这个选项的 :
文章图片
在弹窗中选择 ndk-build ,找到之前说的 Android.mk 这个文件。
文章图片
这时候,我们再回到 JNIUtils
.java ,发现没有飘红了。但是运行编译后会出现错误提示:
文章图片
说是没有找到 getString()的实现方法。在 JNIUtils 中添加如下代码,即可解决上面的问题。可以发现在 build 中已经生成相应的 .so 文件了。
public class JNIUtils { static { System.loadLibrary("JNIHello"); } public static native String getString(); }
再次编译,运行成功:
文章图片
文章图片
demo 地址: Android jni 编程实例
参考文献:
1、将应用代码由eclipse导入Android studio的方法NDK-Build和Cmake两种方法(以android_serialport_api为例)
2、NDK开发(一)————如何在Android Studio下进行NDK开发
3、使用AndroidStudio编写第一个JNI程序
【Android studio 下 JNI 开发实例】
推荐阅读
- Android自定义权限与使用
- 关于手机已经设置成开发者模式但是Android studio不能识别问题
- Application 简介 常用方式
- appium windows环境环境
- 安卓存储资源
- Android APK 包名以及Activity 查询方式
- appium mac环境搭建
- CSAPP —— 信息的表示和处理
- form编码方式application/x-www-form-urlencoded和multipart/form-data的区别