Android App中通过JNI调用C/C++代码(二)


前面已经实现了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输出:






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio 可以通过 JNIJava Native Interface)来调用 C/C++ 文件。 具体步骤如下: 1. 在 Android Studio 项目下,创建一个名为 `jni` 的目录。 2. 在 `jni` 目录下,创建一个名为 `native-lib.c` 的 C 文件。 3. 在 `native-lib.c` 文件实现需要调用的 C/C++ 函数。 4. 在 `jni` 目录下创建一个名为 `Android.mk` 的文件,用于编译 `native-lib.c`。 ``` LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := native-lib LOCAL_SRC_FILES := native-lib.c include $(BUILD_SHARED_LIBRARY) ``` 5. 在 `jni` 目录下创建一个名为 `Application.mk` 的文件,用于指定编译选项。 ``` APP_ABI := all ``` 6. 在 `MainActivity.java` 文件,声明需要调用的 C/C++ 函数。 ``` public native int add(int a, int b); ``` 7. 在 `MainActivity.java` 文件的 `onCreate` 方法,加载动态库,并调用 C/C++ 函数。 ``` static { System.loadLibrary("native-lib"); } int result = add(1, 2); ``` 8. 使用 `ndk-build` 命令编译动态库,并将编译生成的 `.so` 文件放置到 `app/src/main/jniLibs` 目录下。 9. 运行 Android 应用程序,即可调用 C/C++ 函数。 注意事项: 1. 需要在 `build.gradle` 文件添加如下配置: ``` android { defaultConfig { ndk { abiFilters 'armeabi-v7a', 'x86' } } sourceSets { main { jniLibs.srcDirs = ['src/main/jniLibs'] } } } ``` 2. 需要安装 NDK 工具包,并在 `local.properties` 文件指定 NDK 路径。 ``` ndk.dir=/path/to/ndk ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值