SWIG与JAVA 交互最全开发指南一

项目背景

最近开始研究做移动端项目,但是本人基本是做了五六年的c++的底层研发,对C++的研发可以说是驾轻就熟了,但是对于android还是属于刚入门阶段,虽然断断续续做移动端也做了一年,但是没有一个系统的去研究过android,怎么才能结合两者的优势呢。我决定用C++写底层。

  • ANDROID是运行JAVA虚拟机层,编译的是字节码,效率不会太高,特别是密集型CPU计算。
  • 希望用更快速,更简单的方法调用已有的技术,而不用重新来一套。
  • 防止核心代码被别人反编译破解。
    所以我想到了使用SWIG封装技术。

使用SWIG介绍

SWIG是个帮助使用C或者C++编写的软件能与其它各种高级编程语言进行嵌入联接的开发工具。SWIG能应用于各种不同类型的语言包括常用脚本编译语言例如Perl, PHP, Python, Tcl, Ruby and PHP。支持语言列表中也包括非脚本编译语言,例如C#, Common Lisp (CLISP, Allegro CL, CFFI, UFFI), Java, Modula-3, OCAML以及R,甚至是编译器或者汇编的计划应用(Guile, MzScheme, Chicken)。SWIG普遍应用于创建高级语言解析或汇编程序环境,用户接口,作为一种用来测试C/C++或进行原型设计的工具。SWIG还能够导出XML或Lisp s-expressions格式的解析树。SWIG可以被自由使用,发布,修改用于商业或非商业中。

SWIG从C++到Android开发的五个步骤

SWIG是一个开源的C++到其他语言包装技术,你可以下载它的源码自己编译,也可以直接下载编译好的二进制包,如果没有啥特殊的需求,使用编译好的EXE就可以了。不用自己花心思去处理。从网上下载SWIG并下载一份官方文档,解压并将其目录加到PATH的环境目录中。

编写C++代码

与平常写C++代码没有区别,但是为了方便,一般情况下我们会写一个C++的接口文件,之后写一个实现类来集成那个接口

  1. c++的接口文件(ishapeprovider.h)
//这是一个读写SHAPE数据的接口类;文件名小写测
class IShapeProvider
{
public:
    //打开一个文件或者一个数据库
    virtual void openFile(const std::string& file_name) = 0;
    //添加一个记录到文件中,其中IFeature是一个自定义接口类;
    virtual void addFeatrue(IFeature* feature) = 0;
    //设置一个属性;
    virtual void setProperty(const std::string& key, const Variant& variant) = 0;
    //打开一个图层,ITable也是一个自定义接口类
#ifndef SWIG  //这个宏是SWIG的特有的宏,告诉SWIG在处理的时候不要将此函数暴露给JAVA,对C++代码不受影响
    virtual ITable* table(const std::string& table_name) = 0;
#endif
    //获取一个图层的外包范围
    #ifdef SWIG   //对于传指针的处理方式
    %apply void &OUTPUT{ (int* x,int* y,int*with,int*height};
#endif
    virtual void extent(int* x,int* y,int*with,int*height)=0;

//获取类的信息,由于toString方法在Java中的方法冲突,所以我们需要给该函数改一个名字
#ifdef SWIG
%rename (toJavaString)  toString;//()里面是修改之后的函数名字,toString是在C++的函数名字;
#endif
    virtual std::string toString()=0;

};
  1. C++的实现文件(shapeProvider.h)
class ShapeProvider:public IShapeProvider
{
public:
    //打开一个文件或者一个数据库
    virtual void openFile(const std::string& file_name)
    {
        //实现省略
    }
    //添加一个记录到文件中,其中IFeature是一个自定义接口类;
    virtual void addFeatrue(IFeature* feature)
    {
        //实现省略
    }
    //设置一个属性;
    virtual void setProperty(const std::string& key, const Variant& variant)
    {
        //实现省略
    }
    //打开一个图层,ITable也是一个自定义接口类
    virtual ITable* table(const std::string& table_name)
    {
        //实现省略
    }
       //其他实现....
private:
     void initTableInformaction() {}
private:
    QFile _file;//QT类
    OGRDriver* _driver;//GDAL类
    
};
  1. 类实例化封装类(classfactory.h)
class ClassFactory
{
public:
    //打开一个文件或者一个数据库
    virtual IShapeProvider* newInstance(const std::string& class_name) 
    {
//实现在CPP文件中
        if (class_name == "IShapeProvider")
        {
            return new ShapeProvider();
        }
    };
    virtual void releaseClass(IShapeProvider* shape_provider)
    {
        delete shape_provider;
    }

};

对于一个比较庞大的项目,按上面的方式去实现,有以下几个原因

