如题,最近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 ...
-----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() -- 发送请求