JNI简介


Java Native Interface (JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI 是本地编程接口,它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行交互操作。简而言之,JNI就是使得在Java或者Android中嵌入其他语言的接口,后面我们只提及嵌入c/c++的知识。

JNI的目的


1.保密性好。我们都知道apk文件没有采取相关措施的话很容易被反编译出来,这无论对Android程序员,还是企业的商业机密来说都是很忌讳。而采取JNI嵌入c/c++编译后的文件,使得被反编译的难度大大增加。
2.嵌入c/c++文件,使得程序运行效率高。由于java和Android都是很跑在VM上的,故相比与直接跑在真机上的c/c++效率会偏低。但是使用JNI必然会使得程序的复杂性大大增加,故开发时需要在两者之间找到平衡。

JNI的使用


1、环境的配置

1.1cygwin(仿Linux环境编译c/c++文件),用来编译文件。
下载地址:http://www.cygwin.com

下载完成后双击运行setup.exe,可以看到向导界面如下:


点击下一步,此时让你选择安装方式:
1)Install fromInternet:直接从Internet上下载并立即安装(安装完成后,下载好的安装文件并不会被删除,而是仍然被保留,以便下次再安装)。
2)Download WithoutInstalling:只是将安装文件下载到本地,但暂时不安装。
3)Install from Local Directory:不下载安装文件,直接从本地某个含有安装文件的目录进行安装。
选择第一项,点击下一步:

选择要安装的目录,注意,最好不要放到有中文和空格的目录里,似乎会造成安装出问题,其它选项不用变,之后点下一步:


上一步是选择安装cygwin的目录,这个是选择你下载的安装包所在的目录,默认是你运行setup.exe的目录(就是你下载的可执行文件setup.exe所在的目录),我放在了f:\download目录下,然后点击下一步。


此时你共有三种连接方式选择:

1)Direct Connection:直接连接。
2)Use IE5 Settings:使用IE的连接参数设置进行连接。

3)Use HTTP/FTP Proxy:使用HTTP或FTP代理服务器进行连接(需要输入服务器地址、端口号)。


用户可以 根据自己的网络连接的实情情况进行选择,一般正常情况下,均选择第一种,也就是直接连接方式。然后再点击“下一步”,选择要下载的站点,然后点击下一步:


此时会出现一个要下载安装的组件包列表:


(或者是展开Devel,只下载里面有关于make,G++,GCC,GNU的文件)

点击下一步,进入安装过程:


安装完成后点击完成结束安装。
下面测试一下cygwin是不是已经安装好了:

运行cygwin,在弹出的命令行窗口输入:cygcheck -c cygwin命令,会打印出当前cygwin的版本和运行状态,如果status是ok的话,则cygwin运行正常。然后依次输入gcc –version,g++--version,make –version,gdb –version进行测试,如果都打印出版本信息和一些描述信息,cygwin就算是安装完成了。


1.2安装NDK
下载地址:
http://dl.google.com/android/ndk/android-ndk-r4-windows.zip
http://androidappdocs.appspot.com/sdk/ndk/index.html
http://developer.android.com/sdk/ndk/overview.html
设置NDK环境变量
首先找cygwin的安装目录,找到“home/<你的用户名>/.bash_profile”文件。
我的是D:/cygwin/home/Mr_Shen/.bash_profile,打开bash_profile文件,添加如下内容(根据具体的ndk安装目录,我的是D:\\Android\\android-ndk-r9):
NDK=/cygdrive/d/Android/android-ndk-r9
export NDK

其中NDK这个名字是随便取的,为了方面以后使用方便,选个简短的名字,然后保存。运行cygwin,输入echo $NDK,如果输出上面配置的/cygdrive/d/Android/android-ndk-r9信息,则表明环境变量设置成功了。


2、代码实现

在项目中建立jni目录,并在目录里写Android.mk文件,.c源文件(或者.cpp,可能还有.h文件)如下图


Android.mk文件的实现


说明:我自己的看法是,有点类似批处理文件。Android.mk文件是一个实现make功能的文件,指定路径(固定格式),清除全局变量的缓存(固定格式),将编译出来的文件名,提供需要编译的文件名,按照动态库还是静态库的格式编译,这些都在这里事先规定了。

头文件的实现


源文件的实现


说明:这里需要注意的是返回类型jstring,这是JNI的数据类型,相当于Java中的string类型,另外还有jint,jlong,jchar,其转化的对应关系由头文件<jni.h>给出。这里谈谈个人的一些理解,这些类型的转化主要是在返回给java文件的时候用到,如上面的jstring;其他在h,c/cpp文件中保持原来的数据格式即可,例如上面的char*类型。
这个用于jni调用的函数的函数名格式固定,为“jni数据类型 Java_<包名>_<类名>_函数名”,其中“.”用“_”来代替。由上面的函数名可以知道,返回一个string类型的数据给java文件调用者,包名为“com.example.hellojni”,类名为“HelloJni”,函数名为“GetStr()”。

上述代码编写完成之后,开始编译运行,打开cygwin终端,并转到你的工程的目录下,下面是我的例子的一个截图:


然后运行编译命令:

$NDK/ndk-build(这里NDK变量是我们前面设置好的路径变量)


上述三行提示信息,表示已经成功编译并安装到你的项目中,有时eclipse并没有及时刷新,可以通过右键点击项目,选择refresh刷新项目,这时可以看到libs目录下多了个armeabi子文件夹,在该文件夹下就有我们编译生成的.so文件


Java文件的实现


首先在文件中声明方法,方法名前的关键字“native”不能缺失。本程序用的是静态导入库文件,即上图中的static以及其作用域里的代码。(也可以动态导入,直接在onClick方法里添加“System.loadLibrary(“stringFromJNI”)”这句代码即可)

运行程序,成功运行。


其他
1、用反编译文件测试

未用JNI时,源代码以及反编译出来的代码对比如下图:



可以看到源码暴露无遗。使用JNI,对比图如下:



被反编译出来的代码中找不到GetStr()方法的实现,唯一的办法就是找到libstringFromJNI.so文件并查看,但是该文件是一对二进制代码,要看懂表示压力很大。

更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. 一款常用的 Squid 日志分析工具
  3. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  4. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  5. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  6. 用android ksoap2 上传、下载数据
  7. Java采用JNI调用VC++生成的dll(Java与C++交互)
  8. android调用相应的应用市场进行评价功能开发
  9. Android中的绘制机制

随机推荐

  1. android APP隐私政策弹框的实现代码实例
  2. EventBus从入门到装逼,源码分析,手撸框架
  3. android 颜色 获取
  4. Android多线程
  5. 数据短信接收
  6. Android(安卓)WiFi 电源管理
  7. Android:你不能忽略的代码命名规范
  8. Android 时间获取总结
  9. [Android] The wiki of EoeAndroid
  10. alipay--- Android(安卓)集成支付宝SDK实