Android平台调用c++

少年恃险若平地,独倚长剑凌清秋。这篇文章主要讲述Android平台调用c++相关的知识,希望能为你提供帮助。

小白:java代码中,为什么不能直接写c或c++代码?而oc代码却可以直接写!
【Android平台调用c++】小程:你可以写,只是编译不过而已。
小白:那不就是不能写嘛!
不管是编译到jvm,还是dalvik上运行,java的编译器都不会直接生成执行文件,而只是生成字节码(表现为class文件,或者是经过转换的dex文件),这跟c/c++编译器的做法大为不同,而很可能因为这个原因,使得java中不能参杂c/c++代码,而objective-c就可以混编c/c++,因为它的编译器直接生成执行文件。
那java语言就不能使用c++代码了吗?有问题,就有解决办法,办法是使用JNI。
JNI(java native interface,即java本地接口)的出现,可以解决java与c++交互的问题,并且不仅限于c++。
小白:可是,我的android程序,为什么要调用c++的代码呢?
小程:事出有因,比如已经实现某个功能的是c++代码而非java代码,比如要进行大量的数据运算而c++的执行性能远在java之上,比如要调用一些驱动类的接口,比如...
本文演示java如何调用c++的代码,即jni的使用。
jni层,可以分为jni上层,跟jni下层。
jni上层用java实现,jni下层用c/c++实现。
大概的调用关系是这样的:
Android平台调用c++

文章图片

小程接下具体介绍jni上下层的实现,并介绍如何生成so库(so库代表了c++实现的功能)并调用它。
(1)实现jni上层随便找一个java类(或者新建一个),然后在里面声明一个native方法,就实现了jni上层。
比如,创建一个Android Studio项目,并且有这样的native方法声明:
Android平台调用c++

文章图片

至此,就已经建立了jni上层。
(2)实现jni下层java代码调用jni上层的native函数时,会调用到c++的什么函数?这里需要有映射的关系。
建立起这个映射,有两个办法。
办法一:使用签名对于native方法,使用javah,可以抽取出对应的签名,然后c++实现这个签名的函数即可。
可以这样生成签名:
Android平台调用c++

文章图片

这个.h文件的内容是这样的:
Android平台调用c++

文章图片

那一长串就是对应的签名,c++代码实现这个函数,这样java在调用jni上层声明的native函数时,就会调用到这里面来。显然,一旦建立了映射,jni上层与下层就不能再改名字(除非重新签名)。
小白:一大串的,还不给改名,大不人性化了。
小程:要改名就新增接口吧,或者,使用第二个办法。
办法二:使用RegisterNatives在jni层加载时,调用RegisterNatives。
这种办法,没有使用javah生成固定的签名,而是使用RegisterNatives来建立navtive方法与具体的实现的关联,具体实现可随意命名。
在JNI_onLoad函数内,触发RegisterNatives的调用:
Android平台调用c++

文章图片

Android平台调用c++

文章图片

在解决掉jni上下层的映射问题后,就是natvie方法的具体实现了。这里介绍如何生成动态链接so库。
在项目的根目录中,创建一个jni目录,在里面写c/c++代码与编译脚本,目录结构是这样的:
Android平台调用c++

文章图片

impl.c的内容:
Android平台调用c++

文章图片

脚本Android.mk的内容:
Android平台调用c++

文章图片

执行ndk-build,生成so库:
Android平台调用c++

文章图片

Android平台调用c++

文章图片

可以用readelf查看so库:
Android平台调用c++

文章图片

这里涉及到编译脚本(Android.mk)的规则、smalis语言特征(jni的数据类型等),还有ndk-build的使用等知识,小程不展开了,读者可以关注“广州小程”微信公众号,并获取后续的更新。
(3)调用jni层在java层调用native方法,比如:
Android平台调用c++

文章图片

执行这个程序,可以看到输出:
Android平台调用c++

文章图片

到此,如何在Android平台调用c++的实现就介绍完毕了。
总结一下,本文介绍了如何在Android平台调用c++的实现,演示了jni层的创建与编译出so库,并且调用了so库。读者可以把这部分知识应用到实际的Android项目中。

    推荐阅读