使用 CLE 从 Java Android 调用 C/C++
如何使用 CLE 从 Java Android 调用 C/C++
存在大量的 C/C++ 语言编写的资源。但在 Android 平台上,Java 是主要的语言。开发者必须使用 JNI 来封装 C/C++ 代码的接口。JNI 适用于简单的情况。对于更复杂的应用,程序员需要维护 C++ 对象到 Java 对象的引用,处理从 C/C++ 到 Java 的回调函数等,这些并不容易。使用 CLE,这些工作将由 CLE 完成,程序员只需要专注于特定的功能。
对于 Java 调用 C/C++ 使用 CLE,方法不像 Java 调用脚本那样直接,例如 lua、python 等。因为脚本语言都有反射机制。我们可以动态地获取函数和属性定义。但对于 C/C++,没有类似的机制。源代码中的所有定义都将被编译成二进制代码。因此,在使用 CLE 之前,我们需要先描述函数和属性。
描述对象属性和函数有两种方法。
第一种方法,使用 CLE 的接口函数
void *AtomicClass,*Add_AtomicFunction,*Print_AtomicFunction;
AtomicClass = SRPInterface ->CreateAtomicObjectSimple(
"TestItem","TestClass","VS_INT32 CValue",NULL,NULL);
Add_AtomicFunction = SRPInterface ->CreateAtomicFunctionSimple(
AtomicClass,"CAdd",
"VS_INT32 CAdd(VS_INT32 x,VS_INT32 y);",NULL,NULL,VS_FALSE,VS_FALSE);
Print_AtomicFunction = SRPInterface ->CreateAtomicFunctionSimple(
AtomicClass,"CPrint",
"void CPrint(VS_INT32 x,VS_INT32 y);",NULL,NULL,VS_FALSE,VS_FALSE);
第二种方法,使用 XML 字符串生成对象的属性和函数
void *AtomicClass,*Add_AtomicFunction,*Print_AtomicFunction;
class ClassOfSRPSXMLInterface *SXMLInterface;
SXMLInterface = BasicSRPInterface -> GetSXMLInterface();
SXMLInterface -> LoadFromBuf(
" <?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
" <sysrootitem>\n"
" <TestItem>\n"
" <object>\n"
" <TestClass ID=\"ed51e615-e548-442e-8802-a99b2fa8fe15\">\n"
" <attribute>\n"
" <CValue Type=\"VS_INT32\" />\n"
" </attribute>\n"
" <function>\n"
" <CAdd ID=\"f402fd47-8bea-4136-b7f7-45bb7fb51b14\">\n"
" <input Name=\"x\" Type=\"VS_INT32\" />\n"
" <input Name=\"y\" Type=\"VS_INT32\" />\n"
" <output Type=\"VS_INT32\" />\n"
" </CAdd>\n"
" <CPrint ID=\"da44c24e-f20a-46e3-8d37-49c3b90c6c05\">\n"
" <input Name=\"x\" Type=\"VS_INT32\" />\n"
" <input Name=\"y\" Type=\"VS_INT32\" />\n"
" </CPrint>\n"
" </function>\n"
" </TestClass>\n"
" </object>\n"
" </TestItem>\n"
" </sysrootitem>\n"
,NULL);
SRPInterface -> XmlToSysRootItem(SXMLInterface,NULL,"",NULL,0);
AtomicClass = SRPInterface ->GetAtomicObject
(_UUIDPTR("ed51e615-e548-442e-8802-a99b2fa8fe15"));
Add_AtomicFunction = SRPInterface ->GetAtomicFunction
(_UUIDPTR("f402fd47-8bea-4136-b7f7-45bb7fb51b14"));
Print_AtomicFunction = SRPInterface ->GetAtomicFunction
(_UUIDPTR("da44c24e-f20a-46e3-8d37-49c3b90c6c05"));
完成对象属性和函数的描述后,我们可以附加函数体地址
//---Set Function Address
SRPInterface -> SetAtomicFunction(Add_AtomicFunction,(void *)CAdd);
SRPInterface -> SetAtomicFunction(Print_AtomicFunction,(void *)CPrint);
此时,这些函数和属性可以从 Java 访问。
Java 代码
StarObjectClass a = Service._GetObject("TestClass")._New();
a._Call("CAdd",12,34));
C/C++ 回调到 Java
java call back function:
StarObjectClass a = Service._GetObject("TestClass")._New()._Assign(new StarObjectClass(){
public int JavaAdd(StarObjectClass self,int x,int y){
return x+y;
}
});
C 代码
VS_INT32 ScriptStack;
ScriptStack = SRPInterface -> ScriptGetStack(); //----save script stack
SRPInterface -> Print( "Function result from java %d",
SRPInterface -> ScriptCall
(Object,NULL,"JavaAdd","(ii)i)",x,y) );
SRPInterface -> ScriptSetStack(ScriptStack);
源代码(将 CLE 集成到您的项目中)
- 从 http://code.google.com/p/cle-for-android 下载 devfiles,然后打开 Eclipse
- 创建一个 Android 项目。
- 将 CLE jar 添加到项目,如下所示
C++ 代码
#include "vsopenapi.h"
class ClassOfSRPInterface *SRPInterface;
struct StructOfTestClass{
VS_INT32 CValue;
};
static VS_INT32 CAdd(void *Object,VS_INT32 x,VS_INT32 y)
{
struct StructOfTestClass *TestClass;
TestClass = (struct StructOfTestClass *)Object;
TestClass -> CValue = 200;
SRPInterface -> Print("Call c function...");
return x+y;
}
static void CPrint(void *Object,VS_INT32 x,VS_INT32 y)
{
VS_INT32 ScriptStack;
ScriptStack = SRPInterface -> ScriptGetStack(); //----save script stack
SRPInterface -> Print( "Value defined in java is %d",SRPInterface ->
ScriptGetInt(Object,"JavaValue") );
SRPInterface -> Print( "Function result from java %d",
SRPInterface -> ScriptCall(Object,NULL,"JavaAdd","(ii)i)",x,y) );
SRPInterface -> ScriptSetStack(ScriptStack); //----restore script stack
}
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
{
void *AtomicClass,*Add_AtomicFunction,*Print_AtomicFunction;
class ClassOfBasicSRPInterface *BasicSRPInterface;
//--init star core
BasicSRPInterface = starcore ->GetBasicInterface();
SRPInterface = BasicSRPInterface ->GetSRPInterface
(BasicSRPInterface->QueryActiveService(NULL),"","");
//---Create Atomic Class, for define function,
AtomicClass = SRPInterface ->CreateAtomicObjectSimple
("TestItem","TestClass","VS_INT32 CValue",NULL,NULL);
Add_AtomicFunction = SRPInterface ->CreateAtomicFunctionSimple
(AtomicClass,"CAdd","VS_INT32 CAdd(VS_INT32 x,VS_INT32 y);",
NULL,NULL,VS_FALSE,VS_FALSE);
Print_AtomicFunction = SRPInterface ->CreateAtomicFunctionSimple
(AtomicClass,"CPrint","void CPrint(VS_INT32 x,VS_INT32 y);",
NULL,NULL,VS_FALSE,VS_FALSE);
//---Set Function Address
SRPInterface -> SetAtomicFunction(Add_AtomicFunction,(void *)CAdd);
SRPInterface -> SetAtomicFunction(Print_AtomicFunction,(void *)CPrint);
return VS_TRUE;
}
void StarCoreService_Term(class ClassOfStarCore *starcore)
{
SRPInterface -> Release();
return;
}
使用 NDK 将代码编译成共享库,Android.mk 是
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Here we give our module name and sourcefile(s)
LOCAL_CFLAGS += -Wno-write-strings -DENV_ANDROID
LOCAL_CPPFLAGS += -Wno-write-strings -fexceptions -DENV_ANDROID
LOCAL_LDFLAGS += -Wno-write-strings -DENV_ANDROID
LOCAL_C_INCLUDES += ../../cle_files/include
#--------source file
MODULE_CXXSRCS := AddFunction.cpp
LOCAL_SRC_FILES := ${MODULE_CXXSRCS}
LOCAL_LDLIBS := ../../cle_files/libs/armeabi/libstarlib.a
LOCAL_MODULE := AddFunction
include $(BUILD_SHARED_LIBRARY)
Java 代码
package com.cle.cfromjava;
import android.app.Activity;
import android.os.Bundle;
import com.srplab.www.starcore.*;
import com.srplab.netinst.*;
public class CfromjavaActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//--init CLE
starcore_net_inst.InstallZipFile
(this,"libstarcore.so",
"http://www.srplab.com/android/starcore_armeabi_r3.zip",
"/data/data/com.cle.cfromjava/files");
StarCoreFactoryPath.StarCoreShareLibraryPath =
"/data/data/com.cle.cfromjava/files";
StarCoreFactoryPath.StarCoreOperationPath =
"/data/data/com.cle.cfromjava/files";
StarCoreFactory starcore= StarCoreFactory.GetFactory();
StarServiceClass Service=starcore._InitSimple
("test","123",0,0);
Service._CheckPassword(false);
Service._DoFile
("","/data/data/com.cle.cfromjava/lib/libAddFunction.so","");
StarObjectClass a = Service._GetObject
("TestClass")._New()._Assign(new StarObjectClass(){
public int JavaAdd(StarObjectClass self,int x,int y){
System.out.println("Call java function...");
return x+y;
}
});
a._Set("JavaValue",100);
System.out.println(a._Call("CAdd",12,34));
System.out.println(a._Get("CValue"));
a._Call("CPrint",56,78);
starcore._ModuleExit();
}
}