不過今天這邊要介紹的是另外一個方法 - 透過 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 即可。
沒有留言:
張貼留言