SWIG是一个编译时软件开发工具,它能生成将用c/c++编写的原生模块与baokuo包括java在内的其他变成语言进行联接的必要代码。
1.下载、安装和配置
SWIG的下载:
http://www.swig.org
下载完成后,解压出来。将swig的根目录添加到系统环境变量中。
检测配置是否成功。
2.试用SWIG
(1).创建ndk项目
(2).修改CMakeLists文件
cmake_minimum_required(VERSION 3.4.1)
#寻找swig
find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})
set(JAVA_GEN_PACKAGE "com.example.ndk2.jni")
string(REPLACE "." "/" JAVA_GEN_SUBDIR ${JAVA_GEN_PACKAGE})
set(JAVA_GEN_DIR ${Project_SOURCE_DIR}/../java/${JAVA_GEN_SUBDIR})
#文件输出目录
set(CMAKE_SWIG_OUTDIR ${JAVA_GEN_DIR})
set(CMAKE_SWIG_FLAGS -c++ -package ${JAVA_GEN_PACKAGE})
#在c ++模式下调用SWIG
set_property(SOURCE see.i PROPERTY CPLUSPLUS ON)
swig_add_library(See LANGUAGE java SOURCES See.i)
(3).创建.i文件
see.i
/*模块名see*/
%module See
//将自定义的代码包含在生成的文件中,例如编译生成的代码所需的头文件
/**
* %<section>%{
*
* %}
* <section>参数介绍:
* begin:在生成的文件的开头位置放置代码
* runtime:将代码块放在swig的内部类型检查及其他支持函数之后
* header:将代码块放在header部分,这部分在头文件和其他帮助函数之后,这是生成的文件中插入
* 代码的默认位置,可以缩写为%{...%}
* wapper:将代码块放在生成的封装函数之后
* init:将代码块放入装入时初始化模块的函数中。
*/
%{
#include <unistd.h>
%}
typedef unsigned int uid_t;
extern uid_t getuid(void);
(4).运行后生成文件如下
(5).调用后看效果
TextView tv = findViewById(R.id.sample_text);
tv.setText(com.example.ndk2.jni.See.getuid() + "");
3.SWIG的全局变量
在.i文件中声明
%module See
%{
#include <unistd.h>
int counter;
%}
extern int counter;
运行,SWIG生成getter和settter方法,java调用getter和settter来访问全局变量。
public class See {
public static void setCounter(int value) {
SeeJNI.counter_set(value);
}
public static int getCounter() {
return SeeJNI.counter_get();
}
public static long getuid() {
return SeeJNI.getuid();
}
}
4.常量
.i接口文件中用#define或%constant预处理指令定义
%module See
#define Max 9999
%constant int MAX2 = 2222;
程序讯运行后,会生成Constant的java接口文件,如下:
public interface SeeConstants {
public final static int Max = SeeJNI.Max_get();
public final static int MAX2 = SeeJNI.MAX2_get();
}
%javaconst
告诉SWIG生成编译时常量还是运行库常量。
作用体现在SeeConstants文件中
public interface SeeConstants {
public final static int Max = 9999;
public final static int MAX2 = SeeJNI.MAX2_get();
}
5.只读变量
%immutable标记只读变量
.i接口文件
/*模块名see*/
%module See
//只读变量
%immutable;
extern int readOnlu;
%mutable;
extern int rw;
%{
#include <unistd.h>
int rw;
int readOnlu;
%}
生成的文件
public class See {
//readOnlu不生成
public static int getReadOnlu() {
return SeeJNI.readOnlu_get();
}
public static void setRw(int value) {
SeeJNI.rw_set(value);
}
public static int getRw() {
return SeeJNI.rw_get();
}
}
6.枚举
(1)匿名枚举
.i文件中声明枚举类型
%module See
enum {one =1,two =2,three,four};
%{
#include <unistd.h>
enum {one =1,two =2,three,four};
%}
生成文件 SeeConstants
public interface SeeConstants {
public final static int one = SeeJNI.one_get();
public final static int two = SeeJNI.two_get();
public final static int three = SeeJNI.three_get();
public final static int four = SeeJNI.four_get();
}
(2)类型-安全
命名枚举展示给java的是类型-安全枚举。
/*模块名see*/
%module See
enum Num{one =1,two =2,three,four};
%{
#include <unistd.h>
enum Num{one,two,three,four};
%}
SWIG会为命名枚举定义一个单独的类。这类枚举比基于常量的方法更安全。
public final class Num {
public final static Num one = new Num("one", SeeJNI.one_get());
public final static Num two = new Num("two", SeeJNI.two_get());
public final static Num three = new Num("three");
public final static Num four = new Num("four");
..............
(3)类型-不安全
/*模块名see*/
%module See
//类型不安全
%include "enumtypeunsafe.swg"
enum Num{one =1,two =2,three,four};
%{
#include <unistd.h>
enum Num{one,two,three,four};
%}
生成的文件如下:
public final class Num {
public final static int one = SeeJNI.one_get();
public final static int two = SeeJNI.two_get();
public final static int three = SeeJNI.three_get();
public final static int four = SeeJNI.four_get();
}
(4)java枚举
/*模块名see*/
%module See
//类型不安全
%include "enums.swg"
enum Num{one =1,two =2,three,four};
%{
#include <unistd.h>
enum Num{one,two,three,four};
%}
生成的文件
public enum Num {
one(SeeJNI.one_get()),
two(SeeJNI.two_get()),
three,
four;
......
}
7.结构体
SWIG支持结构体。.i接口文件中声明结构体。
/*模块名see*/
%module See
struct Ponit{
int x;
int y;
};
%{
struct Ponit{
int x;
int y;
};
%}
会生成Ponit类
public class Ponit {
private transient long swigCPtr;
protected transient boolean swigCMemOwn;
protected Ponit(long cPtr, boolean cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = cPtr;
}
protected static long getCPtr(Ponit obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}
@SuppressWarnings("deprecation")
protected void finalize() {
delete();
}
public synchronized void delete() {
if (swigCPtr != 0) {
if (swigCMemOwn) {
swigCMemOwn = false;
SeeJNI.delete_Ponit(swigCPtr);
}
swigCPtr = 0;
}
}
public void setX(int value) {
SeeJNI.Ponit_x_set(swigCPtr, this, value);
}
public int getX() {
return SeeJNI.Ponit_x_get(swigCPtr, this);
}
public void setY(int value) {
SeeJNI.Ponit_y_set(swigCPtr, this, value);
}
public int getY() {
return SeeJNI.Ponit_y_get(swigCPtr, this);
}
public Ponit() {
this(SeeJNI.new_Ponit(), true);
}
}