  • 为了隐藏实现类的实现结构,暴露类的结构容易造成各种依赖问题;
  • swig技术以最简单的方式包装出去,特别是引用第三方库的时候,如果直接用一个实现类的头文件,那么就有可能需要依赖第三方库的头文件,在包装的时候就要考虑这个第三方头文件的问题。
  • 做框架接口与实现分离, 对内部实现的以及变量的改动不影响接口的修改,不用重新编译所有模块

写SWIG的i文件

%module(directors="1") dandelion_swig   //指定模块名 directors="1" 代表可以对C++的类在JAVA中继承
%{
    #include "ishapeprovider.h"   //在后面生成的dandelion_swig.cxx代码中包含的头文件
   #include "classfactory.h"
}%
  %include "ishapeprovider.h"   //将该头文件所有的类、宏定义、以及全局变量包装到JAVA中,生成对应的类
  %include "classfactory.h"  
//添加系统的一些文件,处理一些常用的基本类型,具体可以参考SWIG的帮助文档
%include stdint.i
%include carrays.i
%include windows.i
%include typemaps.i
#ifdef SWIGJAVA   //swig到java的swig预定义宏
%include <enums.swg>
%rename (toDString) toString;
#endif
//对于这种结构的定义,可以理解为改名,不改名在JAVA中是识别不了的,如智能指针
%template(JavaList) std::list<long>;
%template(IShapeProviderPtr) std::shared_ptr<IShapeProvider>;

i文件书写简要说明

STL/C++库的转化 swig提供了很多基本类型库的转化。如std::map 可以转成java的map,std::string 转成String
可以在C++写接口在JAVA中实现,如要对IShapeProvider接口用java 实现,需要调用
%feature("director") IShapeProvider ;
一般在c++文件中,可通过宏定义加入swig的代码,这样方便管理,当接口文件多了的时候要增加或者删除某些功能可一起删除。

使用SWIG将C++包装成JAVA类

SWIG生成的文件一个是CXX的C文件,以及一些JAVA的类文件,还有就是模块内的全局变量文件

  • swig 脚本编写
swig.exe -c++ -java -package com.simple.dandelion -outdir ./java_simple_wrapper/src/com/simple/dandelion -o ./java_simple_swig/src/java_dandelion_swig.cxx -Iswig_dandelion.i 

说明:

  • -c++ 指定当前语言是C++还是C,默认是C,只有这两种,没有其他的
  • -java 生成的包装语言,可以使其他任何一种支持的语言 如-python -csharp
  • -package 生成的java包名
  • -outdir java文件的输出目录
  • -o 输出的CXX文件的路径文件名
  • -I i文件路径(文件名必须紧跟参数)
  • swig 命令执行完成之后,将在当前路径下面生成以下几个文件
  • dandelion_swig_wrap.cxx c++文件,包装文件,将C++的类的方法转成C语言的函数
  • dandelion_swig.java 与SWIG定义中module名字同名的类
  • dandelion_swigJni.java c++类中的方法在此文件中转为java的静态方法,就是JAVA中的native方法
  • 其他的JAVA类为C++中对应的类

编译SO库

使用android stuido 新建一个包含C++支持的工程,使用CMAKE将dandelion_swig_wrap.cxx 编译为SO文件。以下是参考链接

将JAVA文件编译为JAR包

方法很简单,在android studio 中建立一个库项目,将SWIG生成的所有的JAVA文件按照包名建立路径,拷贝到所在包的路径下面,直接用android studio 编译就可以了。

android 调用so库使用

//MainActivity类
public class MainActivity extends QtActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        JavaNatives.init(this);
        String text=JavaNatives.stringFromJNI();
        TextView tv = (TextView) findViewById(R.id.simple_text);
        tv.setText(text);
    }
}
import  android.content.Context;
import  android.util.Log;
import  com.simple.dandelion.*;


public class JavaNatives {

    public static void init(Context context) {
        System.loadLibrary("simple");//本来模块调用的simple库
        System.loadLibrary("dandelion_swig");//swig包装的CXX文件生成的SO,加载顺序必须先加载其他库。
        ClassFactory class_factory=new ClassFactory(); //c++中的类
        IShapeProvider shape_provider=class_factory.newInstance("ShapeProvider");
        shape_provider.openFile("/sdcard/simple.shp");

    }
}

 

