函数项目【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)函数项目

本文朋友在北京吃饭的时候突然想到的...近期就有想写几篇关于函数项目的文章,所以回家到之后就奋笔疾书的写出来发表了

    

    本站文章均为 李华明Himi 创原,转载务必在显明处注明:(作者新浪微博: @李华明Himi 
转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/iphone-cocos2dx/1354.html
 

☞ 点击订阅 ☜
 本博客最新动态!时及将最新博文知通您!

    

    

    

    

 

    

 

    

    首先说明一个题问:

    为什么要在线更新源资和本脚件文!?

    对于此题问,那要说的太多了,简略归纳综合,如果你的项目已经在google play 或Apple Store 等台平上架了,那么当你项目要需做一些活动或者修改前端的一些代码等那么你要需新重提交一个新本版给台平,这时候你的上架时候是个不确定的时候,具体什么时候能上架,重要跟台平有关,你再焦急,也没有用的。

    那么如果你的项目是应用本脚语言行进编写的,例如lua,js等等,那么一旦你有要需更新你的项目,你完全可以通过从服务器下载最新的本脚和源资来实现在线更新,免除很多懊恼,最少更新再也不要需台平的核审来制限了不是么~(有些台平是止禁在线更新源资方法的,但是你得懂)

    那么如在何项目中实现在线更新呢?则是本章具体要需跟大家分享的教程啦。

    面下进入本章的重要内容:

    在cocos2dx 2.x 擎引的扩展包(extensions)中有一个 AssetsManager

    AssetsManager 重要功能就是下载源资到当地,并帮你解压!

    如果大家还不道知这个类,那么可以先到cocos2dx擎引的http:///Users/slater/Documents/cocos2d-2.1rc0-x-2.1.2-hotfix/samples/Cpp/AssetsManagerTest 录目下行运示例。

     (注:以后Himi应用的是cocos2dx-2.1.2hotfix本版这个示例在我的mac os法无正常行运)

    面下Himi新建个项目来具体解讲AssetsManager:

    Himi这里拿lua项目行进,首先创立一个新的cocos2dx-lua 的项目:

    第一步:将项目中Resoures录目下的 hello.lua 除删!

         第二步:在AppDelegate.h 中添加如下代码:

    先导入所需的头件文:

    

1
2
3
4
5
6
7
8
9
10
11
#include "cocos2d.h"
#include "AssetsManager.h"
#include "cocos-ext.h"
using namespace std;
using namespace cocos2d;
using namespace extension;
 
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
#include <dirent.h>
#include <sys/stat.h>
#endif

    续继添加变量和方法名:

    

1
2
3
void updateFiles();
void createDownDir();
string pathToSave;

    pathToSave 变量用于存保下载的路径!用于添加到  CCLuaEngine 擎引中,这样便于CCLuaEngine查找Lua件文!

     第三步:在AppDelegate.cpp 中添加如下代码:

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
static AssetsManager* pAssetsManager;
 
void AppDelegate::updateFiles(){
    createDownDir();
 
 
    if(pAssetsManager->checkUpdate()){
        if( pAssetsManager->update() ){//改码源
 
            CCLuaEngine* pEngine = CCLuaEngine::defaultEngine();
            CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
 
            //首先添加下载件文的录目
            pEngine->addSearchPath(pathToSave.c_str());
 
            //续继添加当地hello2的路径到CCLuaEngine中
            string path = CCFileUtils::sharedFileUtils()->fullPathForFilename("hello2.lua");
            pEngine->addSearchPath(path.substr(0, path.find_last_of("/")).c_str());
 
            //行运下载件文hello.lua
            string runLua = CCFileUtils::sharedFileUtils()->fullPathForFilename("hello.lua");
            pEngine->executeScriptFile(runLua.c_str());
 
        }
    }
}
 
void AppDelegate::createDownDir(){
    pathToSave = CCFileUtils::sharedFileUtils()->getWritablePath();
    pathToSave += "Himi";
 
    // Create the folder if it doesn't exist
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
    DIR *pDir = NULL;
 
    pDir = opendir (pathToSave.c_str());
    if (! pDir)
    {
        mkdir(pathToSave.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
    }
#else
    if ((GetFileAttributesA(pathToSave.c_str())) == INVALID_FILE_ATTRIBUTES)
    {
        CreateDirectoryA(pathToSave.c_str(), 0);
    }
#endif
 
}

    首先绍介createDwomDir函数:

    (注:有所连接都是Hmi在GitHub服务器中的,大家可以所以拜访)!

    此函数重要用于在项目录目下新建一个件文夹,到底创立到哪里,你不必管,交给如下函数:

    CCFileUtils::sharedFileUtils()->getWritablePath();

    下面这个函数能从ios、android台平动自找到可写入的路径!

    createDwomDir 函数中  pathToSave += “Himi”;  重要作用是在getWritablePath()路径后自定义一个录目名!要需不要需都可以的,如果想创立个,那就自定义便可,名字无所谓思密达。

    续继绍介  updateFiles 函数

    此函数中,首先我们调用 createDwomDir 函数用于创立我们新的写入录目,并且将录目存保到pathToSave变量中。

    然后我们创立了一个 AssetsManager 实例,这里要静态。AssetsManager创立函数有两种,如下:

    

1
2
3
1. AssetsManager::AssetsManager(const char* packageUrl, const char* versionFileUrl)
 
2. AssetsManager::AssetsManager(const char* packageUrl, const char* versionFileUrl, const char* storagePath)

    首先看第一种创立函数:

    参数1 :  packgeUrl: 表示要需下载更新的zip包的url地址

    参数2 : versionFileUrl :表示获取以后服务器本版号的rul,用于匹配客户端是否要需更新!

    第二种创立方法多了一个参数: storagePath 表示我们的自定义包名,如createDwomDir函数中的pathToSave += “Himi” 一句功能一样。

    而在AssetsManager类中封装了很多方法,例如检查是否要需更新、更新下载件文、获取packageUrl等。具体方法可看AssetsManager码源!

    pAssetsManager->checkUpdate() :通过得到服务器返回的本版号与当地本版号行进匹配如不一致则返回true,反之返回false

    一旦通过判断checkUpdate函数返回true,我们便可调用AssetsManager中的update行进件文更新!

    这里要注意:由于以后AssetsManager的码源中并没有给予我们判断件文下载成功的函数!因此Himi与AssetsManager作者联系,我们可以更改update函数让其返回bool类型便可! (注:update 函数中对本版做了比较、对下载件文做了判断、对解压做了判断,所以当此函数返回true,则完成一切操作)

    修改方法如下:首先我们到码源AssetsManager.h中将如下upate函数修改:

    

1
2
3
4
5
virtual void update();
 
修改成如下:
 
virtual bool update();

    续继到 AssetsManager.cpp 中update函数行进修改成如下:

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
修改为:
 
bool AssetsManager::update()
{
    // 1. Urls of package and version should be valid;
    // 2. Package should be a zip file.
    if (_versionFileUrl.size() == 0 ||
        _packageUrl.size() == 0 ||
        std::string::npos == _packageUrl.find(".zip"))
    {
        CCLOG("no version file url, or no package url, or the package is not a zip file");
        return false;
    }
 
    // Check if there is a new version.
    if (! checkUpdate()) return false;
 
    // Is package already downloaded?
    string downloadedVersion = CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_DOWNLOADED_VERSION);
    if (downloadedVersion != _version)
    {
        if (! downLoad()) return false;
 
        // Record downloaded version.
        CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, _version.c_str());
        CCUserDefault::sharedUserDefault()->flush();
    }
 
    // Uncompress zip file.
    if (! uncompress()) return false;
 
    // Record new version code.
    CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_VERSION, _version.c_str());
 
    // Unrecord downloaded version code.
    CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, "");
 
    CCUserDefault::sharedUserDefault()->flush();
 
    // Set resource search path.
    setSearchPath();
 
    // Delete unloaded zip file.
    string zipfileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
    if (remove(zipfileName.c_str()) != 0)
    {
        CCLOG("can not remove downloaded zip file");
    }
    return true;
}

    当我们做了如此的修改后,那么当件文下载完成后则会返回true!

    最后我们来看如下代码:

     

    

