【原创】我所理解的自动更新-客户端更新流程

创建更新线程,跟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发布与后台发布
【原创】我所理解的自动更新-资源打包流程
【原创】我所理解的自动更新-客户端更新流程
【原创】我所理解的自动更新-知识点讲解

posted @ 2015-03-30 19:12  ldr123  阅读(1607)  评论(0编辑  收藏  举报