cocos2d-js 3.10 AssetsManager 热更问题以及解决方案

公司开发的项目用到热更AssetsManager。其中遇到几个问题,这里与大家分享一下。
1.多个文件需要更新,没有全部更新成功。然而更新成功的文件使用了。导致异常。
解决方案:

(1)首先需要使用热更临时目录,全部热更成功再把文件移动到热更目录。

_storagePath = (jsb.fileUtils ? jsb.fileUtils.getWritablePath()+"/update": "./update");
_storageTempPath = (jsb.fileUtils ? jsb.fileUtils.getWritablePath()+"/temp" : "./temp");

(2)手动添加searchpaths,注释掉AssetsManager的添加searchpath代码。

void AssetsManager::setSearchPath()
{
    //vector<string> searchPaths = FileUtils::getInstance()->getSearchPaths();
    //vector<string>::iterator iter = searchPaths.begin();
    //searchPaths.insert(iter, _storagePath);
    //FileUtils::getInstance()->setSearchPaths(searchPaths);
}
var searchPaths = jsb.fileUtils.getSearchPaths();
searchPaths.unshift(_storagePath);

(3)在android/ios增加创建文件,复制文件,删除文件的接口。

主要注意ios的文件创建,以及热更前需要清空临时文件夹。不然会导致异常。

android:

//删除文件夹和文件夹里面的文件
    public static void deleteDir(final String pPath) {
        File dir = new File(pPath);
        deleteDirWihtFile(dir);
    }

    public static void deleteDirWihtFile(File dir) {
        if (dir == null || !dir.exists() || !dir.isDirectory())
            return;
        for (File file : dir.listFiles()) {
            if (file.isFile())
                file.delete(); // 删除所有文件
            else if (file.isDirectory())
                deleteDirWihtFile(file); // 递规的方式删除文件夹
        }
        dir.delete();// 删除目录本身
    }


    public static void createDir(String path) {
        (new File(path)).mkdirs(); //如果文件夹不存在 则建立新文件夹
    }
    /**
     * 复制单个文件
     * @param oldPath String 原文件路径 如:c:/fqf.txt
     * @param newPath String 复制后路径 如:f:/fqf.txt
     * @return boolean
     */
    public static void copyFile(String oldPath, String newPath) {
        try {
            int bytesum = 0;
            int byteread = 0;
            File oldfile = new File(oldPath);
            if (oldfile.exists()) { //文件存在时
                InputStream inStream = new FileInputStream(oldPath); //读入原文件
                FileOutputStream fs = new FileOutputStream(newPath);
                byte[] buffer = new byte[1024];
                int length;
                while ( (byteread = inStream.read(buffer)) != -1) {
                    bytesum += byteread; //字节数 文件大小
                    System.out.println(bytesum);
                    fs.write(buffer, 0, byteread);
                }
                inStream.close();
            }
        }
        catch (Exception e) {
            System.out.println("复制单个文件操作出错");
            e.printStackTrace();

        }

    }
ios:

//复制
+ (void)copyFile:(NSString*) oldPath newPath:(NSString*) newPath
{
    NSFileManager *fileManger = [NSFileManager defaultManager];
    BOOL isDir;
    if ([fileManger fileExistsAtPath:oldPath isDirectory:&isDir] && isDir) {
        NSArray *pathArray = [fileManger contentsOfDirectoryAtPath:oldPath error:nil];
        for (NSString *path in pathArray) {
            NSLog(@"copy old path is %@",path);
            NSString *dOldpath = [NSString stringWithFormat:@"%@/%@",oldPath,path];
            NSString *dNewpath = [NSString stringWithFormat:@"%@/%@",newPath,path];
            [AppController copyFile:dOldpath newPath:dNewpath];
        }
    }else{
        BOOL isCopy = [fileManger copyItemAtPath:oldPath toPath:newPath error:nil];
        NSLog(@"path is copy %@%d",oldPath,isCopy);
    }
}
//删除
+ (void)deleteDir:(NSString*)path
{
    NSFileManager *fileManger = [NSFileManager defaultManager];
    BOOL isDelete = [fileManger removeItemAtPath:path error:nil];
    NSLog(@"%d",isDelete);
}
//创建
+(void)createDir:(NSString*)path{
    NSFileManager *fileManger = [NSFileManager defaultManager];
    if (![fileManger fileExistsAtPath:path]) {
        NSLog(@"file not find %@",path);
        [fileManger createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
    }
}

2.ios设备下载文件错误导致的崩溃问题。

解决方案:修改CCDownloader-apple.mm下的

- (void)URLSession:(NSURLSession *)session task :(NSURLSessionTask *)task
                            didCompleteWithError:(NSError *)error
{
    DLLOG("DownloaderAppleImpl task: \"%s\" didCompleteWithError: %d errDesc: %s"
          , [task.originalRequest.URL.absoluteString cStringUsingEncoding:NSUTF8StringEncoding]
          , (error ? (int)error.code: 0)
          , [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding]);

    // clean wrapper C++ object
    DownloadTaskWrapper *wrapper = [self.taskDict objectForKey:task];
    
    if(_outer)
    {
        if(error)
        {
            std::vector<unsigned char> buf; // just a placeholder
            _outer->onTaskFinish(*[wrapper get],
                             cocos2d::network::DownloadTask::ERROR_IMPL_INTERNAL,
                             (int)error.code,
                             [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding],
                             buf);
        }
        else if (![wrapper get]->storagePath.length())
        {
            // call onTaskFinish for a data task
            // (for a file download task, callback is called in didFinishDownloadingToURL)
            std::string errorString;

            const int64_t buflen = [wrapper totalBytesReceived];
            char buf[buflen];
            [wrapper transferDataToBuffer:buf lengthOfBuffer:buflen];
            std::vector<unsigned char> data(buf, buf + buflen);
            
            _outer->onTaskFinish(*[wrapper get],
                                 cocos2d::network::DownloadTask::ERROR_NO_ERROR,
                                 0,
                                 errorString,
                                 data);
        }
        else
        {
            NSInteger statusCode = ((NSHTTPURLResponse*)task.response).statusCode;
            
            // Check for error status code
            if (statusCode >= 400)
            {
                std::vector<unsigned char> buf; // just a placeholder
                const char *orignalURL = [task.originalRequest.URL.absoluteString cStringUsingEncoding:NSUTF8StringEncoding];
                std::string errorMessage = cocos2d::StringUtils::format("Downloader: Failed to download %s with status code (%d)", orignalURL, (int)statusCode);
                
                _outer->onTaskFinish(*[wrapper get],
                                     cocos2d::network::DownloadTask::ERROR_IMPL_INTERNAL,
                                     0,
                                     errorMessage,
                                     buf);
                
                while (!_taskQueue.empty() && _taskQueue.front()) {
                    if (_taskQueue.front() != nil) {
                        [_taskQueue.front() cancel];
                    }
                    _taskQueue.pop();
                }
            }
        }
    }
    [self.taskDict removeObjectForKey:task];
    [wrapper release];

    while (!_taskQueue.empty() && _taskQueue.front() == nil) {
        _taskQueue.pop();
    }
    if (!_taskQueue.empty()) {
        
        [_taskQueue.front() resume];
        _taskQueue.pop();
    }
}
 这个问题是 AssetsManager对象已经被失败的线程释放了,后面的线程再使用了AssetsManager导致的。所以一个线程遇到失败要把其他线程取消掉。








猜你喜欢

转载自blog.csdn.net/yyyangyy/article/details/79099467
今日推荐