三、Android版本:

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_c++

1、ndk开发必要的基础知识:
原本想配套写一下ndk开发方面的基础和步骤,但老实说,这也并非三言两语就能描述清楚的,好在网上已经有现存的文章了,经过该作者同意,本人就引用一下:@zzyyppqq thanks

关于开发工具的选择

2014年的时候,基本都是使用eclipse来开发,使用android mk来编译ndk程序。但是目前都是使用AndroidStudio做为开发和编译ndk的工具,因此我们关注AndroidStudio上的实现和编译。

.mk构建系统demo

zzyyppqq-超级简单的Android Studio jni 实现(无需命令行)
通过使用ndk提供的工具来编译ndk程序。
根据上述文档,总结一下开发ndk的流程以及编译过程:

1) public native String getString();在类中用native关键字声明一个成员方法
2) 调用javah程序,自动生成navtie方法对应的.h文件,得到可怕的c/c++函数原型:
   JNIEXPORT jstring JNICALL Java_com_zhangyp_higo_myndk_MyNdk_getString (JNIEnv *, jobject);
3) 在.c或.cpp文件中实现上面javah自动生成的函数
4) 编写mk文件,用于编译生成.so(类linux系统的动态链接库)文件
   包括Application.mk和android.mk这两个mk文件
5) 你可以先调用一下ndk-build clear命令清理一下工程缓存之类的(有时不清理会出现一些问题),然后再调用ndk-build命令用于生成.so文件
6) 在android 类中使用static { System.loadLibrary("MyLibrary"); }方式,将刚才生成的.so加载进来,然后就按照正常的android开发流程进行native函数调用了。

由此可见,Ndk的开发也不是很难,只要记住上面几个步骤,就可以进行简单的ndk开发。

要点:能够被java调用的c/c++库必须是以.so动态链接库方式链接进来的,但是在ios开发中,必须要使用.lib静态链接库方式链入,这是两者很大的区别。
技术在发展,时代在进步。随着AndroidStudio的普及,引入了新的构建系统:gradle系统后,我们可以不用写.mk文件了
要知道,一个稍微复杂一点的ndk项目,要在.mk中撰写很多命令,单单.mk命令参考就有n多页,太可怕了!!
gradle构建系统Demo

zzyyppqq-Android Studio使用gradle-experimental构建NDK工程(无需Android.mk、Application.mk文件)

gradle构建注意点:
1) gradle使用ndk编译,必须要使用:gradle-experimental 插件,这个需要到android相关网站去下载的
2) 一定要注意gradle-experimental的版本号与gradle的对应关系,不能搞混了。曾经我因为没注意这一点,导致掉在坑里两天没出来。太痛苦了(见下图说明)。
3) 一定要按照上文提到的步骤,一步步设置,zzyyppqq的gradle设置流程很清楚,就当武功口诀来使用,否则掉在坑里你也不知道怎么回事。
4) 代码的开发流程和.mk demo差不多,只是不需要编写.mk文件以及调用ndk-build命令了,这是使用gradle-experimental获得的最大好处。

再次强调一下:

gradle-experimental插件与gradle的版本号对应关系图:

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_c++_02

gradle构建文档参考,请戳这里

使用gradle构建系统后,虽然省掉了.mk文件的撰写,但是很麻烦:
1)需要在java类中用native声明方法
2)需要用Javah生成.h头文件
3)需要在实现.h中的函数时候,很熟悉java中的数据类型和c/c++中的数据类型之间的对应关系
例如JNIEnv,jobject,jstring等,还有其他很多数据类型,可以自己参看ndk开发文档。
4)需要有时调用如此长名字的函数:Java_com_zhangyp_higo_myndk_MyNdk_getString
有没有办法解决上面提到的那些问题呢?………我们的猪脚…….SWIG库……出场了……

有了SWIG后,我们就可以正常方式编写C/C++代码,然后自动包装成ndk jni调用,不需要了解android ndk数据类型,不需要javah调用,也不需要native声明,Let’s go! go! go! go!

2、SWIG篇章:

SWIG简介:

SWIG全称是Simplified Wrapper and Interface Generator,官方网站是http://www.swig.org/。SWIG是一个开发工具,能够将使用C或者C++编写的软件与其他各种高级编程语言进行嵌入联接。

SWIG目前支持输出的语言列表:

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_c++_03

SWIG的安装:
1)很简单,官网下载,解压到**最好没有中文字符的**文件夹下
2)由于要使用swig.exe命令行程序,最好设置一下环境变量
3) 在命令行中输入swig -help,出现各种命令参数,说明环境变量设置成功。

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_android_04

AndroidStudio与SWIG配合流程:
1) 严格按照zzyyppqq的文档配置好gradle以及gradle-experimental的参数
2) 在AndroidStudio中按zzyyppqq文档创建jni文件夹
3) 将用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一)中的
    calendarCore.h和calendarCore.cpp文件复制到jni文件夹下面,如下图:

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_ios_05

4)  编写swig.i文件(接口文件),用于描述如何输出.h文件为java接口,.i表示interface

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_ios_06

5) 编写generate.bat文件用于调用swig.exe自动生成接口文件(很多个,具体我们图示)

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_c++_07

双击运行bat前后效果如下:

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_c++_08

 6) swig转换的流程分析:

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_c++_09

7) c/c++中的struct和class会自动生成java对应的类,并自动添加(如果需要的话)get/set函数:请查看CGPoint.java SCalendar.java等源码

8) c/c++中的输出参数,例如void calendar_get_year_month(SCalendar* calendar,int* year,int* month);
int* year 和 int* month是传地址方式,将结果传出来,对于java来说,必须要装箱(boxing)以及拆箱(unboxing)
将int传值方式变为传引用方式,因此自动生成了SWIG_TYPE_p_int.java类,用于将值类型变为引用类型
到此为止,SWIG的使命已经完成了,接下来纯粹属于Android java的控件开发,其中会经常调用上面分析过的由SWIG自动生成的Java类。

3、 Android和ISO版Calendar的源码:

Android源码不再分析,实现细节可以参考
calendar IO实现


Android和IOS版所有的源码请狠狠地戳这里
https://github.com/jackyblf/

(android/swig实现)用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(三)_c++_10


4、再次强调一下为什么用c/c++。基于虚拟机的源码实在太容易反编译了,c#/java/as3等代码,借助于一些工具,不到一分钟就可以将源码和资源全部反编译出来。大家可以下载一下微信android或faceu android版,反编译后发现,核心代码都在.so文件中,好多.so文件啊!


5、 到此,c/c++结合ios/android原生开发的文章结束了,花了两个礼拜,将近13000字。也算是呕心沥血吧。 如果觉得有用,请关注我一下,谢谢

说明:

关于一些原创的文章,除非是一些第三方经典源码分析,否则我一定会提供相应的demo。