如题,最近cocos2dx-lua项目用到http里请求。quick的话可以用network.createHTTPRequest实现,我们的项目是直接用2dx原生创建的lua项目,没有quick的部分。百度了下,发现可以用cc.XMLHttpRequest来实现http请求,然而我在调用cc.XMLHttpRequest却报错说XMLHttpRequest为nil,具体原因还没看,不过看代码2dx是绑定了这个类的。于是我打算重写一个类,用httpClient原生实现http请求,并进行lua绑定。
导航:主要看2,3,4,6(2,3为主要代码,4就一句话,6为lua最后调用代码)。
---------------1.新建lua_tool.hpp和lua_tool.cpp
--------1.1新建文件夹luaTool
完整路径为frameworks->cocos2d-x->cocos->scripting->lua-bindings->luaTool,luaTool为新建的文件夹。
--------1.2新建lua_tool.hpp
文件夹luaTool下新建lua_tool.hpp文件,完整路径为frameworks->cocos2d-x->cocos->scripting->lua-bindings->luaTool->lua_tool.hpp
--------1.3新建lua_tool.cpp
文件夹luaTool下新建lua_tool.cpp文件,完整路径为frameworks->cocos2d-x->cocos->scripting->lua-bindings->luaTool->lua_tool.cpp
---------------2.lua_tool.hpp完整代码
/* *Evan */ #include "base/ccConfig.h" #ifndef __lua_tool_h__ #define __lua_tool_h__ #ifdef __cplusplus extern "C" { #endif #include "tolua++.h" #ifdef __cplusplus } #endif #include "cocos-ext.h" #include "network/HttpClient.h" #include "network/HttpResponse.h" USING_NS_CC; USING_NS_CC_EXT; using namespace network; using namespace std; class LuaHttp { public: LuaHttp(); ~LuaHttp(); void setLuaCallBack(int _luaCallBack); void sendGet(const char* url, const char* data); void sendPost(const char* url, const char* data); void loadImage(const char* url); void onRequestComplete(HttpClient *sender, HttpResponse *response); void onRequestImageComplete(HttpClient *sender, HttpResponse *response); private: int luaCallBack; }; int register_all_luaTool(lua_State* tolua_S); ---------------3.lua_tool.cpp完整代码 /* *Evan */ #include "lua_tool.hpp" #include <string> //#include "ccUTF8.h" #include "scripting/lua-bindings/manual/LuaBasicConversions.h" #include "scripting/lua-bindings/manual/CCLuaValue.h" #include "scripting/lua-bindings/manual/CCLuaStack.h" #include "scripting/lua-bindings/manual/CCLuaEngine.h" /****************************************************************************** ******************************* C++ CODE ****************************** ******************************************************************************/ LuaHttp::LuaHttp() :luaCallBack(0) { } LuaHttp::~LuaHttp() { if (luaCallBack) { LuaEngine::getInstance()->removeScriptHandler(luaCallBack); } } void LuaHttp::setLuaCallBack(int _luaCallBack) { luaCallBack = _luaCallBack; } void LuaHttp::sendGet(const char* url, const char* data){ HttpRequest* request = new HttpRequest(); string _url = StringUtils::format("%s?%s", url, data); request->setUrl(_url.c_str()); request->setRequestType(HttpRequest::Type::GET); request->setResponseCallback(CC_CALLBACK_2(LuaHttp::onRequestComplete, this)); request->setTag("GET REQUEST"); HttpClient::getInstance()->send(request); request->release(); } void LuaHttp::sendPost(const char* url, const char* data){ HttpRequest* request = new HttpRequest(); request->setUrl(url); request->setRequestType(HttpRequest::Type::POST); request->setResponseCallback(CC_CALLBACK_2(LuaHttp::onRequestComplete, this)); // write the post data request->setRequestData(data, strlen(data)); request->setTag("POST REQUEST"); //HttpClient::getInstance()->setTimeoutForConnect(10); HttpClient::getInstance()->send(request); request->release(); } void LuaHttp::onRequestComplete(HttpClient *sender, HttpResponse *response){ if (!response) { log("LuaHttp::onRequestComplete response is null"); //lua callBack if (luaCallBack) { LuaValueDict dict; dict["code"] = LuaValue::intValue(9999); LuaStack *stack = LuaEngine::getInstance()->getLuaStack(); stack->clean(); stack->pushLuaValueDict(dict); stack->executeFunctionByHandler(luaCallBack, 1); } return; } if (0 != strlen(response->getHttpRequest()->getTag())) { log("LuaHttp::onRequestComplete %s complete", response->getHttpRequest()->getTag()); } int statusCode = (int)response->getResponseCode(); const char* flag = response->getHttpRequest()->getTag(); string statusString = StringUtils::format("Http Request Code: %d tag = %s", statusCode, flag); log("LuaHttp::onRequestComplete statusString:%s", statusString.c_str()); //special error code if (statusCode == 503 || statusCode == 500 || (statusCode != -1 && statusCode != 404/* && statusCode != 500*/ && statusCode != 200)) { log("LuaHttp::onRequestComplete response failed! statusCode == 503 || statusCode == 500"); // log("HNManager::onHttpRequestComplete error buffer:%s statusCode == 503", response->getErrorBuffer()); // return; } if (!response->isSucceed()) { log("LuaHttp::onRequestComplete response failed!"); log("LuaHttp::onRequestComplete error buffer:%s", response->getErrorBuffer()); //lua callBack if (luaCallBack) { LuaValueDict dict; dict["code"] = LuaValue::intValue((int)response->getResponseCode()); dict["tag"] = LuaValue::stringValue(response->getHttpRequest()->getTag()); LuaStack *stack = LuaEngine::getInstance()->getLuaStack(); stack->clean(); stack->pushLuaValueDict(dict); stack->executeFunctionByHandler(luaCallBack, 1); } return; } // dump data vector<char>* buffer = response->getResponseData(); string result; for(vector<char>::iterator iter = buffer->begin(); iter != buffer->end(); ++iter) { result += *iter; } log("LuaHttp::onRequestComplete server result:%s", result.c_str()); //lua callBack if (luaCallBack) { LuaValueDict dict; dict["code"] = LuaValue::intValue((int)response->getResponseCode()); dict["tag"] = LuaValue::stringValue(response->getHttpRequest()->getTag()); dict["result"] = LuaValue::stringValue(result); // dict["request"] = LuaValue::ccobjectValue(this, "HTTPRequest"); LuaStack *stack = LuaEngine::getInstance()->getLuaStack(); stack->clean(); stack->pushLuaValueDict(dict); stack->executeFunctionByHandler(luaCallBack, 1); } } /****************************************************************************** **************************** LUA-BINDING ****************************** ******************************************************************************/ static int lua_tool_LuaHttp_constructor(lua_State* L) { int argc = 0; LuaHttp* self = nullptr; #if COCOS2D_DEBUG >= 1 tolua_Error tolua_err; #endif argc = lua_gettop(L)-1; if (argc == 0) { self = new (std::nothrow) LuaHttp(); tolua_pushusertype(L, (void*)self, "lt.LuaHttp"); tolua_register_gc(L, lua_gettop(L)); return 1; } luaL_error(L, "%s has wrong number of arguments: %d, was expecting %d \n", "LuaHttp",argc, 0); return 0; #if COCOS2D_DEBUG >= 1 tolua_lerror: tolua_error(L,"#ferror in function 'lua_tool_LuaHttp_constructor'.",&tolua_err); return 0; #endif } int lua_tool_LuaHttp_sendGet(lua_State* tolua_S) { int argc = 0; LuaHttp* cobj = nullptr; bool ok = true; #if COCOS2D_DEBUG >= 1 tolua_Error tolua_err; #endif #if COCOS2D_DEBUG >= 1 if (!tolua_isusertype(tolua_S,1,"lt.LuaHttp",0,&tolua_err)) goto tolua_lerror; #endif cobj = (LuaHttp*)tolua_tousertype(tolua_S,1,0); #if COCOS2D_DEBUG >= 1 if (!cobj) { tolua_error(tolua_S,"invalid 'cobj' in function 'lua_tool_LuaHttp_sendGet'", nullptr); return 0; } #endif argc = lua_gettop(tolua_S)-1; do { if (argc == 1) { std::string arg0; ok &= luaval_to_std_string(tolua_S, 2,&arg0, "lt.LuaHttp:sendGet"); if (!ok) { break; } cobj->sendGet(arg0.c_str(), ""); lua_settop(tolua_S, 1); return 1; } } while (0); ok = true; do { if (argc == 2) { std::string arg0; ok &= luaval_to_std_string(tolua_S, 2, &arg0, "lt.LuaHttp:sendGet"); if (!ok) { break; } std::string arg1; ok &= luaval_to_std_string(tolua_S, 3, &arg1, "lt.LuaHttp:sendGet"); if (!ok) { break; } cobj->sendGet(arg0.c_str(), arg1.c_str()); lua_settop(tolua_S, 1); return 1; } } while (0); ok = true; do { if (argc == 3) { std::string arg0; ok &= luaval_to_std_string(tolua_S, 2, &arg0, "lt.LuaHttp:sendGet"); if (!ok) { break; } std::string arg1; ok &= luaval_to_std_string(tolua_S, 3, &arg1, "lt.LuaHttp:sendGet"); if (!ok) { break; } LUA_FUNCTION callBack = (toluafix_ref_function(tolua_S, 4, 0)); cobj->sendGet(arg0.c_str(), arg1.c_str()); cobj->setLuaCallBack(callBack); lua_settop(tolua_S, 1); return 1; } } while (0); ok = true; luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d \n", "lt.LuaHttp:sendGet",argc, 1); return 0; #if COCOS2D_DEBUG >= 1 tolua_lerror: tolua_error(tolua_S,"#ferror in function 'lua_tool_LuaHttp_sendGet'.",&tolua_err); #endif return 0; } int lua_tool_LuaHttp_sendPost(lua_State* tolua_S) { int argc = 0; LuaHttp* cobj = nullptr; bool ok = true; #if COCOS2D_DEBUG >= 1 tolua_Error tolua_err; #endif #if COCOS2D_DEBUG >= 1 if (!tolua_isusertype(tolua_S,1,"lt.LuaHttp",0,&tolua_err)) goto tolua_lerror; #endif cobj = (LuaHttp*)tolua_tousertype(tolua_S,1,0); #if COCOS2D_DEBUG >= 1 if (!cobj) { tolua_error(tolua_S,"invalid 'cobj' in function 'lua_tool_LuaHttp_sendGet'", nullptr); return 0; } #endif argc = lua_gettop(tolua_S)-1; do { if (argc == 1) { std::string arg0; ok &= luaval_to_std_string(tolua_S, 2,&arg0, "lt.LuaHttp:sendGet"); if (!ok) { break; } cobj->sendGet(arg0.c_str(), ""); lua_settop(tolua_S, 1); return 1; } } while (0); ok = true; do { if (argc == 2) { std::string arg0; ok &= luaval_to_std_string(tolua_S, 2, &arg0, "lt.LuaHttp:sendGet"); if (!ok) { break; } std::string arg1; ok &= luaval_to_std_string(tolua_S, 3, &arg1, "lt.LuaHttp:sendGet"); if (!ok) { break; } cobj->sendGet(arg0.c_str(), arg1.c_str()); lua_settop(tolua_S, 1); return 1; } } while (0); ok = true; do { if (argc == 3) { std::string arg0; ok &= luaval_to_std_string(tolua_S, 2, &arg0, "lt.LuaHttp:sendGet"); if (!ok) { break; } std::string arg1; ok &= luaval_to_std_string(tolua_S, 3, &arg1, "lt.LuaHttp:sendGet"); if (!ok) { break; } LUA_FUNCTION callBack = (toluafix_ref_function(tolua_S, 4, 0)); cobj->sendPost(arg0.c_str(), arg1.c_str()); cobj->setLuaCallBack(callBack); lua_settop(tolua_S, 1); return 1; } } while (0); ok = true; luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d \n", "lt.LuaHttp:sendGet",argc, 1); return 0; #if COCOS2D_DEBUG >= 1 tolua_lerror: tolua_error(tolua_S,"#ferror in function 'lua_tool_LuaHttp_sendGet'.",&tolua_err); #endif return 0; } int lua_register_luaTool_LuaHttp(lua_State* tolua_S) { tolua_usertype(tolua_S, "lt.LuaHttp"); tolua_cclass(tolua_S, "LuaHttp","lt.LuaHttp", "", nullptr); tolua_beginmodule(tolua_S, "LuaHttp"); tolua_function(tolua_S, "new", lua_tool_LuaHttp_constructor); tolua_function(tolua_S, "sendGet", lua_tool_LuaHttp_sendGet); tolua_function(tolua_S, "sendPost", lua_tool_LuaHttp_sendPost); tolua_endmodule(tolua_S); std::string typeName = typeid(LuaHttp).name(); g_luaType[typeName] = "lt.LuaHttp"; g_typeCast["LuaHttp"] = "lt.LuaHttp"; return 1; } TOLUA_API int register_all_luaTool(lua_State* tolua_S) { tolua_open(tolua_S); tolua_module(tolua_S,"lt",0); tolua_beginmodule(tolua_S,"lt"); lua_register_luaTool_LuaHttp(tolua_S); tolua_endmodule(tolua_S); return 1; }说明:这里我没用cocos通用的cc开头,而用了lt(luatool的意思),看个人爱好。
---------------4.注册lua绑定--------4.1调用register_all_luaTool(_state); frameworks->cocos2d-x->cocos->scripting->lua-bindings->manual->CCLuaStack.cpp中的boolLuaStack::init(void)方法中在
register_all_cocos2dx(_state);下面添加register_all_luaTool(_state);
-----4.2添加头文件
#include "scripting/lua-bindings/luaTool/lua_tool.hpp"
---------5.项目中添加lua_tool.hpp和lua_tool.cpp
-----5.1 New Group
项目->cocos2d_lua_bindings.xcodeproj->右键->New Group->命名为luaTool
-----5.2 Add Files To ...
项目->cocos2d_lua_bindings.xcodeproj->luaTool->右键->Add Files To ...,选择lua_tool.hpp和lua_tool.cpp所在位置。-----5.3勾选libluacocos2d iOS
选中刚刚添加的两个文件,Xcode右侧->TargetMembership->勾选libluacocos2d iOS。否则在移动端还是没编译这两个文件。
---------6.lua调用
local callBack = function (request) print("返回 返回 code : ", request.code) print("返回 返回 tag : ", request.tag) print("返回 返回 result : ", request.result) end local luaHttp = lt.LuaHttp:new() -- luaHttp:sendGet("https://www.baidu.com/","", callBack) luaHttp:sendPost("https://www.baidu.com/","", callBack) ---------------7.添加完register_all_luaTool(_state );后的LuaStack::init方法 bool LuaStack::init(void) { _state = lua_open(); luaL_openlibs(_state); toluafix_open(_state); // Register our version of the global "print" function const luaL_reg global_functions [] = { {"print", lua_print}, {"release_print",lua_release_print}, {nullptr, nullptr} }; luaL_register(_state, "_G", global_functions); g_luaType.clear(); register_all_cocos2dx(_state); register_all_luaTool(_state); tolua_opengl_open(_state); register_all_cocos2dx_manual(_state); register_all_cocos2dx_module_manual(_state); register_all_cocos2dx_math_manual(_state); register_all_cocos2dx_experimental(_state); register_all_cocos2dx_experimental_manual(_state); register_glnode_manual(_state); #if CC_USE_PHYSICS register_all_cocos2dx_physics(_state); register_all_cocos2dx_physics_manual(_state); #endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC) LuaObjcBridge::luaopen_luaoc(_state); #endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) LuaJavaBridge::luaopen_luaj(_state); #endif register_all_cocos2dx_deprecated(_state); register_all_cocos2dx_manual_deprecated(_state); tolua_script_handler_mgr_open(_state); // add cocos2dx loader addLuaLoader(cocos2dx_lua_loader); return true; }
---------------8.Android.mk
若在Android平台运行,则需要修改对应的Android.mk文件。frameworks->cocos2d-x->cocos->scripting->lua-bindings->proj.android->Android.mk,大概65行的位置,在../manual/tolua_fix.cpp \下面添加代码:../luaTool/lua_tool.cpp \
--------9.其他
其中请求返回的callBack参数可以随便添加,仿照c++代码调用luaCallBack时的LuaValueDict即可(dict["xxx"] = xxx),类型自己点进去看看就行了。
--------10.虽然报nil,但最后还是列出XMLHttpRequest实现http请求的方法。
-- local xhr = cc.XMLHttpRequest:new() -- http请求 -- xhr.responseType = cc.XMLHTTPREQUEST_RESPONSE_STRING -- 响应类型 -- xhr:open("GET", "https://www.baidu.com/") -- 打开链接 -- -- 状态改变时调用 -- local function onReadyStateChange() -- -- 显示状态文本 -- -- local statusString = "Http Status Code:"..xhr.statusText -- -- labelStatusCode:setString(statusString) -- print(xhr.response) -- -- 显示状态码,成功显示200 -- -- labelStatusCode:setString("Http Status Code:"..xhr.statusText) -- -- local response = xhr.response -- 获得响应数据 -- -- local output = json.decode(response,1) -- 解析json数据 -- -- table.foreach(output,function(i, v) print (i, v) end) -- -- print("headers are") -- -- table.foreach(output.headers,print) -- end -- -- 注册脚本回调方法 -- xhr:registerScriptHandler(onReadyStateChange) -- xhr:send() -- 发送请求