65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C++ 编写 Android GUI: 入门

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.68/5 (13投票s)

2012年6月3日

CPOL

2分钟阅读

viewsIcon

98528

使用 CLE 和 Wrapandroid 项目,程序员可以通过 CLE 的接口更轻松地调用 Android 类。

引言

由于某种原因,我们可能希望使用原生代码编写 Android 应用程序。在这种情况下,将使用 NDK。但仅使用 NDK 是不够的。因为 Android 仅向程序员导出 Java 接口,所以应用程序无法直接调用 Android 类。我们如何解决这个问题?使用 CLE 和 Wrapandroid 项目,程序员可以通过 CLE 的接口更轻松地调用 Android 类。

本文介绍了使用 CLE 和 Wrapandroid 编写 Android GUI 应用程序。 CLE 是一个用于使用多种语言编程的中间件,支持 Java、Python、C/C++、Lua 等,并且可以扩展以支持其他语言。例如,类的实例等对象将被维护在内核中。然后,CLE 提供了一个通用的多语言接口。我们可以调用一个对象的函数,获取或设置对象的属性,捕获对象的事件等。

Wrapandroid 使用 CLE 对象包装 Android 类,这使程序员能够在他们的应用程序中使用 Android 类。通常情况下,步骤如下所示

  1. 使用 CLE 接口的 MallocObjectL 创建一个 Android 类的对象。
  2. 使用 ScriptCall 方法调用对象的函数。
  3. 使用 CreateOvlFunction 方法覆盖对象的函数
  4. 使用 RegEventFunction 方法挂钩对象的事件

步骤 1:准备环境

  1. CLE 可以由应用程序从网络自动安装,您只需要在项目中包含 starcore_android_r6.jar。该文件位于 starcore_devfiles_r6.zip 中,可以从 http://code.google.com/p/cle-for-android 下载。
  2. Wrapandroid 有库文件:wrapandroid.jar,可以从 这里 下载。

步骤 2:开始编程 

我们将使用 Eclipse 和 NDK 来开发应用程序。如何安装这些,请参考其他相关文章。 Android 版本应高于 2.2。

  1. 打开 Eclipse,创建一个名为“introduction”的新 Android 项目。
  2. CLE 可以在应用程序启动时从网络安装;在这种情况下,应添加以下权限
  3. <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
  4. 将 Java 库 starcore_android_r6.jarwrapandroid.jar 复制到项目目录并将它们添加到项目中
  5. 编辑 IntroductionActivity.java,更改为以下内容以加载原生共享库。
  6. 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");
        }
    }
  7. CLE 也可以包含在项目中,在这种情况下,您应该将 CLE 的共享库复制到项目目录中
  8. 并将下载标志更改为 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");
        }
    }
  9. 编辑布局:main.xml
  10. <?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>
  11. 在项目下创建一个 jni 目录,将 Wrapandroid 和 CLE 的头文件复制到 jni 目录中。创建名为 code.cppAndroid.mk 的新文件,并按如下所示编辑 Android.mk
  12.  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)

步骤 3. Code.cpp

在 Android 中编写原生代码,我们应该将源文件编译成共享库。共享库公开两个函数

VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
void StarCoreService_Term(class ClassOfStarCore *starcore)

第一个函数将在加载库时被调用,可以用于进行一些初始化。 StarCoreService_Term 将在卸载共享库之前被调用。 

code.cpp 的代码如下所示。 我们将详细了解它

//--header file of wrap android
<pre>#include "SRPWrapAndroidEngine_VSClass.h"
//--service interface, other function calls will be done through this interface.
static class ClassOfSRPInterface *SRPInterface;
//--Activity object of android, which is created by previous java code.
static void *StarActivity;
//--button event function. Each event has the same prototype.
static VS_INT32 MyButton_onClick(VS_ULONG FunctionChoice,void *EventPara)
{
    //--when the event is triggered, we show some information using android Toast.
    //--Create instance of toast.
    void *toast = SRPInterface->MallocObjectL(&VSOBJID_ToastClass,0,NULL);
    //--call toast function “makeText”, (si) is input parameter type and return type. please refer to CLE documents.
    SRPInterface -> ScriptCall(toast,NULL,"makeText","(si)","Button is click", 0);
    //--call toast function “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;
}
//--share library init function.
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
{
    class ClassOfBasicSRPInterface *BasicSRPInterface;
    
    //--get basic interface of CLE
    BasicSRPInterface = starcore ->GetBasicInterface();    
    //---get current service interface, the service is create by java code.
    SRPInterface = BasicSRPInterface ->GetSRPInterface(
      BasicSRPInterface->QueryActiveService(NULL),"","");
    
    void *ActivityClass;
    //---get wrapped acvitity
    ActivityClass = SRPInterface -> GetObjectEx(NULL,"ActivityClass");
    //--call getCurrent function to get current activity,
    // which is created by java code. ()O means the return type is CLE object;
    StarActivity = (void *)SRPInterface -> ScriptCall(ActivityClass,NULL,"getCurrent","()O");
    //--show some infotmation.
    SRPInterface -> Print("Get Main Activity = %s", SRPInterface -> GetName(StarActivity));    
    //--call activity function getResource to obtained resource id of above layout.
    // Input parameter is a string and output is an integer, so here we use (s)I tag.
    int widget45 = SRPInterface -> ScriptCall(StarActivity,NULL,
      "getResource","(s)i","id/widget45");
   //--Call findViewById function of activity, which is a textview. For this function, we should provide
   // class name as input parameter, which is little different from android function.
   // Input parameter is string and integer and return type is CLE object. So, here uses tag (si)o.
    void *MyText = (void *)SRPInterface -> ScriptCall(StarActivity,NULL,
      "findViewById","(si)o","TextViewClass",widget45);
    //--Call setText of textview object.
    SRPInterface -> ScriptCall(MyText,NULL,"setText",
      "(s)","TextViewClass","from layout");
    int widget74 = SRPInterface -> ScriptCall(StarActivity,NULL,
      "getResource","(s)i","id/widget74");
    //--Call findViewById function of activity to get button object.
    void *MyButton = (void *)SRPInterface -> ScriptCall(StarActivity,NULL,
      "findViewById","(si)o","ButtonClass",widget74);
    //--Call setText function of button object.
    SRPInterface -> ScriptCall(MyButton,NULL,"setText","(s)","click me");
    //--Call setOnClickListener function of button object.
    SRPInterface -> ScriptCall(MyButton,NULL,"setOnClickListener","()");
    //--register event function of button object.
    SRPInterface -> RegEventFunction(MyButton,&VSOUTEVENTID_ViewClass_onClick,MyButton,(void *)MyButton_onClick,0);
    
    int widget73 = SRPInterface -> ScriptCall(StarActivity,NULL,
      "getResource","(s)i","id/widget73");
    //--Call findViewById function of activity to get LinearLayout.
    void *MyLinearLayout = (void *)SRPInterface -> ScriptCall(
      StarActivity,NULL,"findViewById","(si)o","LinearLayoutClass",widget73);
    //--Dynamically create a button, which as a child of linear out.
    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);
    //--set layout parameters of button created.
    SRPInterface -> ScriptCall(MyDynaButton,NULL,"setLinearLayoutParams","(ii)",100,50);
    return VS_TRUE;
}
void StarCoreService_Term(class ClassOfStarCore *starcore)
{
    SRPInterface -> Release();
    return;
}

步骤 4. 编译到共享库

结果

示例可以从以下位置下载: http://wrapandroid-for-multilanguage.googlecode.com/svn/wiki/examples/c_introduction.zip

© . All rights reserved.