实现效果如下
iPhone截图
android 日志截图
流程图如下
功能主要通过CURL c pthread 实现 我实现的不是多线程断点(如果要实现可以根据我这个进行添加任务序列,可参考 cocos2d-x 中AssetsManager的实现,其实我的部分也是参考这个写的 为什么写这个呢 原因就是 AssetsManager是不支持断点续传的)
博客地址:http://blog.csdn.net/vpingchangxin/article/details/22309067
具体可以去CURL官网或者找资料科普一下
PS:如果是版本发布最后设置超时时间20秒左右否则下载会占用更多下载实现效率等问题 我是为了测试 设置超时时间为2秒
1.先创建一个界面进行控制进行下载、停止、删除、进度 并绑定事件
2.在进行下载中开一个线程进行下载 (因为牵涉到UI,不开线程UI会卡着堵塞UI线程直到下载完成)下面是事件中的控制 HelloWorldSecene.cpp中的实现
- void HelloWorld::menuCallback(CCObject* pSender) {
- CCMenuItem *item = (CCMenuItem *)pSender;
- switch (item->getTag()) {
- case 1: // down start
- CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(HelloWorld::updateUI), this, 0, false); // HttpClient中参考
- isStop = false;
- this->threadStart();
- break;
- case 2: // down stop
- isStop = true;
- break;
- case 3:
- if (isStop) {
- CCLog(“downFilePath:%s”,downFilePath.c_str());
- if (access(downFilePath.c_str(), 0) == 0) {
- remove(downFilePath.c_str());
- CCMessageBox(“删除成功”, ”温馨提示”);
- }else{
- CCMessageBox(“没有找到文件目录”, ”温馨提示”);
- }
- }else{
- CCMessageBox(“下载中或没有文件下载”, ”温馨提示”);
- }
- break;
- default:
- break;
- }
- }
3。实现线程类并回调设置
- // 启动线程的方法
- int HelloWorld::threadStart() {
- pthread_mutex_init(&g_downloadMutex, NULL);
- int errCode=0;
- pthread_t th_curlDown; // 线程初始化
- do {
- pthread_attr_t tAttr;
- errCode=pthread_attr_init(&tAttr);
- CC_BREAK_IF(errCode!=0);
- errCode=pthread_attr_setdetachstate(&tAttr, PTHREAD_CREATE_DETACHED);
- if(errCode!=0) {
- pthread_attr_destroy(&tAttr);
- break;
- }
- errCode=pthread_create(&th_curlDown, &tAttr, thread_funcation, this);
- } while (0);
- return errCode;
- }
- // 需要线程来完成的功能都写在这个函数里
- void* HelloWorld::thread_funcation(void *arg) {
- CCLOG(“thread started…”);
- HelloWorld *hw = (HelloWorld*)arg;
- hw->ccc = new CurlDown(“http://developer.baidu.com/map/static/doc/output/BaiduMap_AndroidSDK_v2.4.0_All.zip”,hw->downFilePath);
- // ccc->mDownloadUrl = ”http://developer.baidu.com/map/static/doc/output/BaiduMap_AndroidSDK_v2.4.0_All.zip”;
- // int leng = ccc->getDownloadFileLenth();
- hw->ccc->setDelegate(hw);
- hw->ccc->downloadControler();
- return NULL;
- }
4.实现回调进度、成功、错误(里面用到线程锁对数据进度更新UI,本来对线程就不熟悉,问了群里面的大牛,看了不少资料)
- void HelloWorld::onError(CurlDown::ErrorCode errorCode){
- CCLog(“error”);
- pthread_mutex_lock(&g_downloadMutex);
- updateStr = ”error”;
- pthread_mutex_unlock(&g_downloadMutex);
- CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(HelloWorld::updateUI), this);
- }
- void HelloWorld::onProgress(double percent, void *delegate, string filefullPath){ // 下载进度
- CCLog(“donw progress:%.2f%%”,percent);
- if (isStop) {
- CurlDown * cd = (CurlDown *)delegate;
- // pthread_mutex_lock(&g_downloadMutex);
- cd->setStopDown();
- // pthread_mutex_unlock(&g_downloadMutex);
- }
- pthread_mutex_lock(&g_downloadMutex);
- const char * per =CCString::createWithFormat(“donw progress:%.2f%%”,percent)->getCString();
- updateStr = per;
- downFilePath = filefullPath;
- pthread_mutex_unlock(&g_downloadMutex);
- }
- void HelloWorld::onSuccess(string filefullPath){
- CCLog(“success”);
- pthread_mutex_lock(&g_downloadMutex);
- updateStr = ”success”;
- downFilePath = filefullPath;
- pthread_mutex_unlock(&g_downloadMutex);
- }
5.CurlDown.h CurlDown.cpp类实现 (可以直接抽取出来用于任何地方,没有牵涉到cocos2d-x部分,cocos2d-x 部分可以删除没关系)
1)对类初始化
- static pthread_mutex_t g_downloadMutex_1;
- CurlDown::~CurlDown(){
- mFileLenth = 0;
- }
- CurlDown::CurlDown():isStop(false),mDownloadUrl(“”),timeout(2){ // test timeout 2 seconds. if release timeout 20 seconds
- mFileLenth = 0;
- mFilePath = ”";
- pthread_mutex_init(&g_downloadMutex_1, NULL);
- }
- CurlDown::CurlDown(string downUrl,string filePath):mFileLenth(0),isStop(false),mDownloadUrl(downUrl),timeout(2),mFilePath(filePath){ // test timeout 2 seconds. if release timeout 20 seconds
- mDownloadUrl = downUrl;
- pthread_mutex_init(&g_downloadMutex_1, NULL);
- }
- void CurlDown::setDelegate(CurlDownDelegate * delegate) {
- mDelegate = delegate;
- }
2)控制下载方法
- void CurlDown::downloadControler() {
- CCLog(“–1-”);
- mFileLenth = getDownloadFileLenth(); // 获取远程文件大小
- if (mFileLenth <= 0) {
- cout << ”download file fail…” << endl;
- mDelegate->onError(kNetwork);
- return;
- }
- vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths();
- vector<string>::iterator iter = searchPaths.begin();
- searchPaths.insert(iter, mFilePath);
- CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
- CCLog(“–2-mFileLenth:%f”,mFileLenth);
- mFileName = mDownloadUrl.substr(mDownloadUrl.rfind(‘/’) + 1);
- CCLog(“–3-”);
- CCLog(“mFileName:%s;”,mFileName.c_str());
- // mFilePath = CCFileUtils::sharedFileUtils()->getWritablePath();
- // CCLog(“–5-”);
- mFilePath = mFilePath + mFileName;
- CCLog(“mFilePath:%s”,mFilePath.c_str());
- CCLog(“–6-”);
- bool ret = false;
- while (true){ // 循环下载 每30秒进行下载 避免断网情况
- ret = download(); //直接下载 进行堵塞线程
- CCLog(“—-stop—%s——”,isStop?”true”:”false”);
- if (isStop) { // 如果进行停止 break
- CCLog(“—-stop———”);
- break;
- }
- if (ret ){ //下载完成
- break;
- }
- sleep(0.5); //每次下载中间间隔0.5秒
- }
- if (ret) {
- CCLog(“download ok”);
- mDelegate->onSuccess(mFilePath);
- } else {
- CCLog(“download fail”);
- mDelegate->onError(kUncompress);
- }
- }
3)核心下载
- #pragma mark 进行下载
- bool CurlDown::download() {
- FILE *fp = NULL;
- if(access(mFilePath.c_str(), 0)==0) { // 以二进制形式追加
- fp = fopen(mFilePath.c_str(), ”ab+”);
- } else { // 二进制写
- fp = fopen(mFilePath.c_str(), ”wb”);
- }
- if (fp == NULL) {// 如果文件初始化失败进行返回
- return false;
- }
- // 读取本地文件下载大小
- long localFileLenth = getLocalFileLength(); //已经下载的大小
- CCLog(“filePath:%s;leng:%ld”,mFilePath.c_str() , localFileLenth ); //4397779 //3377875
- CURL *handle = curl_easy_init();
- std::string packageUrl = mDownloadUrl; //下载地址+下载文件名
- curl_easy_setopt(handle, CURLOPT_URL, packageUrl.c_str()); // http://curl.haxx.se/libcurl/c/fopen.html
- curl_easy_setopt(handle, CURLOPT_TIMEOUT, timeout);
- curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_write_func); //写文件回调方法
- curl_easy_setopt(handle, CURLOPT_WRITEDATA, fp); // 写入文件对象
- curl_easy_setopt(handle, CURLOPT_RESUME_FROM, localFileLenth); // 从本地大小位置进行请求数据
- // curl_easy_setopt(handle, CURLOPT_RESUME_FROM_LARGE, localFileLenth); // 坑
- curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
- curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, my_progress_func ); //下载进度回调方法
- curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, this); // 传入本类对象
- CURLcode res = curl_easy_perform(handle);
- fclose(fp);
- return res == CURLE_OK;
- }
下面大家要问道的就是求源码(^..^)源码已经上传github https://github.com/pingchangxin/BPDownload cesd 下载位置:http://download.csdn.net/detail/vpingchangxin/7108649
我这边就再mac上门跑了下 windows的没有进行跑(对win的配置繁琐的头疼了了)