根据服务器检测本地版本号并自动更新资源

.h

#ifndef __AutoUpdate__AutoUpdateLayer__
#define __AutoUpdate__AutoUpdateLayer__

#include "cocos2d.h"
#include "curl.h"

USING_NS_CC;
using namespace std;

#define BUFFER_SIZE    8192
#define MAX_FILENAME   512

enum class ErrorCode
{
    // Error caused by creating a file to store downloaded data
    CREATE_FILE,
    /** Error caused by network
     -- network unavaivable
     -- timeout
     -- ...
     */
    NETWORK,
    /** There is not a new version
     */
    NO_NEW_VERSION,
    /** Error caused in uncompressing stage
     -- can not open zip file
     -- can not read file global information
     -- can not read file information
     -- can not create a directory
     -- ...
     */
    UNCOMPRESS,
};

class AssetsManagerDelegateProtocol
{
public:
    virtual ~AssetsManagerDelegateProtocol(){};
public:
    /* @brief Call back function for error
     @param errorCode Type of error
     * @js NA
     * @lua NA
     */
    virtual void onError(ErrorCode errorCode) {};
    /** @brief Call back function for recording downloading percent
     @param percent How much percent downloaded
     @warning    This call back function just for recording downloading percent.
     AssetsManager will do some other thing after downloading, you should
     write code in onSuccess() after downloading.
     * @js NA
     * @lua NA
     */
    virtual void onProgress(int percent) {};
    /** @brief Call back function for success
     * @js NA
     * @lua NA
     */
    virtual void onSuccess() {};
};

class AutoUpdateLayer : public Layer
{
public:
    static Scene * createScene();
    
    virtual bool init();
    
    virtual void onEnter();
    
    virtual void onExit();
    
    CREATE_FUNC(AutoUpdateLayer);
    
    /**
     *检查资源是否需要更新的更新函数
     */
    void update(float dt);
    
    /**
     *读取json文件,初始化页面上的ui资源
     */
    void initUI();
    
    /**
     *检查是否需要更新版本
     */
    bool checkUpdate();
    
    /**
     *联网获取版本信息的回调函数
     */
    static size_t geVersionData(char *data, size_t size, size_t nmeb, void *stream);
    
    /**
     *解析版本数据的字典,获取对应的版本信息数据
     */
    int getLatestVersion();
    
    /**
     *执行下载资源并解压到指定的目录,并更新本地版本号
     */
    void downloadAndUncompress();
    
    /**
     *下载需要更新的资源
     */
    bool downLoad();
    
    /**
     *下载需要更新的资源的回调函数
     */
    static size_t downLoadPackage(void *ptr, size_t size, size_t nmemb, void *userdata);
    
    /**
     *显示下载进度百分比的回调函数
     */
    static int assetsManagerProgressFunc(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded);
    
    /**
     *解压文件
     */
    bool uncompress();
    
    bool createDirectory(const char *path);
    
private:
    /**
     *是否需要下载的标志位
     */
    bool needDownload;
    
    /**
     *版本信息的字典的本地存储路径
     */
    string fileDicLocalPath;
    
    /**
     *本地资源的版本号
     */
//    int m_iLocalVersionValue;
    
    AssetsManagerDelegateProtocol *_delegate;
    
    CURL * _curl;
    
    /**
     *下载的资源存储的位置
     */
    string fileLocalPath;
};

#endif /* defined(__AutoUpdate__AutoUpdateLayer__) */
.cpp

#include "AutoUpdateLayer.h"
#include "unzip.h"
#include "PngName.h"
#include <sys/stat.h>
#include "AssetsManager.h"

Scene * AutoUpdateLayer::createScene()
{
    auto scene = Scene::create();
    
    auto layer = AutoUpdateLayer::create();
    
    scene->addChild(layer);
    
    return scene;
}

bool AutoUpdateLayer::init()
{
    if (!Layer::init())
    {
        return false;
    }
    
    this->initUI();
    
    return true;
}

