Introduction
For some reason, we might want to write Android applications using native code. In this case,
the NDK will be used. But using only NDK is not enough. Because Android only exports
Java interface to programmers, so applications can not call Android classes directly. How
do we solve this problem? Using CLE
and the Wrapandroid project, programmers can call Android classes through interfaces of
CLE more easily.
The article is an introduction to write Android GUI applications using CLE and
Wrapandroid. CLE is a middleware for programming using multiple languages,
which supports Java, Python, C/C++, Lua, etc., and can be extended to support other languages. Objects, for example, instances of classes, will be maintained in the kernel.
And then, CLE provides a common interface to multiple languages. We can call an object’s function, get or set object’s attributes, capture object’s events,
etc.
Wrapandroid wraps android classes with CLE objects, which enables programmers to use android classes in their applications. In normal case, the steps is illustrated below:
- Create an object of an Android class using
MallocObjectL
of
the CLE interface. - Call object’s functions using
ScriptCall
method. - Override object’s function using
CreateOvlFunction
method - Hook object’s event using
RegEventFunction
method
Step 1: Prepare environment
- CLE may be installed from the network by the application automatically, you only
need to include starcore_android_r6.jar in the project. The file is in
starcore_devfiles_r6.zip, which can be download from
http://code.google.com/p/cle-for-android.
- Wrapandroid has lib files: wrapandroid.jar, which can be download from here.
Step 2: Begin programming
We will be using Eclipse and NDK to develop the application. How to install these, please refer to other related articles. Android version should be above 2.2.
- Open Eclipse, create a new Android project named “introduction”.
- CLE may be installed from the network when the application is started; in this case, the following permissions should be added:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
- Copy the Java libraries starcore_android_r6.jar and wrapandroid.jar to
the project directory and add them into the project:
- Edit IntroductionActivity.java, change as follows loading the native share library.
import com.srplab.wrapandroid.*;
public class IntroductionActivity extends WrapAndroidActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
StarActivity._Call("DoFile","",
"/data/data/"+getPackageName()+"/lib/libCode.so");
}
}
- CLE may also be included in the project, in this case, you should copy the share libraries of CLE to the directory of the project:
And change the download flag to false:
public class IntroductionActivity extends WrapAndroidActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
DownloadFromNetFlag = false;
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
StarActivity._Call("DoFile","",
"/data/data/"+getPackageName()+"/lib/libCode.so");
}
}
- Edit layout: main.xml.
="1.0"="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>
- Create a jni directory under the project, copy header files of Wrapandroid and CLE into
the jni directory. Create new files named code.cpp and Android.mk,
and edit Android.mk as follows:
LOCAL_PATH := $(call my-dir)
<pre>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)
Step 3. Code.cpp
Write native code in Android, we should compile the source file into a share library. The share library exposes two functions:
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
void StarCoreService_Term(class ClassOfStarCore *starcore)
The first function will be called when the library is loaded, which can be used to do some initializing.
StarCoreService_Term
will be called before the share library is unloaded.
The code for code.cpp is listed below. We will see it in detail:
<pre>#include "SRPWrapAndroidEngine_VSClass.h"
static class ClassOfSRPInterface *SRPInterface;
static void *StarActivity;
static VS_INT32 MyButton_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;
}
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();
SRPInterface = BasicSRPInterface ->GetSRPInterface(
BasicSRPInterface->QueryActiveService(NULL),"","");
void *ActivityClass;
ActivityClass = SRPInterface -> GetObjectEx(NULL,"ActivityClass");
StarActivity = (void *)SRPInterface -> ScriptCall(ActivityClass,NULL,"getCurrent","()O");
SRPInterface -> Print("Get Main Activity = %s", SRPInterface -> GetName(StarActivity));
int widget45 = SRPInterface -> ScriptCall(StarActivity,NULL,
"getResource","(s)i","id/widget45");
void *MyText = (void *)SRPInterface -> ScriptCall(StarActivity,NULL,
"findViewById","(si)o","TextViewClass",widget45);
SRPInterface -> ScriptCall(MyText,NULL,"setText",
"(s)","TextViewClass","from layout");
int widget74 = SRPInterface -> ScriptCall(StarActivity,NULL,
"getResource","(s)i","id/widget74");
void *MyButton = (void *)SRPInterface -> ScriptCall(StarActivity,NULL,
"findViewById","(si)o","ButtonClass",widget74);
SRPInterface -> ScriptCall(MyButton,NULL,"setText","(s)","click me");
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");
void *MyLinearLayout = (void *)SRPInterface -> ScriptCall(
StarActivity,NULL,"findViewById","(si)o","LinearLayoutClass",widget73);
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);
return VS_TRUE;
}
void StarCoreService_Term(class ClassOfStarCore *starcore)
{
SRPInterface -> Release();
return;
}
Step 4. Compile to share library
Result:
The example can be download from: http://wrapandroid-for-multilanguage.googlecode.com/svn/wiki/examples/c_introduction.zip.