Android JNI/NDK 开发指南

JNI 概述

JNI 是 Java 语言提供的 Java 和 C/C++ 相互沟通的机制,Java 可以通过 JNI 调用本地的 C/C++ 代码,本地的 C/C++ 的代码也可以调用 Java 代码。JNI 是本地编程接口,Java 和 C/C++ 互相通过的接口。Java 通过 C/C++ 使用本地的代码的一个关键性原因在于 C/C++ 代码的高效性。 代码和其他语言写的代码进行交互。

相信很多做过 Java 或 Android 开发的朋友经常会接触到 JNI 方面的技术,由其做过 Android 的朋友,为了应用的安全性,会将一些复杂的逻辑和算法通过本地代码(C或C++)来实现,然后打包成.so动态库文件,并提供 Java 接口供应用层调用,这么做的目的主要就是为了提供应用的安全性,防止被反编译后被不法分子分析应用的逻辑。当然打包成.so也不能说完全安全了,只是相对反编译 Java 的 class 字节码文件来说,反汇编.so动态库来分析程序的逻辑要复杂得多,没那么容易被破解。比如百度开放平台提供的定位服务、搜索服务、LBS 服务、推送服务的Android SDK,除了Java接口的jar包之外,还有一个.so文件,这个.so就是实现了Java层定义的native接口的动态库。

以前公司有一个 JavaWeb 的项目,其中有一个用户注册的模块,需要验证用户的手机号(流程大家都懂的),由于这个项目的用户量不大,没用采用运营商的短信网关接口,直接采购了一台 16 口的短信猫设备和 SIM 卡来解决这个事情。由于短信猫设备只提供了 C 的接口,而 Java 是不能直接与 C 语言进行交互的,所以 JNI 就派上用场了,先在 Java 层定义好发送短信、接收短信、短信发送队列等相关 native 方法,然后用 javah 命令将定义 Java native 接口的 class 字节码文件生成.h头文件(这个后面会讲到),最后用设备场商提供的 C 接口来实现 java 的 native 方法,完了之后编译成.dll或.so动态库,提供给 Java 程序使用即可。

JNI 在 Cocos2d-x 游戏引擎中也经常用到,该引擎是用纯 C++ 开发的,而且是跨平台的,依托 C++ 的跨平台特性,只需用 C++ 编写一次逻辑,就可以将游戏打包发布到不同的平台(IOS、Android、WinPhone、黑莓、Linux、Windows),打包发布的细节就不在这里讨论了。如果游戏要发布到 Android 平台,开发过程当中,少不了 C++ 层和 Java 层进行交互,比如游戏当中要打开一个网页、播放一段视频或打开一个新的窗口等,这些在 C++ 层实现是非常麻烦的,如果用 Android 应用层提供的 API 就变得相当容易。所以这时就不得不写 JNI 来完成这些功能的需求。当然这些常用的 JNI 操作,Cocos2d-x 引擎进行了封装,相关的接口定义在 JniHelper.cpp这个类中,可以拿来直接使用。(后面会有例子详细介绍)

虽然现在的物联网和智能家居行业还处于萌芽状态,但随着这个时代在技术的创新与不断改进的发展下,想象 5 年后,物联网和智能家居行业真正成熟起来,由于 Android 系统的开源,自然会被各大硬件场商所采用,相当于这几年 Android 智能手机的市场一样,仍然可能会处于移动智能终端的霸主地位。你可能会问,但这和 JNI 和有什么关系呢?当各种设备接入互联网的同时,自然少不了人机交互的应用程序,当应用程序需要调用硬件特定的功能时,此时只能通过 C 或 C++ 封装对应功能的 JNI 接口来供上层应用使用。比如要用手机中的 app 控制家里的电灯、窗帘、冰箱、空调等一切智能的电子设备时,自然少不了应用要和底层硬件进行通讯,至于各种智能设备的运行控制,自然是由厂商来实现,他们只需提供操作设备相关功能的接口即可。虽然厂商会封装好 JNI 接口,但我们也要了解下 JNI 与 Java 通讯的原理,以便我们在开发过程当中遇到问题时,能够快速定位到问题。

NDK 概述

NDK 是一系列工具的集合。它提供了一系列的工具,帮助开发者快速开发 C(或C++)的动态库,并能自动将 so 和 Java 应用一起打包成 apk。这些工具对开发者的帮助是巨大的。它集成了交叉编译器,并提供了相应的 mk 文件隔离 CPU、平台、ABI 等差异,开发人员只需要简单修改 mk 文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出 so。它可以自动地将 so 和 Java 应用一起打包,极大地减轻了开发人员的打包工作。
NDK 产生的背景
Android 平台从诞生起,就已经支持 C、C++ 开发。众所周知,Android 的 SDK 基于 Java 实现,这意味着基于Android SDK 进行开发的第三方应用都必须使用 Java 语言。但这并不等同于“第三方应用只能使用 Java”。在Android SDK 首次发布时,Google 就宣称其虚拟机 Dalvik 支持 JNI 编程方式,也就是第三方应用完全可以通过 JNI 调用自己的 C 动态库,即在 Android 平台上,“Java+C”的编程方式是一直都可以实现的。
不过,Google 也表示,使用原生 SDK 编程相比 Dalvik 虚拟机也有一些劣势,Android SDK 文档里,找不到任何 JNI 方面的帮助。即使第三方应用开发者使用 JNI 完成了自己的 C 动态链接库(so)开发,但是 so 如何和应用程序一起打包成 apk 并发布?这里面也存在技术障碍。比如程序更加复杂,兼容性难以保障,无法访问Framework API,Debug 难度更大等。开发者需要自行斟酌使用。
于是 NDK 就应运而生了。NDK 全称是 Native Development Kit。
NDK 的发布,使“Java+C”的开发方式终于转正,成为官方支持的开发方式。NDK 将是 Android 平台支持 C 开发的开端。

NDK 优点:
代码的保护。由于 apk 的 java 层代码很容易被反编译,而 C/C++ 库反汇难度较大。
可以方便地使用现存的开源库。大部分现存的开源库都是用 C/C++ 代码编写的。
提高程序的执行效率。将要求高性能的应用逻辑使用 C 开发,从而提高应用程序的执行效率。
便于移植。用 C/C++ 写得库可以方便在其他的嵌入式平台上再次使用。
NDK 提供了一份稳定、功能有限的 API 头文件声明

Google 明确声明该 API 是稳定的,在后续所有版本中都稳定支持当前发布的 API。从该版本的 NDK 中看出,这些 API 支持的功能非常有限,包含有:C 标准库(libc)、标准数学库(libm)、压缩库(libz)、Log 库(liblog)。


JNI 的详细使用:JNI/NDK 开发指南

猜你喜欢

转载自blog.csdn.net/gulanggege/article/details/79654899