1
2
3
4
5
6
7
8
9
10
11
12
13
CCLuaEngine* pEngine = CCLuaEngine::defaultEngine();
CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
 
//首先添加下载件文的录目
pEngine->addSearchPath(pathToSave.c_str());
 
//续继添加当地hello2的路径到CCLuaEngine中
string path = CCFileUtils::sharedFileUtils()->fullPathForFilename("hello2.lua");
pEngine->addSearchPath(path.substr(0, path.find_last_of("/")).c_str());
 
//行运下载件文hello.lua
string runLua = CCFileUtils::sharedFileUtils()->fullPathForFilename("hello.lua");
pEngine->executeScriptFile(runLua.c_str());

     

     

    首先我们将件文更新下来的路径通过setScriptEngine添加到 CCLuaEngine中,然后将hello2.lua 的路径也添加到CCLuaEngine的搜索途径中,这样一来 CCLuaEngine 会从我们设置的这两个路径中去找我们在lua中require的对应lua件文!这一步设置必须设置!因为CCLuaEngine不像cocos2dx那样动自帮我们找件文路径!CCLuaEngine 是不存在路径的,所以我们要手动设置CCLuaEngine搜索路径,以便找到对应的lua件文!

    也正是因为CCLuaEngine不会动自帮我们找件文路径,因此我们行运lua本脚时,必须将行运的本脚lua件文完整的路径传入,如下:

    