void AutoUpdateLayer::onEnter()
{
    Layer::onEnter();
    
    needDownload = false;
    
    this->scheduleUpdate();
}

void AutoUpdateLayer::onExit()
{
    
    
    Layer::onExit();
}

void AutoUpdateLayer::update(float dt)
{
    if (needDownload)
    {
        return ;
    }
    
    if (checkUpdate())
    {
        this->unscheduleAllSelectors();
        //切换到下一个页面
//        Director::getInstance()->replaceScene();
    }
    else
    {
        needDownload = true;
        
        auto t = std::thread(&AutoUpdateLayer::downloadAndUncompress, this);
        t.detach();
    }
}

void AutoUpdateLayer::initUI()
{
    
}

bool AutoUpdateLayer::checkUpdate()
{
    //获取本地的资源版本号
    __String * key = __String::createWithFormat("localVersion");
    std::string localVersion = UserDefault::getInstance()->getStringForKey(key->getCString());
    int localVersionValue = __String::createWithFormat("%s",localVersion.c_str())->intValue();
    
    //获取网络上的最新版本号
    FILE * fp = NULL;
    
    fileDicLocalPath = FileUtils::getInstance()->getWritablePath() + "patch.plist" ;
    
    fp = fopen(fileDicLocalPath.c_str(), "wb");
    
    _curl = curl_easy_init();
    
    CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
    
    if (_curl)
    {
        __String * channeId = __String::create(channel_Id);
        __String * url = __String::createWithFormat("http://www.xxxx.com/jx/%s/patch.plist",channeId->getCString());
        
        curl_easy_setopt(_curl, CURLOPT_URL, url->getCString());
        curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, geVersionData);
        curl_easy_setopt(_curl, CURLOPT_TIMEOUT, 30);
        curl_easy_setopt(_curl, CURLOPT_WRITEDATA, fp);
        
        res = curl_easy_perform(_curl);
        
        fclose(fp);
    }
    
    int lastestVersion = getLatestVersion();
    
    if (localVersionValue < lastestVersion)
    {
        CCLOG("有新版本需要下载");
        return false;
    }
    else
    {
        CCLOG("当前为最新版本");
        return  true;
    }
}

size_t AutoUpdateLayer::geVersionData(char *data, size_t size, size_t nmeb, void *stream)
{
    FILE *fp = (FILE*)stream;
	size_t written = fwrite(data, size, nmeb, fp);
    
    return written;
}

int AutoUpdateLayer::getLatestVersion()
{
    int lastestVersion = 0;
    __Dictionary * versionDic = __Dictionary::createWithContentsOfFile(fileDicLocalPath.c_str());
    
    if (versionDic)
    {
        __Array * versionDataArr = (__Array *)versionDic->objectForKey("Default");
        __Dictionary * singleDataDic = (__Dictionary *)versionDataArr->getObjectAtIndex(versionDataArr->count() - 1);
        lastestVersion = ((__String *)singleDataDic->objectForKey("Version"))->intValue();
    }
    
    return lastestVersion;
}

void AutoUpdateLayer::downloadAndUncompress()
{
    if (! downLoad())
    {
        return ;
        
        UserDefault::getInstance()->flush();
    }
   
    // Uncompress zip file.
    if (! uncompress())
    {
        Director::getInstance()->getScheduler()->performFunctionInCocosThread([&, this]{
            if (this->_delegate)
                this->_delegate->onError(ErrorCode::UNCOMPRESS);
        });
        
        return ;
    }
}

