Android NDK JNI C++ <2>
这一篇主要涉及是如何用swig转换C写的程序,发现网上还是书上都不会介绍swig的功能,但是实际根本没有傻乎乎的去写JString之类的云云....
现在步骤如下:
<1> 首先新建一个SwigSimpleC工程,然后在工程中新建一个jni文件夹.
<2> 我比较喜欢.h,.c两种文件都配到写,无论是否使用,都会写,习惯问题.
example.h:
#ifndef _EXAMPLE_HEADER_H_ #define _EXAMPLE_HEADER_H_ int gcd(int x,int y); #endif
example.c:在这里还定义了一个常量,等下转换后就会有一个getFoo()的方法返回这个值,已提供给应用层使用
#include "example.h" double Foo = 3.0; int gcd(int x, int y) { int g; g = y; while (x > 0) { g = x; x = y % x; y = g; } return g; }
<3> 要让swig工具转换,同样要写一个swig能够识别的脚本:
%module example %inline %{ extern int gcd(int x,int y); extern double Foo; %}
从上面可以看到,和cpp不一样,cpp直接导出.h,不过我等下也用.h导出这个.
<4> : 编写好了上面的脚本,我还会写一个help.txt文件,这个文件包含了运行所需要的信息,包括文件名和路径之类,方便一个后使用.sh(shell编程所需)的开发,
help.txt如下:其实相当于一个帮助文档.
<a> : under project direction , input following command to terminal swig -java -package org.swig.cls -outdir src/org/swig/cls -o jni/example_wrap.c jni/example.i <b> : under jni direction , input following command to terminal swig -c++ -java -package org.swig.cls -outdir src/org/swig/cls -o example_wrap.cpp example.i
<5> : 这个里面要注意<a>显示jni/example.i,那么终端切换路径到和jni同级目录下就可以执行了(或者工程根目录下),<b>最后一个参数显示example.i,那么就要将路径切换到jni目录下,上面的outdir是用绝对路径,所以没关系.在执行之前首先要新建org.swig.cls的包,因为等下执行.i脚本后,输出将会直接输出到指定的包下.
将<a>的信息复制到终端里面,不出意外,就会输出各种文件了,这里面输出的文件中example_wrap.c文件非常重要,打开看看:
/* ---------------------------------------------------------------------------- * This file was automatically generated by SWIG (http://www.swig.org). * Version 2.0.4 * * This file is not intended to be easily readable and contains a number of * coding conventions designed to improve portability and efficiency. Do not make * changes to this file unless you know what you are doing--modify the SWIG * interface file instead. * ----------------------------------------------------------------------------- */ #define SWIGJAVA /* ----------------------------------------------------------------------------- * This section contains generic SWIG labels for method/variable * declarations/attributes, and other compiler dependent labels. * ----------------------------------------------------------------------------- */ /* template workaround for compilers that cannot correctly implement the C++ standard */ #ifndef SWIGTEMPLATEDISAMBIGUATOR # if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) # define SWIGTEMPLATEDISAMBIGUATOR template # elif defined(__HP_aCC) /* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ /* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ # define SWIGTEMPLATEDISAMBIGUATOR template # else # define SWIGTEMPLATEDISAMBIGUATOR # endif #endif /* inline attribute */ #ifndef SWIGINLINE # if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) # define SWIGINLINE inline # else # define SWIGINLINE # endif #endif /* attribute recognised by some compilers to avoid 'unused' warnings */ #ifndef SWIGUNUSED # if defined(__GNUC__) # if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) # define SWIGUNUSED __attribute__ ((__unused__)) # else # define SWIGUNUSED # endif # elif defined(__ICC) # define SWIGUNUSED __attribute__ ((__unused__)) # else # define SWIGUNUSED # endif #endif #ifndef SWIG_MSC_UNSUPPRESS_4505 # if defined(_MSC_VER) # pragma warning(disable : 4505) /* unreferenced local function has been removed */ # endif #endif #ifndef SWIGUNUSEDPARM # ifdef __cplusplus # define SWIGUNUSEDPARM(p) # else # define SWIGUNUSEDPARM(p) p SWIGUNUSED # endif #endif /* internal SWIG method */ #ifndef SWIGINTERN # define SWIGINTERN static SWIGUNUSED #endif /* internal inline SWIG method */ #ifndef SWIGINTERNINLINE # define SWIGINTERNINLINE SWIGINTERN SWIGINLINE #endif /* exporting methods */ #if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) # ifndef GCC_HASCLASSVISIBILITY # define GCC_HASCLASSVISIBILITY # endif #endif #ifndef SWIGEXPORT # if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) # if defined(STATIC_LINKED) # define SWIGEXPORT # else # define SWIGEXPORT __declspec(dllexport) # endif # else # if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) # define SWIGEXPORT __attribute__ ((visibility("default"))) # else # define SWIGEXPORT # endif # endif #endif /* calling conventions for Windows */ #ifndef SWIGSTDCALL # if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) # define SWIGSTDCALL __stdcall # else # define SWIGSTDCALL # endif #endif /* Deal with Microsoft's attempt at deprecating C standard runtime functions */ #if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) # define _CRT_SECURE_NO_DEPRECATE #endif /* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ #if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) # define _SCL_SECURE_NO_DEPRECATE #endif /* Fix for jlong on some versions of gcc on Windows */ #if defined(__GNUC__) && !defined(__INTEL_COMPILER) typedef long long __int64; #endif /* Fix for jlong on 64-bit x86 Solaris */ #if defined(__x86_64) # ifdef _LP64 # undef _LP64 # endif #endif #include <jni.h> #include <stdlib.h> #include <string.h> /* Support for throwing Java exceptions */ typedef enum { SWIG_JavaOutOfMemoryError = 1, SWIG_JavaIOException, SWIG_JavaRuntimeException, SWIG_JavaIndexOutOfBoundsException, SWIG_JavaArithmeticException, SWIG_JavaIllegalArgumentException, SWIG_JavaNullPointerException, SWIG_JavaDirectorPureVirtual, SWIG_JavaUnknownError } SWIG_JavaExceptionCodes; typedef struct { SWIG_JavaExceptionCodes code; const char *java_exception; } SWIG_JavaExceptions_t; static void SWIGUNUSED SWIG_JavaThrowException(JNIEnv *jenv, SWIG_JavaExceptionCodes code, const char *msg) { jclass excep; static const SWIG_JavaExceptions_t java_exceptions[] = { { SWIG_JavaOutOfMemoryError, "java/lang/OutOfMemoryError" }, { SWIG_JavaIOException, "java/io/IOException" }, { SWIG_JavaRuntimeException, "java/lang/RuntimeException" }, { SWIG_JavaIndexOutOfBoundsException, "java/lang/IndexOutOfBoundsException" }, { SWIG_JavaArithmeticException, "java/lang/ArithmeticException" }, { SWIG_JavaIllegalArgumentException, "java/lang/IllegalArgumentException" }, { SWIG_JavaNullPointerException, "java/lang/NullPointerException" }, { SWIG_JavaDirectorPureVirtual, "java/lang/RuntimeException" }, { SWIG_JavaUnknownError, "java/lang/UnknownError" }, { (SWIG_JavaExceptionCodes)0, "java/lang/UnknownError" } }; const SWIG_JavaExceptions_t *except_ptr = java_exceptions; while (except_ptr->code != code && except_ptr->code) except_ptr++; (*jenv)->ExceptionClear(jenv); excep = (*jenv)->FindClass(jenv, except_ptr->java_exception); if (excep) (*jenv)->ThrowNew(jenv, excep, msg); } /* Contract support */ #define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_JavaThrowException(jenv, SWIG_JavaIllegalArgumentException, msg); return nullreturn; } else extern int gcd(int x,int y); extern double Foo; #ifdef __cplusplus extern "C" { #endif SWIGEXPORT jint JNICALL Java_org_swig_cls_exampleJNI_gcd(JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2) { jint jresult = 0 ; int arg1 ; int arg2 ; int result; (void)jenv; (void)jcls; arg1 = (int)jarg1; arg2 = (int)jarg2; result = (int)gcd(arg1,arg2); jresult = (jint)result; return jresult; } SWIGEXPORT void JNICALL Java_org_swig_cls_exampleJNI_Foo_1set(JNIEnv *jenv, jclass jcls, jdouble jarg1) { double arg1 ; (void)jenv; (void)jcls; arg1 = (double)jarg1; Foo = arg1; } SWIGEXPORT jdouble JNICALL Java_org_swig_cls_exampleJNI_Foo_1get(JNIEnv *jenv, jclass jcls) { jdouble jresult = 0 ; double result; (void)jenv; (void)jcls; result = (double)Foo; jresult = (jdouble)result; return jresult; } #ifdef __cplusplus } #endif
看到上面的内容坑爹吧,如果没有swig,上面的内容都要我们开发,为了实现一个功能,要写一堆,累死猿人呀.
如果熟悉jni开发,可以大致看看,没啥子难度.
<6> 生成.so,是需要example_wrap.c的文件,要生成.so,有需要写一个脚本Android.mk,这个脚本的结构都是差不多的.
# LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE :=example LOCAL_SRC_FILES :=example_wrap.c example.c include $(BUILD_SHARED_LIBRARY)
<7> 让后进入jni该目录(准确说是进入Android.mk目录),然后ndk-build就可以看见生成examplelib.so的文件了.
<8> Android工程那边,因为在swig转换时候,已经生成了接口java,所以只要在主工程中加载so库就可以使用:
package org.swig.simple; import org.swig.cls.example; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.widget.TextView; import android.widget.Toast; public class SwigSimple extends Activity { static{ System.loadLibrary("example"); } private TextView mText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_swig_simple); mText=(TextView)findViewById(R.id.textview1); mText.setText("gcd : "+example.gcd(3, 5)); Toast.makeText(this, "Foo : "+example.getFoo(), Toast.LENGTH_SHORT).show(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.swig_simple, menu); return true; } }
<9> 运行结果............
<10> 最终结果目录应该是这样的:


浙公网安备 33010602011771号