1
2
3
//行运下载件文hello.lua
            string runLua = CCFileUtils::sharedFileUtils()->fullPathForFilename("hello.lua");
            pEngine->executeScriptFile(runLua.c_str());

          面下我们开始书写测试代码:

    在AppDelegate.cpp中的  applicationDidFinishLaunching 函数中注释一些代码并且添加测试代码,修改后的 applicationDidFinishLaunching 函数内容如下:

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
bool AppDelegate::applicationDidFinishLaunching()
{
    // initialize director
    CCDirector *pDirector = CCDirector::sharedDirector();
    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());
 
    // turn on display FPS
    pDirector->setDisplayStats(true);
 
    // set FPS. the default value is 1.0/60 if you don't call this
    pDirector->setAnimationInterval(1.0 / 60);
 
    // register lua engine
//    CCLuaEngine* pEngine = CCLuaEngine::defaultEngine();
//    CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
//
//#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
//    CCString* pstrFileContent = CCString::createWithContentsOfFile("hello.lua");
//    if (pstrFileContent)
//    {
//        pEngine->executeString(pstrFileContent->getCString());
//    }
//#else
//    std::string path = CCFileUtils::sharedFileUtils()->fullPathForFilename("hello.lua");
//    pEngine->addSearchPath(path.substr(0, path.find_last_of("/")).c_str());
//    pEngine->executeScriptFile(path.c_str());
//#endif
 
    //除删hello.lua
    pathToSave="";
    updateFiles();
 
    return true;
}

    面下开始行运!要需注意的是我们当地是完全不存在hello.lua件文的,所以一旦我们行运成功出现画面说明已经利用AssetsManager成功的在线下载了hello.lua件文!

    行运截图如下:

    函数项目【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)函数项目_第1张图片

     

     

    从如上的行运截图中可以看出,首先我们得到服务器传来的本版号2.1.1,然后行进checkUpdate函数,此函数是从当地的存储件文找是否有本版号,如果没有那么就默认为可下载,如果有则会对比,如不一致则行进更新。

    那么当件文完整下载下来之后update函数则动自会我们在当地存保最新从服务器拿到的本版号!紧接着update函数还为我们行进了对zip件文的解压,解压成功后会动自除删zip包!

    因此如果大家行运过自己的这个项目成功下载行运了,那么下载行运请除删项目后再行运,因为第一次的成功行运已经将最新本版号记录存保下来了,你也可以通过修改服务器本版号或者除删项目的存储件文。

     

    总结本文的教程:

    第一:     CCLuaEngine 擎引是不会动自帮我们找件文的,所以你一旦有一个新的行运本脚的路径,一定要通过  CCLuaEngine的 addSearchPath函数告知!这样的话,当你的一个lua件文采用require其他本脚件文,CCLuaEngine就会在你 addSearchPath的路径中行进查找!

    第二: 如果你想让自己项目自带的本脚与下载本脚同时应用,例如自己项目有a.lua 其中a.lua 中包含一句代码: requireb  ”b”   ,而b.lua是你通过在线更新下载下来的。那么a.lua 和 b.lua的路径都要通过 addSearchPath 设置下各自的路径。

    第三: lua engine应该也是支持搜索路径的优先级的,所以你可以通过控制pEngine->addSearchPath()的调用顺序,从而控制当你当地项目与下载更新同时拥有同一个名字的本脚等源资,可以优先选择应用哪个!

    第四: 在AppStore 规定不允许在主游戏线程中行进联网,然后我们应用的AssetsManager的下载更新却是在联网下载,所以大家要应用异步来做!另外时及没有这条规定我想童鞋们也不会让联网放主游戏线程中吧!

    第五:AssetsManager 中还有其他的功能,更多的功能请大家自己看cocos2dx擎引的示例项目!

     

    最后给出Himi的示例项目下载地址:

               OLUpdateFilesByHimi   :    http://vdisk.weibo.com/s/ycZU1

     

    :Himi:    本篇就到这里,希望对各位没有做过、正要做此功能的童鞋们提供帮助!

     

    


文章结束给大家分享下程序员的一些笑话语录: 开发时间
  项目经理: 如果我再给你一个人,那可以什么时候可以完工?程序员: 3个月吧!项目经理: 那给两个呢?程序员: 1个月吧!
项目经理: 那100呢?程序员: 1年吧!
项目经理: 那10000呢?程序员: 那我将永远无法完成任务.

你可能感兴趣的:(cocos2dx)