Android JNI
为什么用 C
Android 开发中有时要用 c/c++编写一些代码,一般基于以下考量:
1. 众所周知,利用 SDK 编写的代码,生成的 APK,很容易就可以反编译了,安全性极为不高,而利用 NDK 开发的库,不容易被反编译,保密性,安全性都提高了。
2. C&C++的代码运行速度和效率都比 java 快很多。
怎么用
由于 Android 的应用层的类都是以 Java 写的,这些 Java 类编译为 Dex 型式的 Bytecode 之后,必须靠 Dalvik 虚拟机(VM: Virtual Machine)来执行。VM 在 Android 平台里,扮演很重要的角色。
此外,在执行 Java 类的过程中,如果 Java 类需要与 C 组件沟通时,VM 就会去载入 C
组件,然后让 Java 的函数顺利地调用到 C 组件的函数。此时,VM 扮演着桥梁的角色,让 Java
与 C 组件能通过标准的 JNI 介面而相互沟通。
应用层的 Java 类是在虚拟机(VM: Vitual Machine)上执行的,而 C 件不是在 VM 上执行,那么 Java 程式又如何要求 VM 去载入(Load)所指定的 C 组件呢? 可使用下述指令:
System.loadLibrary("#####");
这要求 VM 去载入 Android 的/system/lib/libmedia_jni.so 档案。载入*.so 之后,Java 类与
*.so 档案就汇合起来,一起执行了。
怎么生成 so 库呢,在 Android 开发中我们使用 NDK 来生成 so 库。NDK 全称为 native development kit 本地语言(C&C++)开发包。而对应的是经常接触的 Android-SDK,(software development kit)软件开发包(只支持 java 语言开发)。
简单来说利用 NDK,可以开发纯 C&C++的代码,然后编译成库,让利用 Android-SDK 开发的Java 程序调用。NDK 开发的可以称之为底层开发或者 jni(java native interface)层开发。
流程
用 NDK 生成 so 库肯定要配置 NDK 开发环境,在 Android studio 中配置 NDK 环境很简单
1. 网络下载 NDK 解压,拷贝到英文目录下
2. 在 Android studio 中配置路径,然后 Build->Make Project
3. 在 gradle.properties 中添加 android.useDeprecatedNdk=true
4. 在 build.gradle 中写生成 so 库的名称,跟支持的 cpu 架构
5. 写 native 方法,创建 JniUtils 类,这里创建了两个方法 sayHello(),add(int a,int b)方法;
6. 然后 Build->下 Clean Project,Rebulid Project 依次执行
生成 classes 文件夹,没有生成的话,再依次执行 Clean Project,Rebulid Project
7. 打开 Android Studio 的 Terminal ,输入 cd app/build/intermediates/classes/debug 回车再输入 javah -jni com.example.liu.myapplication.JniUtils 回车(注意:javah -jni 后加的是含有 native 方法的类的全类名)然后关闭 Terminal,必须关闭(不然最后运行 module 时,无法编译),这时候打开 build/intermediates/classes/debug/com_example_liu_myapplication_JniUtils.h
8. 在 main 目录下新建文件夹 jni 把 com_example_liu_myapplication_JniUtils.h 拷贝或复制到该目录下然后在该目录下新建一个 Hello 名字的 c 文件导入 com_example_liu_myapplication_JniUtils.h头,写 c 函数
9. 到这一步已经写好了 c 函数,native 方法也写好了只剩 java 代码调用了,在布局文件中写两个写两个 textview,一个 button,让 button 点击是,调用两个 native 方法,并将返回结果分别显示到 textview 上。
布局文件如下
调用成功,查看 build-intermediates-ndk-debug-lib 下会发现,生成了三种架构的 so 库。
11. 直接使用 so 库就比较简单了分以下几步:
① 在 main 下新建 jniLibs 目录将 so 库拷贝到该目录下
② 在 main-java 下新建 JniUtils 的原来引用的报名,并将 JniUtils 拷贝到该目录下
③ 直接调用就可以了