Android下使用JNI笔记

本文详细介绍了JNI(Java Native Interface)的原理、使用方法及其实现步骤,包括环境配置、代码编写、编译运行等关键环节。通过实例演示,展示了如何在Android开发中利用JNI嵌入c/c++文件,以提高程序运行效率和保护商业机密。同时,文章对比了未使用JNI与使用JNI时源代码和反编译结果的区别,进一步阐述了JNI在实际开发中的价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.1 cygwin(仿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文件并查看,但是该文件是一对二进制代码,要看懂表示压力很大。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值