* NDKで「Lua」を組み込んでみる [#m2b06be5]
 
「Lua」は、ポータブルな組み込み型スクリプト言語です。

現在、スクリプト言語用のフレームワークが、以下のプロジェクトで作成されています。
- http://code.google.com/p/android-scripting/

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

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

** Luaライブラリの作成 [#yc414537]

まず、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アプリの作成 [#zed25ded]

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を配置

#ref(app.png)

**  Javaのnativeメソッドの定義 [#s286fd89]

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メソッドを定義する [#idc764af]

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);
 }

** 実行 [#z05054e3]

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

 make APP=hellolua
 Eclipse: Run as Android Application

#ref(run.png)

----
プレゼンテーション資料は、以下からダウンロードできます。
#ref(AndroidNDKLua.pdf)