创建更新线程,跟ui主线程通过message进行交互。
1,去http://version.mygame.com/check.php? channelid=%d&appver=%d&resver=%d获取客户端最新版本信息。用curl获取,代码如下,至于curl的具体参数,man或者搜索引擎会告诉你答案
1 static size_t funcGetHttpText(void *ptr, size_t size, size_t nmemb, void *userdata) { 2 size_t retSize = size*nmemb; 3 string* pContent = (string*)userdata; 4 if (pContent) { 5 pContent->append((char*)ptr, retSize); 6 } return retSize; 7 } 8 CURLcode getHttpText(const string& strUrl, string& strHttpText) { 9 CURL* pCurl = curl_easy_init(); 10 if (!pCurl) { 11 return CURL_LAST; 12 } 13 strHttpText.clear(); 14 curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 30); 15 curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 1); 16 curl_easy_setopt(pCurl, CURLOPT_FORBID_REUSE, 1); 17 curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); 18 curl_easy_setopt(pCurl, CURLOPT_URL, strUrl.c_str()); 19 curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, funcGetHttpText); 20 curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &strHttpText); 21 CURLcode err = curl_easy_perform(pCurl); 22 if (err == CURLE_OK) { 23 int sz = 0; 24 curl_easy_getinfo(pCurl, CURLINFO_HTTP_CODE, &sz); 25 if ((sz != 200) && (sz != 206)) { 26 //ok or not modify 27 err = CURL_LAST; 28 } 29 } 30 curl_easy_cleanup(pCurl); 31 return err; 32 }
解析返回的字符串。
1:大版本更新,弹出对话框,提示需要进行大版本更新,用户可以选择”更新”,”取消”。取消后就退出app,点击更新,进入下面流程。
Android:通过返回的url下载相应的apk,并进行重装(重装只针对app,不会重置资源),
Ios: AdHoc,通过代码打开url的方式进行更新。代码如下
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms-services://?action=download-manifest&url==https://raw.githubusercontent.com/xxxxxhttp.plist"]];
AppStore:则打开AppStore的app进行更新,代码如下
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@" http://itunes.apple.com/gb/app/yin/idxxxxxxxx?mt=8 "]];
此时会跳出当前应用,跳转到appstore的应用详情页。
2:本地资源版本号为0,下载初始包。3:本地资源版本>0,则下载差异包
判断本地已下载的临时文件大小和外网文件的大小是否相同,如果不相同,则断点下载外网文件。Curl支持断点下载,代码如下
1 char rangBuf[32] = { 0 }; 2 sprintf(rangBuf, "%d-", nRangeFrom); 3 curl_easy_setopt(pCurl, CURLOPT_RANGE, rangBuf);
另外,下载需要判断3g环境的问题,如果在3g环境下,下载的文件超过一定大小(比如30M),则提示玩家是否下载,玩家自行选择是否下载。因为我们下载模块是多线程的,主线程和多线程通过mutex进行通信。
下载线程:
1 while (1) { 2 this_thread::sleep_for(chrono::milliseconds(50)); 3 std::unique_lock<std::mutex> locker(m_mtxConfirm); 4 if (m_eUpdateConfirm == UpdateImplConfirm::UPDATE_UNKNOW) { 5 this_thread::yield(); 6 } else { 7 break; 8 } 9 } 10 if (m_eUpdateConfirm == UpdateImplConfirm::UPDATE_REJECT) { //拒绝更新 11 postMessage(new UserRejectMessage(UpdateState::eUpdateStateDownloadFile)); 12 m_eUpdateConfirm = UpdateImplConfirm::UPDATE_UNKNOW; 13 return CURL_LAST; 14 }
UI:
1 void ConfirmContinue() { 2 std::lock_guard<std::mutex> autoLock(m_mtxConfirm); 3 m_eUpdateConfirm = UpdateImplConfirm::UPDATE_CONTINUE; 4 } 5 void ConfirmReject() { 6 std::lock_guard<std::mutex> autoLock(m_mtxConfirm); 7 m_eUpdateConfirm = UpdateImplConfirm::UPDATE_REJECT; 8 }
下载完成后,文件大小和md5进行比较,如果不同。。。则删除文件,重新下载。
比较成功后,解压文件到writable目录,读取index文件进行数据解析,将追加的文件,覆盖的文件拷贝到资源目录进行覆盖,删除文件的,则把资源目录的相应文件进行删除。检查资源,遍历本地资源文件进行md5对比,如果不相同,则去外网下载散文件进行覆盖。清理临时目录,删除index文件。资源更新完成。
4. 资源版本大于0,并且跟服务器资源版本匹配,无需更新。
Other,出错【服务器timeout,返回错误,==】,显示“重试”按钮可重试。
【原创】我所理解的自动更新-概要
【原创】我所理解的自动更新-环境搭建和协议制定
【原创】我所理解的自动更新-外网web服务器配置
【原创】我所理解的自动更新-APP发布与后台发布
【原创】我所理解的自动更新-资源打包流程
【原创】我所理解的自动更新-客户端更新流程
【原创】我所理解的自动更新-知识点讲解
本文中的服务器用的是linode,linode是啥就不需要过多介绍了吧。
有兴趣的童鞋可以通过https://www.linode.com/?r=000161937771838e320f2bda5fef0dbad54ad86c注册服务器,
r后面的数字是我的推荐码,如果你用了以上我推荐的推荐码,并且保持3个月是在线帐号,那么我将在三个月后得到20美元的信用,
这样也就是可以多用一个月最低档19.95美元的linode vps。
Referrals reward you when you refer people to Linode.
If someone signs up using your referral code,
you‘ll receive a credit of $20.00, so long as the person you referred remains an active customer for 90 days。