1人点赞

 

策划方案

 



作者:揽月凡尘
链接:https://www.jianshu.com/p/a91f4e3e20c3
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: SWIG是一个用于连接C/C++和其他编程语言的工具。它提供了一种简单的方式,可以通过自动生成中间代码来实现C/C++的功能与其他编程语言(如Java)之间的交互。 通过SWIG,我们可以将C代码转换为Java代码,并在Java中调用C库中的函数。这样做的好处是可以利用C/C++的高性能、底层控制和已有的库文件,并在Java中使用这些功能。 要将C代码转换为Java代码,我们需要这样做的步骤: 1. 创建一个SWIG接口文件,以描述C函数的输入和输出类型。这个接口文件使用SWIG定义的特定语法。 2. 使用SWIG运行器,将接口文件作为输入,并生成一个Java包含C函数的Java接口文件。 3. 创建Java代码,以断开连接的方式调用生成的Java接口文件中的C函数。 SWIG通过将C代码封装在JNI(Java Native Interface)调用中来实现C与Java交互。这允许Java代码直接调用C代码,并从C代码中返回结果。 使用SWIG进行C到Java转换可以使开发人员更加方便地利用两种语言的优点,提高开发效率和性能。SWIG还支持其他编程语言,如Python、Ruby和Perl,使C代码更容易与这些语言进行交互。 总之,SWIG是一个非常有用的工具,可以帮助在C/C++和Java之间实现无缝的交互,为开发人员提供了更多的灵活性和选择,并最大程度地利用现有的代码和库文件。 ### 回答2: Swig是一个开源工具,用于将C/C++代码转换为支持多种编程语言的代码,包括Java。使用Swig可以很方便地将C代码转换为Java代码。 转换C代码为Java需经过以下步骤: 1. 安装Swig:首先需要安装Swig工具,可以从Swig官方网站下载并按照指示进行安装。 2. 编写接口文件:接口文件是一个后缀名为.i的文件,用于定义需要转换的C代码和Java代码的映射关系。在接口文件中,需要指定需要转换的C函数的签名以及导出到Java的类、方法、成员变量等。 3. 生成包装代码:使用Swig生成器来生成C和Java代码的包装代码。通过运行类似以下命令来生成包装代码: ``` swig -java your_interface.i ``` 4. 编译和构建:在生成的C代码中,使用Java Native Interface(JNI)来与Java代码进行交互。使用C/C++编译器将C代码编译为共享库(.so或.dll文件),以供Java程序调用。 5. 构建Java代码:创建Java项目,在项目中引入包装代码并实现调用。可以使用JNI函数调用C函数,或直接使用包装代码生成的Java类和方法进行调用。 需要注意的是,转换C代码到Java并不是一种直接的转换过程,可能存在一些依赖问题,对于一些复杂的C代码或使用了C特定功能的代码,还需要在Java代码中添加适当的兼容性处理。 总结而言,Swig是一个强大的工具,可以将C代码转换为Java代码,简化了C/C++与Java之间的交互过程,提高了代码的可维护性和可扩展性。 ### 回答3: SWIG(Simplified Wrapper and Interface Generator)是一个用于将C/C++代码转换为其他语言的工具。如果想要将C代码转换为Java代码,可以使用SWIG来完成。 首先,在使用SWIG之前,需要确保已经安装好了SWIG,并且配置好了相关的环境变量。 接下来,需要创建一个包含C代码的接口文件,该文件的后缀名通常为.i。在接口文件中,需要使用SWIG的语法来指定要转换的C函数和类型。 然后,使用SWIG命令对接口文件进行处理,以生成Java代码。命令的语法通常为:swig -java interfacefile.i 完成上述操作后,会生成一系列的Java文件,包括接口文件中指定的函数和类型的Java封装类。 最后,可以将生成的Java代码导入到你的项目中,并与其它Java代码一起进行编译和运行。 需要注意的是,SWIG并非完美的工具,可能会有一些限制和问题。在使用SWIG进行C转Java时,可能会遇到一些类型对应的困难,或者在C和Java之间的内存管理方面的差异。因此,在使用SWIG转换代码时,需要谨慎处理这些问题,并进行相应的修改和调试。 总之,通过使用SWIG,我们可以方便地将C代码转换为Java代码,从而能够在Java平台上使用C语言的功能和库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值