.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