Cocos2dx 3.X jsb加载JavaScript源码文件分析

前端之家收集整理的这篇文章主要介绍了Cocos2dx 3.X jsb加载JavaScript源码文件分析前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
Cocos2dx 3.X jsb加载JavaScript源码文件分析:
1、其实js和lua差不多,lua中通过require函数加载lua文件,js中也是通过一个函数require,加载js源码文件,而且思路差不多,那这个函数是如何执行的呢?

2、require函数
在ScriptingCore.cpp文件中有个registerDefaultClasses函数,这个函数注册了一些C++ 函数供javascript调用,require就是其中之一:
void registerDefaultClasses(JSContext* cx,JS::HandleObject global) {
………不需要的东西,都去掉了。
// register some global functions
//这里就是重点,注册了一个require函数,实际调用的是
    /**
     * run a script from script :)
     */
    static bool executeScript(JSContext *cx,uint32_t argc,jsval *vp);
函数,找到源头,我们可以去看下代码,具体如何实现得了。

JS_DefineFunction(cx,global,"require",ScriptingCore::executeScript,1,JSPROP_READONLY | JSPROP_PERMANENT);

//顺便说下这个,这个log如果是jsb可以直接使用,但不能在h5上面使用,所以最好还是使用cc.log
    JS_DefineFunction(cx,"log",ScriptingCore::log,JSPROP_READONLY | JSPROP_PERMANENT);
  
}
3、
//这个函数是我们的重点
bool ScriptingCore::executeScript(JSContext *cx,jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc,vp);//获取参数
    if (argc >= 1) {
        JSString* str = JS::ToString(cx,JS::RootedValue(cx,args.get(0)));
        JSStringWrapper path(str);
        bool res = false;
        if (argc == 2 && args.get(1).isString()) {
            JSString* globalName = args.get(1).toString();
            JSStringWrapper name(globalName);

            JS::RootedObject debugObj(cx,ScriptingCore::getInstance()->getDebugGlobal());
            if (debugObj) {
                res = ScriptingCore::getInstance()->runScript(path.get(),debugObj);
            } else {
                JS_ReportError(cx,"Invalid global object: %s",name.get());
                return false;
            }
        } else {
            JS::RootedObject glob(cx,JS::CurrentGlobalOrNull(cx));
            res = ScriptingCore::getInstance()->runScript(path.get(),glob);
        }
        return res;
    }
    args.rval().setUndefined();
    return true;
}

------》》其实最终都是执行这个path就是我们传进来,也就是想要加载的js文件
ScriptingCore::getInstance()->runScript(path.get(),glob);
4、这个函数就是真正加载的函数:
bool ScriptingCore::runScript(const char *path,JS::HandleObject global,JSContext* cx)
{
    if (cx == NULL) {
        cx = _cx;
    }
 //进行编译
    compileScript(path,cx);
    JS::RootedScript script(cx,getScript(path));
    bool evaluatedOK = false;
if (script) {
//编译完后,就可以调用JS_ExecuteScript函数执行了。
        JS::RootedValue rval(cx);
        JSAutoCompartment ac(cx,global);
        evaluatedOK = JS_ExecuteScript(cx,script,&rval);
        if (false == evaluatedOK) {
            cocos2d::log("(evaluatedOK == JS_FALSE)");
            JS_ReportPendingException(cx);
        }
    }
 
    return evaluatedOK;
}
5、编译函数
void ScriptingCore::compileScript(const char *path,JSObject* global,JSContext* cx)
{
    if (!path) {
        return;
    }
    
if (getScript(path)) { //如果已经编译过,则直接返回,这里有一个缓存
// name ~> JSScript map
static std::unordered_map<std::string,JSScript*> filename_script;
        return;
    }

    cocos2d::FileUtils *futil = cocos2d::FileUtils::getInstance();

    if (global == NULL) {
        global = _global.ref().get();
    }
    if (cx == NULL) {
        cx = _cx;
    }
    JSAutoCompartment ac(cx,global);

    JS::RootedScript script(cx);
    JS::RootedObject obj(cx,global);

    // a) check jsc file first  //先测试字节码,我们一般把js文件弄成字节码,防止被人使用
    std::string byteCodePath = RemoveFileExt(std::string(path)) + BYTE_CODE_FILE_EXT;

    // Check whether '.jsc' files exist to avoid outputing log which says 'couldn't find .jsc file'.
    if (futil->isFileExist(byteCodePath))
    { //如果找到字节码文件,则进行JS_DecodeScript解码
        Data data = futil->getDataFromFile(byteCodePath);
        if (!data.isNull())
        {
            script = JS_DecodeScript(cx,data.getBytes(),static_cast<uint32_t>(data.getSize()),nullptr);
        }
    }

    // b) no jsc file,check js file, 如果没有jsc字节码文件,则找js文件
    if (!script)
    {
        /* Clear any pending exception from prevIoUs Failed decoding.  */
        ReportException(cx);

        std::string fullPath = futil->fullPathForFilename(path);
   
        JS::CompileOptions op(cx);
        op.setUTF8(true);
        op.setFileAndLine(fullPath.c_str(),1);

        bool ok = false;
//这里对不同平台有个不同的处理,主要是存放文件的方式不同,然后调用
JS::Compile编译即可。
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
        std::string jsFileContent = futil->getStringFromFile(fullPath);
        if (!jsFileContent.empty())
        {
            ok = JS::Compile(cx,obj,op,jsFileContent.c_str(),jsFileContent.size(),&script);
        }
#else
        ok = JS::Compile(cx,fullPath.c_str(),&script);
#endif
        if (ok) {
            filename_script[fullPath] = script;
        }
    }
    else {
        filename_script[byteCodePath] = script;
    }
}






猜你在找的Cocos2d-x相关文章