在某些情況下,比如原來與很多c/c++的代碼, 可能希望采用c/c++編寫android應用程序.在這種情況下,一般使用NDK.但是由於android直提供了java接口,因此不能夠直接調用android中的各種對象或者部件. 如何直接使用c/c++開發android應用? 可以使用cle和wrapandroid項目作為中間件. CLE項目提供了多種語言的通用接口,其中就包含對c/c++的支持.
本文簡單介紹了如何使用CLE和wrapandroid編寫GUI應用程序。CLE可以作為多種語言的通用平台,支持java, python,c/c++,lua, 等,且可以擴展至其它多種語言,也可以自定義語言。在CLE中,對象作為1個基本的操作元素。對象對外提供了統一的接口,可以通過這些接口,調用對象的函數,重載對象的函數,捕獲對象的事件.
Wrapandroid將android類封裝成為CLE對象,從而可以使程序員在c/c++中使用android的類。一般有以下幾個步驟:
Wrapandroid將android類封裝成為CLE對象,從而可以使程序員在c/c++中使用android的類。一般有以下幾個步驟:
1. 使用CLE接口函數MallocObjectL創建android類的實例對象
2. 使用ScriptCall接口函數調用對象的方法
3. 使用CreateOvlFunction重載對象的函數
4. 使用RegEventFunction注冊對象的事件處理函數
步驟1: 准備環境
a: CLE可以在應用啟動的時候自動安裝,只需要在工程中包含starcore_android_r6.jar,該文件在starcore_devfiles_r6.zip壓縮包中, 可以從鏈接:
http://code.google.com/p/cle-for-android 下載。
b: Wrapandroid是一個jar庫,可以從http:/code.google.com/p/wrapandroid-for-multilaguage/download/wrapandroid_devfiles_0_8_5.rar下載。
步驟2 : 開始編程
開發工具使用eclipse和NDK. 這兩個如何安裝和使用,請參閱相關的文檔.
a. 打開eclipse, 創建一個新工程,名字為“introduction”
b. cle可以在應用啟動的時候從網絡下載,此時需要在工程中增加以下許可:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
c. 將java庫文件starcore_android_r6.jar和wrapandroid.jar拷貝到工程目錄,並加入到工程中:

d. 編輯IntroductionActivity.java,如下修改,裝載共享庫
import com.srplab.wrapandroid.*;
public class IntroductionActivity extends WrapAndroidActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
StarActivity._Call("DoFile","","/data/data/"+getPackageName()+"/lib/libCode.so");
}
}
e cle也可以打包到工程中,此時需要將CLE的共享庫文件放到工程目錄中,如下:

