NDKで「Lua」を組み込んでみる

「Lua」は、ポータブルな組み込み型スクリプト言語です。

現在、スクリプト言語用のフレームワークが、以下のプロジェクトで作成されています。

ここでは、NDKの作成手順を紹介するために、Luaを使用してみます。

ここで紹介するプログラムはサンプルコードのため、実際の動作には適していませんので、ご注意ください。

Luaライブラリの作成

まず、Luaのソースコードをダウンロードします。

  • http://www.lua.org/ から、lua-5.1.4.tar.gz をダウンロード
    ${ndk}/sources/samples/lua-5.1.4に展開
  • srcディレクトリにAndroidからの呼び出しコードのファイルを追加します
    touch src/android.c
  • ${ndk}/sources/samples/lua-5.1.4/Android.mkを作成します
    中身は、include $(call all-subdir-makefiles)のみです
  • ${ndk}/sources/samples/lua-5.1.4/src/Android.mkを作成します
    LOCAL_MODULE    := lua
    LOCAL_SRC_FILES := lapi.c lcode.c ldebug.c ldo.c ldump.c \
       lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c \
       lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c \
       Luaxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c \
       ltablib.c lstrlib.c loadlib.c linit.c android.c
    LOCAL_LDLIBS := -L${SYSROOT}/usr/lib -llog
  • locale.hの部分でエラーが出たので、一か所修正(エラー部分を削除)

Luaアプリの作成

Luaアプリケーションを格納するディレクトリを生成して、Application.mkを作成します。

  • apps/hellolua/Application.mkの作成
    • APP_PROJECT_PATH := $(call my-dir)/project
    • APP_MODULES := lua

EclipseでLuaを呼び出すアプリケーションを作成します。

  • ${ndk}/app/hellolua/projectに作成
  • EditText, Button, TextViewを配置
app.png

Javaのnativeメソッドの定義

Javaのクラスにnativeメソッドを定義します

public class HelloLua extends Activity {
   ...
   public native String doCall(String script);

クラス名を指定して、JNIのヘッダーを生成します

javah -jni -classpath ${ndk}/apps/hellolua/project/bin -d ${ndk}/sources/samples/lua-5.1.4/src jp.hews.hellolua.HelloLua

Nativeメソッドを定義する

JNIの初期化ルーチンでLuaを初期化して、print関数を登録します。 Nativeメソッドの呼び出しルーチンでスクリプトを渡して、実行し、プリント用のバッファを取得します。

/*
  File: android.cpp    - last edit:
  Hideo Kinami     7-Jul-2009
  Copyright(C) 2009 by Hideo Kinami. All rights reserved.
*/

#include <stdio.h>
#include <string.h>

#include "lua.h"
#include "lauxlib.h"

#include "jp_hews_hellolua_HelloLua.h"

#include "loghelper.h"
#define LOG_TAG "Lua"

static char fgBuff[1024];
static size_t fgLen = 0;

static void put(const char* fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);

    if ( sizeof(fgBuff) <= fgLen ) {
        return;
    }
    int len = vsnprintf(&fgBuff[fgLen], sizeof(fgBuff)-fgLen, fmt, ap);
    fgLen += len;
}

static int print(lua_State *L)
{
    int n=lua_gettop(L);
    int i;
    for (i=1; i<=n; i++) {
        if (i>1) {
            LOGI("\t");
            put("\t");
        }
        if (lua_isstring(L,i)) {
            LOGI("%s",lua_tostring(L,i));
            put("%s",lua_tostring(L,i));
        } else if (lua_isnil(L,i)) {
            LOGI("%s","nil");
            put("%s","nil");
        } else if (lua_isboolean(L,i)) {
            LOGI("%s",lua_toboolean(L,i) ? "true" : "false");
            put("%s",lua_toboolean(L,i) ? "true" : "false");
        } else {
            LOGI("%s:%p",luaL_typename(L,i),lua_topointer(L,i));
            put("%s:%p",luaL_typename(L,i),lua_topointer(L,i));
        }
    }
    return 0;
}

static lua_State *gLua = 0;

jint JNI_OnLoad(JavaVM *vm, void * reserved)
{
    fgBuff[0] = 0;
    fgLen = 0;
    gLua = lua_open();
    lua_register(gLua,"print",print);
    return JNI_VERSION_1_6;
}

/*
 * Class:     jp_hews_hellolua_HelloLua
 * Method:    doCall
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
jstring JNICALL Java_jp_hews_hellolua_HelloLua_doCall
  (JNIEnv * env, jobject jobj, jstring jstr)
{

    const jbyte *str = (*env)->GetStringUTFChars(env, jstr, 0);
    LOGI("script = %s", str);

    // clear Buff;
    fgLen = 0;
    fgBuff[0] = 0;
    if (luaL_dostring(gLua, str)) {
        LOGE("%s\n",lua_tostring(gLua,-1));
    }

    (*env)->ReleaseStringUTFChars(env, jstr, str);
    return (*env)->NewStringUTF(env, fgBuff);
}

実行

makeして、Eclipseからアプリを実行します。

make APP=hellolua
Eclipse: Run as Android Application
run.png

プレゼンテーション資料は、以下からダウンロードできます。

添付ファイル: fileAndroidNDKLua.pdf 5292件 [詳細] filerun.png 1726件 [詳細] fileapp.png 1790件 [詳細]