bool AutoUpdateLayer::downLoad()
{
    //获取本地的资源版本号
    __String * key = __String::createWithFormat("localVersion");
    std::string localVersion = UserDefault::getInstance()->getStringForKey(key->getCString());
    int localVersionValue = __String::createWithFormat("%s",localVersion.c_str())->intValue();
    
    int downloadVersion = 0;
    __String * downloadDataName = NULL;
    
    __Dictionary * versionDic = __Dictionary::createWithContentsOfFile(fileDicLocalPath.c_str());
    
    if (versionDic)
    {
        __Array * versionDataArr = (__Array *)versionDic->objectForKey("Default");
        __Dictionary * singleDataDic = (__Dictionary *)versionDataArr->getObjectAtIndex(localVersionValue);
        downloadVersion = ((__String *)singleDataDic->objectForKey("Version"))->intValue();
        downloadDataName = (__String *)singleDataDic->objectForKey("FileName");
    }
    
    fileLocalPath = FileUtils::getInstance()->getWritablePath() + downloadDataName->getCString();
    
    FILE *fp = fopen(fileLocalPath.c_str(), "wb");
    if (! fp)
    {
        Director::getInstance()->getScheduler()->performFunctionInCocosThread([&, this]{
            if (this->_delegate)
                this->_delegate->onError(ErrorCode::CREATE_FILE);
        });
        CCLOG("can not create file %s", downloadDataName->getCString());
        return false;
    }
    
    // Download pacakge
    __String * url = __String::createWithFormat("http://www.xxxxxx.com/jx/7/%s",downloadDataName->getCString());
    CURLcode res;
    curl_easy_setopt(_curl, CURLOPT_URL, url->getCString());
    curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, downLoadPackage);
    curl_easy_setopt(_curl, CURLOPT_WRITEDATA, fp);
    curl_easy_setopt(_curl, CURLOPT_NOPROGRESS, false);
    curl_easy_setopt(_curl, CURLOPT_PROGRESSFUNCTION, assetsManagerProgressFunc);
    curl_easy_setopt(_curl, CURLOPT_PROGRESSDATA, this);
    curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1L);
    curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
    curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_TIME, 5L);
    
    res = curl_easy_perform(_curl);
    curl_easy_cleanup(_curl);
    if (res != 0)
    {
        Director::getInstance()->getScheduler()->performFunctionInCocosThread([&, this]{
            if (this->_delegate)
                this->_delegate->onError(ErrorCode::NETWORK);
        });
        CCLOG("error when download package");
        fclose(fp);
        return false;
    }
    
    CCLOG("succeed downloading package %s", url->getCString());
    
    fclose(fp);
    
    //修改本地版本号
    __String * versionStr = __String::createWithFormat("%d",downloadVersion);
    UserDefault::getInstance()->setStringForKey("localVersion", versionStr->getCString());
    
    return true;
}

size_t AutoUpdateLayer::downLoadPackage(void *ptr, size_t size, size_t nmemb, void *userdata)
{
    FILE *fp = (FILE*)userdata;
    size_t written = fwrite(ptr, size, nmemb, fp);
    return written;
    
    
}

int AutoUpdateLayer::assetsManagerProgressFunc(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
    static int percent = 0;
    int tmp = (int)(nowDownloaded / totalToDownload * 100);
    
    if (percent != tmp)
    {
        percent = tmp;
        Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
            auto manager = static_cast<AutoUpdateLayer*>(ptr);
            if (manager->_delegate)
                manager->_delegate->onProgress(percent);
        });
        
        CCLOG("downloading... %d%%", percent);
    }
    
    return 0;
}

