前面已经实现了Android App通过JNI调用C/C++代码,但那是在一个新创建的android工程里的,如果是在cocos2dx生成的项目呢,相信是差不多的原理。
修改Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := cocos2dlua_shared
LOCAL_MODULE_FILENAME := libcocos2dlua
LOCAL_SRC_FILES := \
../../Classes/AppDelegate.cpp \
hellolua/main.cpp \
../../../cocos2d-x/cocos/scripting/lua-bindings/auto/lua_cocos2dx_hello_auto.cpp \
jnispace/helloJni.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
jnispace
LOCAL_STATIC_LIBRARIES := cocos2d_lua_static
include $(BUILD_SHARED_LIBRARY)
$(call import-module,scripting/lua-bindings/proj.android)
重新打android包就可以啦,cocos compile -p android, 编译好的jni代码加入到了libcocos2dlua.so库中
虽然把JNI代码引入到了cocos2dx库里,但JNI的C代码怎么调用Cocos的逻辑代码呢?
又倒鼓了一天,终于实现了这一功能:Android Activity中调用 C方法,C方法再调用Cocos部分代码,最后进入到了Lua。
首先来看Cocos2dx C++怎么调用Lua
(一)在网上找了很多资料,还是这篇文章比较靠谱:摘自cocos2dx之C++调用Lua
LuaStack * L =LuaEngine::getInstance()->getLuaStack();
lua_State* tolua_s = L->getLuaState();
//--------有参数和返回值的Lua函数的调用---------
lua_getglobal(tolua_s, "testadd"); // 获取函数,压入栈中
lua_pushnumber(tolua_s, 10); // 压入第一个参数
lua_pushnumber(tolua_s, 20); // 压入第二个参数
lua_pushstring(tolua_s, "测试"); // 压入第三个参数
int iRet= lua_pcall(tolua_s, 3, 2, 0);// 调用函数,调用完成以后,会将返回值压入栈中,2表示参数个数,1表示返回结果个数。
if (iRet) // 调用出错
{
const char *pErrorMsg = lua_tostring(tolua_s, -1);
CCLOG("错误-------%s",pErrorMsg);
return ;
}
int fValue = lua_tonumber(tolua_s, -2); //获取第一个返回值
string str = lua_tostring(tolua_s, -1); //获取第二个返回值
CCLOG("有参数和返回值的Lua函数的调用---%d---,%s",fValue,str.c_str());
//--------------读取Lua的变量------------
lua_getglobal(tolua_s, "strTemp");
string strTemp = lua_tostring(tolua_s, -1);
CCLOG("读取Lua的变量---%s",strTemp.c_str());
//-------------读取Lua的table-----------
lua_getglobal(tolua_s,"tableTemp");
lua_getfield(tolua_s,-1,"name");
string strName = lua_tostring(tolua_s,-1);
CCLOG("读取Lua的table--%s",strName.c_str());
(二)再搜出了lua_pcall的用法,摘自 lua_pcall用法
lua_pcall(lua_State *L, int nargs, int nresults, int errfunc)
nargs:参数个数,nresults:返回值个数,errFunc:错误处理函数,0表示无,表示错误处理函数在栈中的索引
假如脚本为:
--test.lua
function test(x,y)
return x+y
end
luaL_loadfile(L, "test.lua");
然后先压x,y的值入栈
lua_pushnumber(L,10);
lua_pushnumber(L,20);
lua_pcall(L,2,1,0);
如果没有错误则此时栈顶的值为30.
如果运行时出错,lua_pcall会返回一个非零的结果,如果指定了错误处理函数会先调用错误处理函数,然后在将错误信息入栈,在将返回结果或者错误信息入栈之前会先将函数和参数从栈中移除。错误处理函数必须要在被调用函数和其参数入栈之前入栈。
lua_getfield(L, idx, "x") 从指定idx的表中取出指定元素x的值 并将其入栈
lua_setfield(L, idx, "x") 将栈顶的值赋给指定索引idx中的x,并pop栈顶
(三)编写自己的Lua全局方法,以待C++调用
main.lua
--全局方法,还不能写成 function globalFuncs(){}这样
--此方法用作C++ 中调用Lua的示例
cc.exports.globalFuncs = function(num)
print(string.format("Lua print: %d", num))
end
(四)C++调用Lua
工程里新建这两个文件
JNICall.h
#ifndef __JNI_CALL__
#define __JNI_CALL__
#include "cocos2d.h"
void callFuns1(int num);
#endif
JNICall.cpp
#include "JNICall.h"
#include "scripting/lua-bindings/manual/CCLuaEngine.h"
USING_NS_CC;
using namespace std;
void callFuns1(int num){
auto L = LuaEngine::getInstance()->getLuaStack();
lua_State* tolua_s = L->getLuaState();
lua_getglobal(tolua_s, "globalFuncs");
lua_pushnumber(tolua_s, 30);
int ret = lua_pcall(tolua_s, 1, 0, 0);
if(ret){
// !=0表示有错误
const char* pErrorMsg = lua_tostring(tolua_s, -1);
CCLOG("error---------------------%s", pErrorMsg);
return;
}
}
JNI代码调用callFuns1方法
(五) 编译运行
修改Android.mk文件,添加JNICall.cpp
cocos compile -p android,编译成功
如果在Activity中直接调用JNI代码,这时lua引擎还没有准备好,会报错,那就做一个延时调用处理:
new Thread(){
public void run(){
Log.d("aaaa", "jni output waiting: ");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
Log.d("aaaa", "jni output: " + HelloJni.getName("a"));
}
}.start();
运行:
java中的输出
lua输出: