cocos2d-x jsbinding 资源下载实现

    cocos2dx没有直接给出资源下载的api,可能是因为资源的管理每个项目的需求不太一样,所以完整的资源下载功能需要我们自己去实现。

    资源下载分为两部分,一部分是资源请求,另一部分是资源文件写入。资源请求模块,cocos2d-x封装了curl的功能,主要实现是extensions etwork下的几个类,通过他们我们可以方便的实现Http请求的功能。资源的写入主要是利用fwrite函数将数据流写入文件。完成了C++模块的实现以后,我们要做的是绑定到js,这样我们就可以在js端发起请求,将资源下载到手机。这里C++绑定还有Http请求的封装主要借鉴了https://github.com/akira-cn/cocos2dx-cqwrap/blob/master/cqwrap/src/scripting/cqwrap_httprequest_manual.cpp 我在此的基础上做了一些改动,同时增加了文件的写入功能

#include "cqwrap_register_all_manual.h"

#include "util/JsonHelper.h"

#include "pattern/EventProxy.h"
#include <algorithm>
#include <sstream>


#include "cocos-ext.h"
// 这个用于获取各个平台的资源缓存缓存路径,关于缓存路径,请看http://www.cnblogs.com/hzd822/p/3258641.html
#include "KT_ALL_PLATFORMS.h"


USING_NS_CC_EXT;



void js_register_cocos2dx_extension_httprequest(JSContext *cx, JSObject *global);

JSClass  *jsb_HttpRequest_Class;

JSObject *jsb_HttpRequest_prototype;



void register_cqwrap_httprequest(JSContext* cx, JSObject* obj) {

    // first, try to get the ns

    jsval nsval;

    JSObject *ns;

    JS_GetProperty(cx, obj, "cc", &nsval);

    if (nsval == JSVAL_VOID) {

        ns = JS_NewObject(cx, NULL, NULL, NULL);

        nsval = OBJECT_TO_JSVAL(ns);

        JS_SetProperty(cx, obj, "cc", &nsval);

    } else {

        JS_ValueToObject(cx, nsval, &ns);

    }

    obj = ns;



    js_register_cocos2dx_extension_httprequest(cx, obj);

}


// 这个类对CCHttpRequest的封装
class HttpRequest: public CCObject{

protected:

    CCHttpRequest* m_request;

    std::vector<std::string> m_headers;

    int m_writefile;

    std::string m_url;

    struct xorStruct

    {

        xorStruct(char value) : m_value(value) {}

        char m_value;

        char operator()(char in) const { return in ^ m_value; }

    };

    

    void responseCallback(cocos2d::CCNode *sender, void *data){

        CCHttpResponse *response = (CCHttpResponse*)data; 



        if (!response) 

        { 

            CCLog("no response...");

            return; 

        } 



        int statusCode = response->getResponseCode(); 

        char statusString[64] = {}; 

        sprintf(statusString, "HTTP Status Code: %d", statusCode); 

        

        CCLOG("response code: %d", statusCode); 



        if (!response->isSucceed())  

        { 

            CCLOG("response failed"); 

            CCLOG("error buffer: %s", response->getErrorBuffer()); 

            

            JsonData* msg = new JsonData();

            (*msg)["data"] = response->getErrorBuffer();

            PROXY_FIRE("error", msg);

            CC_SAFE_DELETE(msg);



            return; 

        }



        JsonData* msg = new JsonData();

        // dump data 

        std::vector<char> *buffer = response->getResponseData();

        if (m_writefile == 1){

            // 获取相对路径

            std::string relativePath = m_url.substr(m_urlhostNum);

            std::string filePath;

            filePath = kt_library_path();

            #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
                
                filePath = filePath + "/Caches/";
                
            #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)

                filePath = filePath + "/Caches/";

            #endif

            filePath.append(relativePath);

            this->writeToFile(filePath.c_str(), *buffer);

            (*msg)["status"] = statusCode;

        }else{

            std::string buf(buffer->begin(),buffer->end());

            (*msg)["data"] = buf.c_str();

        }



        PROXY_FIRE("complete", msg);

        CC_SAFE_DELETE(msg);

    };

    

public:
    int m_urlhostNum;
    
    void send(const char* buffer = NULL){

        if(m_request != NULL){

            if(NULL != buffer){

                m_request->setRequestData(buffer, sizeof buffer);

            }

            m_request->setHeaders(m_headers);

            CCHttpClient::getInstance()->send(m_request);

            CC_SAFE_RELEASE_NULL(m_request);

            m_headers.clear();

        }

    };

    
    // 文件写入
    bool writeToFile(const char *filePath,std::vector<char> _responseData) {

        FILE* fout = fopen(filePath, "wb+");

        if (fout == NULL)

            return false;

        

        if (_responseData.size() > 0) {

            if (fwrite(&_responseData[0], sizeof(char), _responseData.size(), fout) != _responseData.size()) {

                fclose(fout);

                return false;

            }

        }

        

        fclose(fout);

        return true;

    }

    

    void setRequestHeader(std::string key, std::string content){

        if(m_request != NULL){

            key += ": ";

            key += content;

            m_headers.push_back(key);

        }

    };

    

    void setRequestData(std::string* requestData){

        if(m_request != NULL){

            m_request->setRequestData(requestData->c_str(),requestData->length());

        }

    };

    

    void open(CCHttpRequest::HttpRequestType type, const char* url,int writeFile){



        CC_SAFE_RELEASE_NULL(m_request);

        m_writefile = writeFile;

        m_request = new CCHttpRequest(); 

        m_request->setUrl(url);

        m_request->setRequestType(type);

        m_request->setResponseCallback(this, callfuncND_selector(HttpRequest::responseCallback));

        m_url = url;

    };

    HttpRequest(){

        m_request = NULL;

        m_headers = std::vector<std::string>();

        m_writefile = 0;
        
        m_urlhostNum = 32;

    };

    ~HttpRequest(){

        CC_SAFE_RELEASE_NULL(m_request);

    };

};


// 从这里开始是将C++类绑定到js,使js可以调用C++函数
JSBool js_cocos2dx_extension_HttpRequest_setRequestHeader(JSContext *cx, uint32_t argc, jsval *vp){

    jsval *argv = JS_ARGV(cx, vp);

    JSObject *obj = JS_THIS_OBJECT(cx, vp);

    js_proxy_t *proxy; JS_GET_NATIVE_PROXY(proxy, obj);

    HttpRequest* cobj = (HttpRequest *)(proxy ? proxy->ptr : NULL);

    JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object");



    if(argc == 2){

        std::string* key = new std::string();



        do {

            JSBool ok = jsval_to_std_string(cx, argv[0], key);

            JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments");

        } while (0);



        std::string* value = new std::string();



        do {

            JSBool ok = jsval_to_std_string(cx, argv[1], value);

            JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments");

        } while (0);



        cobj->setRequestHeader(*key, *value);



        JS_SET_RVAL(cx, vp, JSVAL_VOID);



        CC_SAFE_DELETE(key);

        CC_SAFE_DELETE(value);



        return JS_TRUE;    

    }

    JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 1);

    return JS_FALSE;

}



JSBool js_cocos2dx_extension_HttpRequest_setRequestData(JSContext *cx, uint32_t argc, jsval *vp){

    jsval *argv = JS_ARGV(cx, vp);

    JSObject *obj = JS_THIS_OBJECT(cx, vp);

    js_proxy_t *proxy; JS_GET_NATIVE_PROXY(proxy, obj);

    HttpRequest* cobj = (HttpRequest *)(proxy ? proxy->ptr : NULL);

    JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object");

    

    if(argc == 1){

        std::string* requestData = new std::string();

        

        do {

            JSBool ok = jsval_to_std_string(cx, argv[0], requestData);

            JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments");

        } while (0);

        

        

        cobj->setRequestData(requestData);

        

        JS_SET_RVAL(cx, vp, JSVAL_VOID);

        

        CC_SAFE_DELETE(requestData);

        

        return JS_TRUE;

    }

    JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0);

    return JS_FALSE;

}



JSBool js_cocos2dx_extension_HttpRequest_open(JSContext *cx, uint32_t argc, jsval *vp){

    jsval *argv = JS_ARGV(cx, vp);

    JSObject *obj = JS_THIS_OBJECT(cx, vp);

    js_proxy_t *proxy; JS_GET_NATIVE_PROXY(proxy, obj);

    HttpRequest* cobj = (HttpRequest *)(proxy ? proxy->ptr : NULL);

    JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object");



    if(argc == 2 || argc == 3 || argc == 4){

        std::string* method = new std::string();

        

        do {

            JSBool ok = jsval_to_std_string(cx, argv[0], method);

            JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments");

        } while (0);



        std::string* url = new std::string();



        do {

            JSBool ok = jsval_to_std_string(cx, argv[1], url);

            JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments");

        } while (0);


        int writeFile = 1;

        if (argc == 3){

            do {

                JSBool ok = jsval_to_int32(cx, argv[2], &writeFile);

                JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments");

            } while (0);

        }
        
        int urlhostNum;
        if (argc == 4){
            do {
                JSBool ok = jsval_to_int32(cx, argv[3], &urlhostNum);

                JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments");
                
                cobj->m_urlhostNum = urlhostNum;

            } while (0);

        }

        

        if(*method == "POST"){

            cobj->open(CCHttpRequest::kHttpPost, url->c_str(),writeFile);

        }else{

            cobj->open(CCHttpRequest::kHttpGet, url->c_str(),writeFile);

        }

        JS_SET_RVAL(cx, vp, JSVAL_VOID);

        

        CC_SAFE_DELETE(url);

        CC_SAFE_DELETE(method);



        return JS_TRUE;    

    }

    JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 1);

    return JS_FALSE;

}



JSBool js_cocos2dx_extension_HttpRequest_send(JSContext *cx, uint32_t argc, jsval *vp){

    jsval *argv = JS_ARGV(cx, vp);

    JSObject *obj = JS_THIS_OBJECT(cx, vp);

    js_proxy_t *proxy; JS_GET_NATIVE_PROXY(proxy, obj);

    HttpRequest* cobj = (HttpRequest *)(proxy ? proxy->ptr : NULL);

    JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object");



    if(argc == 1){

        std::string* data = new std::string();

        do {

            JSBool ok = jsval_to_std_string(cx, argv[0], data);

            JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments");

        } while (0);



        cobj->send(data->c_str());

        JS_SET_RVAL(cx, vp, JSVAL_VOID);

        CC_SAFE_DELETE(data);

        return JS_TRUE;    

    }

    if(argc == 0){

        cobj->send();

        JS_SET_RVAL(cx, vp, JSVAL_VOID);

        return JS_TRUE;    

    }

    JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 1);

    return JS_FALSE;

}



JSBool js_cocos2dx_extension_HttpRequest_oncomplete(JSContext *cx, uint32_t argc, jsval *vp){

    JS_SET_RVAL(cx, vp, JSVAL_VOID);

    return JS_FALSE;

}



JSBool js_cocos2dx_extension_HttpRequest_onerror(JSContext *cx, uint32_t argc, jsval *vp){

    JS_SET_RVAL(cx, vp, JSVAL_VOID);

    return JS_TRUE;

}



void js_cocos2dx_extension_HttpRequest_finalize(JSFreeOp *fop, JSObject *obj){



}



