不過今天這邊要介紹的是另外一個方法 - 透過 SWIG 的 directors 的 feature
SWIG 可以將 C++ 的 class 包裝成一個 Java layer 的 class ,而 Java layer 可以去繼承 Java wrap C++ 的 class,然後 override 它的 virtual function 後,C/C++ layer 呼叫到這個 virtual function 時,就會被轉 call 到 Java layer了。
以下是簡單的 sample code
MyLib.h
在 Callback function 前加上 virtual
#ifndef __MY_LIB_H #define __MY_LIB_H class Base { public: Base(){} virtual ~Base(){} void CallIn(int num1, int num2); virtual void Callback(int num1, int num2); //setting in virtual for override }; #endif
MyLib.cpp
#include "MyLib.h" #include <android/log.h> void Base::CallIn(int num1, int num2) { Callback(num1+1, num2+1); // add the number } void Base::Callback(int num1, int num2) { // If override this function in Java layer, you will not see the log __android_log_print(ANDROID_LOG_DEBUG, "MyLib", "Base::Callback() num1=%d, num2=%d", num1, num2); }
MyLib.i
在 .i 檔中,加上 %feature("director") 後面加上 想處理的 class name
這樣 SWIG 就會自動處理 class name 底下所有的 virtual function
若不指定的話,SWIG 會處理所有的 class 的 virtual function
也可以加上 %feature("nodirector") Foo::Bar; 將 disable 指定的 virtual function
%module(directors="1") MyLib %{ #include "MyLib.h" %} %feature("director") Base; %include "MyLib.h" %pragma(java) jniclasscode=%{ static { try { java.lang.System.loadLibrary("MyLib"); } catch (UnsatisfiedLinkError e) { java.lang.System.err.println("JNI error: " + e); java.lang.System.exit(1); } } %}
Android.mk
務必要加上-fexceptions -frtti,這樣 SWIG 才有能力處理 class override
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := MyLib LOCAL_SRC_FILES := MyLib_wrap.cpp MyLib.cpp LOCAL_LDLIBS := -llog LOCAL_CFLAGS := -fexceptions -frtti #for SWIG director feature include $(BUILD_SHARED_LIBRARY)
MainActivity.java
import com.yourapp.Base //... other import public class MainActivity extends Activity { class JDerived extends Base { @Override public void Callback(int num1, int num2) { String msg = String.format( "Derived::Callback() num1=%d, num2=%d", num1, num2 ); System.out.println(msg); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); JDerived d = new JDerived(); d.CallIn(1,2); } }
最後輸出的 output 結果就是
>>> Derived::Callback() num1=2, num2=3
最後,由於 SWIG 在處理 virtual function 時,需要多 wrapper 好幾層的 function,因而增加了一些 function call 的 overhead,所以盡量指定想被 override 的 virtual function 即可。
沒有留言:
張貼留言