同時,將下載標志設置為false
public class IntroductionActivity extends WrapAndroidActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
DownloadFromNetFlag = false;
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
StarActivity._Call("DoFile","","/data/data/"+getPackageName()+"/lib/libCode.so");
}
}
f. 編輯布局文件:main.xml.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget73"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/widget45"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Button
android:id="@+id/widget74"
android:layout_width="220dp"
android:layout_height="48dp"
android:text="thank for your use"
android:typeface="serif"
android:textStyle="bold"
android:textColor="#ffff0000"
android:layout_x="284dp"
android:layout_y="220dp"
android:textSize="16dp"
/>
</LinearLayout>
g. 在工程目錄下,創建jni目錄, 將wrap android和cle頭文件拷貝到該目錄下. 創建新文件code.cpp. and Android.mk, 編輯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 := Code.cpp SRPWrapAndroidEngine_UUIDDef.cpp
LOCAL_SRC_FILES := ${MODULE_CXXSRCS}
LOCAL_LDLIBS := cle_files/libs/armeabi/libstarlib.a
LOCAL_MODULE := Code
include $(BUILD_SHARED_LIBRARY)
#------------------------
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cle_files/so/armeabi/libstarcore.so
LOCAL_MODULE := starcore
include $(PREBUILT_SHARED_LIBRARY)
#------------------------
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cle_files/so/armeabi/libstar_java.so
LOCAL_MODULE := star_java
include $(PREBUILT_SHARED_LIBRARY)
步驟3. Code.cpp
采用原生代碼編寫android應用,需要將其編譯成為共享庫。共享庫輸出兩個接口函數:
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
void StarCoreService_Term(class ClassOfStarCore *starcore)
第一個函數在共享庫裝載的時候調用,可以進行一些初始化工作;第二個函數在共享庫卸載的時候調用
代碼如下:
//--wrap android頭文件
#include "SRPWrapAndroidEngine_VSClass.h"
//--服務接口,其它所有函數都通過該接口調用.
static class ClassOfSRPInterface *SRPInterface;
//--android Activity對象,由java代碼創建.
static void *StarActivity;
//--按鈕的事件函數。 事件函數的處理原型都相同.
static VS_INT32 MyButton_onClick(VS_ULONG FunctionChoice,void *EventPara)
{
//--當事件被觸發時,顯示一些信息.
//--創建toast對象。
void *toast = SRPInterface->MallocObjectL(&VSOBJID_ToastClass,0,NULL);
//--調用toast的函數“makeText”, (si) 為輸入參數的類型,詳細解釋需要參閱CLE文檔.
SRPInterface -> ScriptCall(toast,NULL,"makeText","(si)","Button is click", 0);
//--調用toast的函數“show”
SRPInterface -> ScriptCall(toast,NULL,"show","()");
return 0;
}
static VS_INT32 MyButton1_onClick(VS_ULONG FunctionChoice,void *EventPara)
{
void *toast = SRPInterface->MallocObjectL(&VSOBJID_ToastClass,0,NULL);
SRPInterface -> ScriptCall(toast,NULL,"makeText","(si)","Button is click", 0);
SRPInterface -> ScriptCall(toast,NULL,"show","()");
return 0;
}
//--共享庫的初始化函數
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
{
class ClassOfBasicSRPInterface *BasicSRPInterface;
//--獲取基本服務接口
BasicSRPInterface = starcore ->GetBasicInterface();
//---獲取當前的服務接口,服務由java代碼創建
SRPInterface = BasicSRPInterface ->GetSRPInterface(BasicSRPInterface->QueryActiveService(NULL),"","");
void *ActivityClass;
//---獲取被封裝的acvitity類
ActivityClass = SRPInterface -> GetObjectEx(NULL,"ActivityClass");
//--調用getCurrent function獲取當前的activity, 由java代碼創建. ()O 表示返回值為一個cle對象
StarActivity = (void *)SRPInterface -> ScriptCall(ActivityClass,NULL,"getCurrent","()O");
//--打印一些信息,打印的信息會顯示到logcat中.
SRPInterface -> Print("Get Main Activity = %s", SRPInterface -> GetName(StarActivity));
//--調用activity的函數getResource獲取布局中定義的資源的ID. 輸入參數為字符串,輸出為整數,使用標記為(s)I.
int widget45 = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","id/widget45");
//--調用findViewById函數獲取textview. 該函數與android的函數原型略為不同,輸入參數中增加的類的名稱。
void *MyText = (void *)SRPInterface -> ScriptCall(StarActivity,NULL,"findViewById","(si)o","TextViewClass",widget45);
//--調用textview的函數setText。
SRPInterface -> ScriptCall(MyText,NULL,"setText","(s)","TextViewClass","from layout");
int widget74 = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","id/widget74");
//--調用findViewById獲取按鈕對象
void *MyButton = (void *)SRPInterface -> ScriptCall(StarActivity,NULL,"findViewById","(si)o","ButtonClass",widget74);
//--調用按鈕對象的setText.
SRPInterface -> ScriptCall(MyButton,NULL,"setText","(s)","click me");
//--調用按鈕對象的函數setOnClickListener.
SRPInterface -> ScriptCall(MyButton,NULL,"setOnClickListener","()");
//--注冊事件的處理函數
SRPInterface -> RegEventFunction(MyButton,&VSOUTEVENTID_ViewClass_onClick,MyButton,(void *)MyButton_onClick,0);
int widget73 = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","id/widget73");
//--調用findViewById獲取LinearLayout.
void *MyLinearLayout = (void *)SRPInterface -> ScriptCall(StarActivity,NULL,"findViewById","(si)o","LinearLayoutClass",widget73);
//--動態創建按鈕對象,是linearlayout的子對象
void *MyDynaButton = SRPInterface->MallocObject(MyLinearLayout,VSATTRINDEX_VIEWGROUPCLASS_VIEWQUEUE,&VSOBJID_ButtonClass,0,NULL);
SRPInterface -> ScriptCall(MyDynaButton,NULL,"setText","(s)","created dynamically");
SRPInterface -> ScriptCall(MyDynaButton,NULL,"setOnClickListener","()");
SRPInterface -> RegEventFunction(MyDynaButton,&VSOUTEVENTID_ViewClass_onClick,MyDynaButton,(void *)MyButton1_onClick,0);
//--設置布局參數
SRPInterface -> ScriptCall(MyDynaButton,NULL,"setLinearLayoutParams","(ii)",100,50);