JSBool js_cocos2dx_extension_HttpRequest_constructor(JSContext *cx, uint32_t argc, jsval *vp){

    if(argc == 0){

        HttpRequest* cobj = new HttpRequest(); 

        cocos2d::CCObject *_ccobj = dynamic_cast<cocos2d::CCObject *>(cobj);

        if (_ccobj) {

            _ccobj->autorelease();

        }



        TypeTest<cocos2d::extension::CCHttpRequest> t;

        js_type_class_t *typeClass;

        uint32_t typeId = t.s_id();

        HASH_FIND_INT(_js_global_type_ht, &typeId, typeClass);

        assert(typeClass);

        JSObject *obj = JS_NewObject(cx, typeClass->jsclass, typeClass->proto, typeClass->parentProto);



        JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));

        // link the native object with the javascript object

        js_proxy_t *p;

        JS_NEW_PROXY(p, cobj, obj);

        JS_AddNamedObjectRoot(cx, &p->obj, "HttpRequest");



        return JS_TRUE;

    }

    JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0);

    return JS_FALSE;

}



void js_register_cocos2dx_extension_httprequest(JSContext *cx, JSObject *global) {

    jsb_HttpRequest_Class = (JSClass *)calloc(1, sizeof(JSClass));

    jsb_HttpRequest_Class->name = "HttpRequest";

    jsb_HttpRequest_Class->addProperty = JS_PropertyStub;

    jsb_HttpRequest_Class->delProperty = JS_PropertyStub;

    jsb_HttpRequest_Class->getProperty = JS_PropertyStub;

    jsb_HttpRequest_Class->setProperty = JS_StrictPropertyStub;

    jsb_HttpRequest_Class->enumerate = JS_EnumerateStub;

    jsb_HttpRequest_Class->resolve = JS_ResolveStub;

    jsb_HttpRequest_Class->convert = JS_ConvertStub;

    jsb_HttpRequest_Class->finalize = js_cocos2dx_extension_HttpRequest_finalize;

    jsb_HttpRequest_Class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);



    static JSPropertySpec properties[] = {

        {0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER}

    };



    static JSFunctionSpec funcs[] = {

        JS_FN("oncomplete",js_cocos2dx_extension_HttpRequest_oncomplete, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),

        JS_FN("onerror",js_cocos2dx_extension_HttpRequest_onerror, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),

        JS_FN("send",js_cocos2dx_extension_HttpRequest_send, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),

        JS_FN("open",js_cocos2dx_extension_HttpRequest_open, 2, JSPROP_PERMANENT | JSPROP_ENUMERATE),

        JS_FN("setRequestHeader",js_cocos2dx_extension_HttpRequest_setRequestHeader, 2, JSPROP_PERMANENT | JSPROP_ENUMERATE),


        JS_FS_END

    };



    jsb_HttpRequest_prototype = JS_InitClass(

        cx, global,

        jsb_HttpRequest_prototype,

        jsb_HttpRequest_Class,

        js_cocos2dx_extension_HttpRequest_constructor, 0, // constructor

        properties,

        funcs,

        NULL, // no static properties

        NULL);



    // make the class enumerable in the registered namespace

    JSBool found;

    JS_SetPropertyAttributes(cx, global, "HttpRequest", JSPROP_ENUMERATE | JSPROP_READONLY, &found);



    // add the proto and JSClass to the type->js info hash table

    TypeTest<cocos2d::extension::CCHttpRequest> t;

    js_type_class_t *p;

    uint32_t typeId = t.s_id();

    HASH_FIND_INT(_js_global_type_ht, &typeId, p);

    if (!p) {

        p = (js_type_class_t *)malloc(sizeof(js_type_class_t));

        p->type = typeId;

        p->jsclass = jsb_HttpRequest_Class;

        p->proto = jsb_HttpRequest_prototype;

        p->parentProto = NULL;

        HASH_ADD_INT(_js_global_type_ht, type, p);

    }

}

  绑定完之后,js的调用就很简单了

// 创建http请求,请求远程图片
        var httpRequest = cc.HttpRequest();
        httpRequest.open('GET',fullPath);
        httpRequest.send();
        httpRequest.oncomplete = function (evt){
            if (evt.status == 200){
                cc.log(fullPath+'------downLoad success');
                // 下载成功
            }
        }

        httpRequest.onerror = function (evt){
            cc.log(fullPath+'------downLoad error');
            }
        }

  

原文地址:https://www.cnblogs.com/zhepama/p/3288574.html