bool AutoUpdateLayer::uncompress()
{
    // Open the zip file
    string outFileName = fileLocalPath;
    unzFile zipfile = unzOpen(outFileName.c_str());
    if (! zipfile)
    {
        CCLOG("can not open downloaded zip file %s", outFileName.c_str());
        return false;
    }
    
    // Get info about the zip file
    unz_global_info global_info;
    if (unzGetGlobalInfo(zipfile, &global_info) != UNZ_OK)
    {
        CCLOG("can not read file global info of %s", outFileName.c_str());
        unzClose(zipfile);
        return false;
    }
    
    // Buffer to hold data read from the zip file
    char readBuffer[BUFFER_SIZE];
    
    CCLOG("start uncompressing");
    
    // Loop to extract all files.
    uLong i;
    for (i = 0; i < global_info.number_entry; ++i)
    {
        // Get info about current file.
        unz_file_info fileInfo;
        char fileName[MAX_FILENAME];
        if (unzGetCurrentFileInfo(zipfile,
                                  &fileInfo,
                                  fileName,
                                  MAX_FILENAME,
                                  NULL,
                                  0,
                                  NULL,
                                  0) != UNZ_OK)
        {
            CCLOG("can not read file info");
            unzClose(zipfile);
            return false;
        }
        
        const string storagePath = FileUtils::getInstance()->getWritablePath();
        const string fullPath = storagePath + fileName;
        
        // Check if this entry is a directory or a file.
        const size_t filenameLength = strlen(fileName);
        if (fileName[filenameLength-1] == '/')
        {
            // Entry is a direcotry, so create it.
            // If the directory exists, it will failed scilently.
            if (!createDirectory(fullPath.c_str()))
            {
                CCLOG("can not create directory %s", fullPath.c_str());
                unzClose(zipfile);
                return false;
            }
        }
        else
        {
            //There are not directory entry in some case.
            //So we need to test whether the file directory exists when uncompressing file entry
            //, if does not exist then create directory
            const string fileNameStr(fileName);
            
            size_t startIndex=0;
            
            size_t index=fileNameStr.find("/",startIndex);
            
            while(index != std::string::npos)
            {
                const string dir=storagePath+fileNameStr.substr(0,index);
                
                FILE *out = fopen(dir.c_str(), "r");
                
                if(!out)
                {
                    if (!createDirectory(dir.c_str()))
                    {
                        CCLOG("can not create directory %s", dir.c_str());
                        unzClose(zipfile);
                        return false;
                    }
                    else
                    {
                        CCLOG("create directory %s",dir.c_str());
                    }
                }
                else
                {
                    fclose(out);
                }
                
                startIndex=index+1;
                
                index=fileNameStr.find("/",startIndex);
                
            }
            
            
            
            // Entry is a file, so extract it.
            
            // Open current file.
            if (unzOpenCurrentFile(zipfile) != UNZ_OK)
            {
                CCLOG("can not open file %s", fileName);
                unzClose(zipfile);
                return false;
            }
            
            // Create a file to store current file.
            FILE *out = fopen(fullPath.c_str(), "wb");
            if (! out)
            {
                CCLOG("can not open destination file %s", fullPath.c_str());
                unzCloseCurrentFile(zipfile);
                unzClose(zipfile);
                return false;
            }
            
            // Write current file content to destinate file.
            int error = UNZ_OK;
            do
            {
                error = unzReadCurrentFile(zipfile, readBuffer, BUFFER_SIZE);
                if (error < 0)
                {
                    CCLOG("can not read zip file %s, error code is %d", fileName, error);
                    unzCloseCurrentFile(zipfile);
                    unzClose(zipfile);
                    return false;
                }
                
                if (error > 0)
                {
                    fwrite(readBuffer, error, 1, out);
                }
            } while(error > 0);
            
            fclose(out);
        }
        
        unzCloseCurrentFile(zipfile);
        
        // Goto next entry listed in the zip file.
        if ((i+1) < global_info.number_entry)
        {
            if (unzGoToNextFile(zipfile) != UNZ_OK)
            {
                CCLOG("can not read next file");
                unzClose(zipfile);
                return false;
            }
        }
    }
    
    CCLOG("end uncompressing");
    unzClose(zipfile);
    
    needDownload = false;
    
    return true;
}

bool AutoUpdateLayer::createDirectory(const char *path)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
    mode_t processMask = umask(0);
    int ret = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
    umask(processMask);
    if (ret != 0 && (errno != EEXIST))
    {
        return false;
    }
    
    return true;
#else
    BOOL ret = CreateDirectoryA(path, NULL);
	if (!ret && ERROR_ALREADY_EXISTS != GetLastError())
	{
		return false;
	}
    return true;
#endif
}

下载链接:

http://download.csdn.net/detail/linyang24/9193475


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lin&Yi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值