huangxiaodong 1 год назад
Родитель
Сommit
71275242b9

+ 24 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/NSURLSession+mixDownloadTask.h

@@ -0,0 +1,24 @@
+//
+//  NSURLSession+mixDownloadTask.h
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface NSURLSession (mixDownloadTask)
+/**
+ 构造一个从特定位置开始下载的任务
+
+ @param urlString 资源路径的URLstring
+ @param startSize 开始的位置
+ @return 下载任务
+ */
+- (NSURLSessionDataTask *)mix_downloadDataTaskWithURLString:(NSString *)urlString
+                                                  startSize:(int64_t)startSize;
+@end
+
+NS_ASSUME_NONNULL_END

+ 41 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/NSURLSession+mixDownloadTask.m

@@ -0,0 +1,41 @@
+//
+//  NSURLSession+mixDownloadTask.m
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import "NSURLSession+mixDownloadTask.h"
+
+@implementation NSURLSession (mixDownloadTask)
+- (NSURLSessionDataTask *)mix_downloadDataTaskWithURLString:(NSString *)urlString
+                                                  startSize:(int64_t)startSize {
+    // 校验URL
+    if (urlString.length == 0) {
+        return nil;
+    }
+    NSURL *url = [NSURL URLWithString:urlString];
+    if (url == nil) {
+        return nil;
+    }
+    
+    // 创建请求 设置请求下载的位置
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
+    //NSString *tokenStr = [[UseAccountManage shareInstance] cloudAutoh];
+    //[request setValue:tokenStr forHTTPHeaderField:@"Authorization"];
+    request.HTTPMethod = @"GET";
+    
+    /*
+     bytes=0-100    请求0-100
+     bytes=200-1000
+     bytes=200-     从200开始直到结尾
+     bytes=-100
+     */
+    NSString *rangeStr = [NSString stringWithFormat:@"bytes=%lld-",startSize];
+    
+    [request setValue:rangeStr forHTTPHeaderField:@"Range"];
+    
+    // 创建task
+    return [self dataTaskWithRequest:request];
+}
+@end

+ 36 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadCacheManager.h

@@ -0,0 +1,36 @@
+//
+//  mixDownloadCacheManager.h
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+#define KFullPath NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]
+#define KFullDirector  [self getFullDirector]
+#define KMixDownloadDirector  @"mixDownload"
+
+@interface mixDownloadCacheManager : NSObject
+
+/** 查询文件信息 */
++ (NSMutableDictionary *)queryFileInfoWithUrl:(NSString *)url;
+
+/** 查询要下载的文件大小 */
++ (NSInteger)totalSizeWith:(NSString *)url;
+
+/**  增加配置信息 */
++ (BOOL)saveFileInfoWithDict:(NSDictionary *)dict;
+
+
++ (NSString *)getFullDirector;
+
++ (NSString *)getNewPlistPath;
+
++ (NSMutableDictionary *)getDownloadList;
+@end
+
+NS_ASSUME_NONNULL_END

+ 121 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadCacheManager.m

@@ -0,0 +1,121 @@
+//
+//  mixDownloadCacheManager.m
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import "mixDownloadCacheManager.h"
+#import "mixDownloadManager.h"
+
+static NSMutableDictionary *_downloadList;
+
+static dispatch_semaphore_t _semaphore;
+
+@implementation mixDownloadCacheManager
+
++ (void)initialize {
+    _semaphore = dispatch_semaphore_create(1);
+}
+
+#pragma mark-plist
++ (NSString *)getNewPlistPath {
+    
+    NSString *account = KMixDownloadUID;
+    if (account.length != 0) {
+        NSString *fileFolder = [HWDataManager documentPathForAccount:account fileFolder:KMixDownloadDirector];
+        HLog(@"下载账号:%@", fileFolder);
+        return [fileFolder stringByAppendingPathComponent:@"downloadInfo.plist"];;
+    }else {
+        HLog(@" 创建下载plist文件失败!");
+        return @"";
+    }
+}
+
++ (NSMutableDictionary *)getDownloadList {
+    
+    if (!_downloadList) { // 内存没有
+        _downloadList = [[NSDictionary dictionaryWithContentsOfFile:[self getNewPlistPath]] mutableCopy]; // 本地加载
+        if (!_downloadList) { // 本地没有,分配内存
+            _downloadList = [NSMutableDictionary dictionary];
+        }
+    }
+    return _downloadList;
+}
+
++ (NSString *)getFullDirector {
+
+    NSString *account = KMixDownloadUID;
+    if (account.length != 0)
+    {
+         NSString *fileFolder = [HWDataManager documentPathForAccount:account fileFolder:KMixDownloadDirector];
+         return fileFolder;
+     }else {
+         HLog(@"创建下载plist文件失败!");
+         return @"";
+     }
+}
+
+/** 查询文件信息 */
++ (NSMutableDictionary *)queryFileInfoWithUrl:(NSString *)url
+{
+    // 本地查找
+    NSString *key = [[url lastPathComponent] stringByDeletingPathExtension];
+    NSMutableDictionary *dictM  = [[[self getDownloadList] objectForKey:key] mutableCopy];
+    
+    if (dictM) {
+        NSString *path = [KFullDirector stringByAppendingString:dictM[@"fileName"]];
+        [dictM setObject:path forKey:@"filePath"];
+        HLog(@"路径:%@", path);
+    }
+    
+    return dictM;
+}
+
++ (NSInteger)totalSizeWith:(NSString *)url {
+    //NSNumber *size = [self queryFileInfoWithUrl:url][totalSize];
+    
+    return [[self queryFileInfoWithUrl:url][@"totalSize"] integerValue];
+}
+
+
+/**  增加配置信息 */
++ (BOOL)saveFileInfoWithDict:(NSDictionary *)dict {
+    
+    // 多账号下载 判断是否需要缓存记录
+    HLog(@"增加配置信息:%@", dict);
+    if ([[dict allKeys] containsObject:@"fullPath"]) {
+        NSArray *fileArray = [[dict objectForKey:@"fullPath"] pathComponents];
+        NSString *filePathAccount = @"0";
+        if (fileArray.count > 3) {
+            filePathAccount = fileArray[fileArray.count - 3];
+        }
+
+        NSString *account = KMixDownloadUID;
+        if (account.length == 0) {
+        }
+
+        if (![filePathAccount isEqualToString:account]) {
+            HLog(@"切换账号 文件缓存账号%@ 与 当前登录账号:%@ 不一致", filePathAccount, account);
+            return NO;
+        }
+    }
+    
+    
+    // 线程等待 (信号量 + 1)
+    dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
+    
+    NSString *key = [[dict[@"url"] lastPathComponent] stringByDeletingPathExtension];
+    NSMutableDictionary *dictM =  [self getDownloadList];
+    [dictM setObject:dict forKey:key];
+    BOOL flag = [dictM writeToFile:[self getNewPlistPath] atomically:YES];
+    
+    // 线程结束 (信号量 - 1)
+    dispatch_semaphore_signal(_semaphore);
+    
+    return flag;
+    
+}
+
+
+@end

+ 44 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadManager.h

@@ -0,0 +1,44 @@
+//
+//  mixDownloadManager.h
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import <Foundation/Foundation.h>
+#import "mixDownloadOperation.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+#define KMixDownloadUID  [mixDownloadManager shareManager].uid
+
+/**
+ block 回调
+ */
+typedef void(^MixDownloadBeginBlock)(NSString * filePath);
+typedef void(^MixDownloadProgressBlock)(NSInteger completeSize,NSInteger expectSize);
+typedef void(^MixDownloadCompleteBlock)(NSDictionary *respose,NSError *error);
+
+
+
+@interface mixDownloadManager : NSObject
+
+@property(nonatomic,strong) NSString *uid;//用户id 用来创建文件夹路径 防止不要用户的缓存关联
+
+/** 实例化对象(单例) */
++ (instancetype)shareManager;
+
+/** 获取全部下载任务 */
+- (NSMutableArray *)getAllOperation;
+
+#pragma mark - 添加下载任务同时开启任务下载
+/** 开启下载任务 监听完成下载 */
+- (void)downloadWithURL:(NSURL *)url
+               complete:(MixDownloadCompleteBlock)complete;
+
+/** 开启当前列队中所有被暂停的下载任务 */
+- (void)startAllDownloadTask;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 100 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadManager.m

@@ -0,0 +1,100 @@
+//
+//  mixDownloadManager.m
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import "mixDownloadManager.h"
+#import "mixDownloadCacheManager.h"
+#import "mixDownloadSession.h"
+
+@interface mixDownloadManager ()
+@property(nonatomic,strong) mixDownloadSession *downloadSession;
+@end
+
+@implementation mixDownloadManager
+
++ (instancetype)shareManager {
+    static mixDownloadManager *_instance;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        _instance = [[self alloc] init];
+    });
+    return _instance;
+}
+
+- (NSString*)uid{
+    if(!_uid || _uid.length == 0){
+        return @"mixDownload";
+    }
+    
+    return _uid;
+}
+
+- (NSMutableArray *)getAllOperation {
+    NSMutableDictionary *allOperationDict = [mixDownloadCacheManager getDownloadList];
+//    HLog(@"%@---%@", allOperation,allOperation.allKeys);
+    NSMutableArray *allOperationArray = [NSMutableArray array];
+    for (NSDictionary *dict in allOperationDict.allValues) {
+        mixDownloadOperation *operation = [mixDownloadOperation mj_objectWithKeyValues:dict];
+        [allOperationArray addObject:operation];
+    }
+    return allOperationArray;
+}
+
+#pragma mark - 外界交互
+- (void)downloadWithURL:(NSURL *)url complete:(void(^)(NSDictionary *,NSError *))complete{
+    [self downloadWithURL:url begin:nil progress:nil complete:complete];
+}
+
+- (void)downloadWithURL:(NSURL *)url begin:(void(^)(NSString *))begin progress:(void(^)(NSInteger,NSInteger))progress complete:(void(^)(NSDictionary *,NSError *))complete {
+    
+    if (![url isKindOfClass:NSURL.class]) {
+        if ([url isKindOfClass:NSString.class]) {
+            url = [NSURL URLWithString:(NSString *)url];
+        }else {
+            // 失败回调
+            complete(nil,nil);
+            return;
+        }
+    }
+    // 开启异步 操作
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        // 本地查找
+        NSDictionary *fileInfo = [mixDownloadCacheManager queryFileInfoWithUrl:url.absoluteString];
+        
+        // 本地存在直接返回
+        if (fileInfo && [fileInfo[@"currentSize"] integerValue] == [fileInfo[@"totalSize"] integerValue]
+            && [fileInfo[@"totalSize"] integerValue] != 0) {
+            
+            dispatch_async(dispatch_get_main_queue(), ^{
+                !complete ? : complete(fileInfo,nil);
+            });
+            return;
+        }
+        
+      
+        // 交给downloader下载
+        [self.downloadSession downloadWithURL:url begin:begin progress:progress complete:complete];
+    });
+    
+}
+
+
+/** 开启当前列队中所有被暂停的下载任务 */
+- (void)startAllDownloadTask {
+    [self.downloadSession startAllDownloads];
+}
+
+#pragma mark - lazy load
+- (mixDownloadSession *)downloadSession {
+    if (!_downloadSession) {
+        _downloadSession = [[mixDownloadSession alloc] init];
+        
+    }
+    return _downloadSession;
+}
+
+
+@end

+ 64 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadOperation.h

@@ -0,0 +1,64 @@
+//
+//  mixDownloadOperation.h
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import <Foundation/Foundation.h>
+#import "mixDownloadCacheManager.h"
+
+/** 下载状态*/
+typedef  enum : NSUInteger {
+    DownloadStateWaiting = 0,   /** 下载等待中 */
+    DownloadStateDoing,         /** 下载中 */
+    DownloadStateSuspended,     /** 下载暂停 */
+    DownloadStateCompleted,     /** 下载完成 */
+    DownloadStateFailed,        /** 下载失败 */
+} MixDownloadStateType;
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface mixDownloadOperation : NSObject
+
+/** 绑定的标示及task的创建 */
+@property (readonly,nonatomic, copy)NSString *url;
+
+/** 下载任务 */
+@property (nonatomic,strong)NSURLSessionDataTask *dataTask;
+
+/** 文件句柄 可以记录文件的下载的位置 */
+@property (nonatomic,strong) NSFileHandle *handle;
+
+/** 下载的文件总大小 */
+@property (nonatomic,assign) int64_t totalSize;
+
+/** 当前下载了多少 */
+@property (nonatomic,assign) int64_t currentSize;
+
+/** 当前下载文件名称 */
+@property (nonatomic,copy) NSString *fileName;
+
+/** 当前下载文件沙盒全路径 */
+@property (nonatomic,copy) NSString *fullPath;
+
+/** 文件下载状态 */
+@property (nonatomic,assign) MixDownloadStateType downloadState;
+
+/** 下载完成-时间戳 */
+@property (nonatomic,assign)  NSInteger timeStamp;
+
+/** 文件类型 */
+@property (nonatomic,assign)  NSInteger fileType;
+
+/** 是否完成 */
+@property (nonatomic, assign)  NSInteger isFinished;
+
+// 创建下载操作任务
+- (instancetype)initWith:(NSString *)url session:(NSURLSession *)session;
+
+- (NSDictionary *)downLoadInfoWithFinished:(BOOL)finished;
+@end
+
+NS_ASSUME_NONNULL_END

+ 77 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadOperation.m

@@ -0,0 +1,77 @@
+//
+//  mixDownloadOperation.m
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import "mixDownloadOperation.h"
+#import "mixDownloadManager.h"
+#import "NSURLSession+mixDownloadTask.h"
+
+@implementation mixDownloadOperation
+- (instancetype)initWith:(NSString *)url session:(NSURLSession *)session {
+    
+    if (self = [super init]) {
+        _url = url;
+        // 初始化下载信息
+        _currentSize = [self getFileSizeWithURL:url];
+        
+        // 偏好设置里面存储总数据
+        _totalSize = [mixDownloadCacheManager totalSizeWith:url];
+        
+        _timeStamp = [iTools getNowTimeStamp];
+        // 校验
+        if (self.currentSize == self.totalSize && self.totalSize != 0) {
+            return nil;
+        }
+        
+        _downloadState = DownloadStateWaiting;
+        [mixDownloadCacheManager saveFileInfoWithDict:[self downLoadInfoWithFinished:NO]];
+        
+        _dataTask = [session mix_downloadDataTaskWithURLString:url startSize:_currentSize];
+    }
+    return _dataTask ? self : nil;
+}
+
+#pragma mark - setups
+- (int64_t)getFileSizeWithURL:(NSString *)url {
+//    // md5文件名加密
+//    NSString *md5FielName = [[url lastPathComponent] stringByDeletingPathExtension];
+//    // 获取后缀名
+//    NSArray *subString = [[url lastPathComponent] componentsSeparatedByString:@"."];
+//    // 拼接后缀名
+    self.fileName = [url lastPathComponent];
+    
+    // 创建文件储存路径
+    if (![[NSFileManager defaultManager] fileExistsAtPath:[mixDownloadCacheManager getFullDirector]]) {
+        [[NSFileManager defaultManager] createDirectoryAtPath:[mixDownloadCacheManager getFullDirector] withIntermediateDirectories:YES attributes:nil error:nil];
+    }
+
+    // 设置下载路径
+    self.fullPath = [[mixDownloadCacheManager getFullDirector] stringByAppendingPathComponent:self.fileName];
+    
+    // 获取下载进度
+    NSDictionary *fileInfo = [[NSFileManager defaultManager] attributesOfItemAtPath:self.fullPath error:nil];
+    // 获取已下载的长度
+    return  [fileInfo[NSFileSize] longLongValue];
+}
+
+
+#pragma mark - get download info
+// 构造回调信息
+- (NSDictionary *)downLoadInfoWithFinished:(BOOL)finished {
+    HLog(@"downloadState:%zd", self.downloadState);
+    return  @{
+                    @"url" : self.url,
+               @"fileName" : self.fileName,
+               @"fullPath" : self.fullPath,
+            @"currentSize" : @(self.currentSize),
+              @"totalSize" : @(self.totalSize),
+               @"fileType" : @(self.fileType),
+              @"timeStamp" : @(self.timeStamp),
+          @"downloadState" : @(self.downloadState),
+             @"isFinished" : @(finished)
+            };
+}
+@end

+ 29 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadQueue.h

@@ -0,0 +1,29 @@
+//
+//  mixDownloadQueue.h
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface mixDownloadQueue : NSObject
+
+/** 设置最大的并发下载个数 */
+@property (nonatomic, assign) NSInteger              maxCount;
+
+@property (nonatomic,strong) NSURLSession *session;
+
+// 添加下载任务
+- (void)addDownloadWithSession:(NSURLSession *)session
+                        URL:(NSURL *)url
+                      begin:(void(^)(NSString * filePath))begin
+                   progress:(void(^)(NSInteger completeSize,NSInteger expectSize))progress
+                   complete:(void(^)(NSDictionary *respose,NSError *error))complet;
+
+- (void)startAllTasksWithSession:(NSURLSession *)session;
+@end
+
+NS_ASSUME_NONNULL_END

+ 191 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadQueue.m

@@ -0,0 +1,191 @@
+//
+//  mixDownloadQueue.m
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import "mixDownloadQueue.h"
+#import "mixDownloadManager.h"
+#import "mixDownloadCacheManager.h"
+#import "mixDownloadSession.h"
+#import "NSURLSession+mixDownloadTask.h"
+
+@interface mixDownloadQueue ()
+// 列队管理集合
+@property (nonatomic,strong) NSMutableArray <mixDownloadOperation *> *operations;
+
+@end
+
+@implementation mixDownloadQueue
+
+- (instancetype)init {
+
+    if (self = [super init]) {
+        _maxCount = 3;
+        
+    }
+    return self;
+}
+
+- (NSMutableArray *)getOperationDoing {
+    
+    NSMutableArray *doingArray = [NSMutableArray array];
+    for (mixDownloadOperation *operation in self.operations) {
+        if (operation.downloadState == DownloadStateDoing) {
+            [doingArray addObject:operation];
+        }
+    }
+    return doingArray;
+}
+
+#pragma mark - handle Out operations
+- (void)addDownloadWithSession:(NSURLSession *)session URL:(NSURL *)url begin:(void(^)(NSString *))begin progress:(void(^)(NSInteger,NSInteger))progress complete:(void(^)(NSDictionary *,NSError *))complet {
+    // 获取operation对象
+    mixDownloadOperation *operation = [self operationWithUrl:url.absoluteString];
+    
+    if (operation == nil) { // 之前不存在此任务
+        
+        operation = [[mixDownloadOperation alloc] initWith:url.absoluteString session:session];
+        
+        if (operation == nil) {
+            // 没有下载任务代表已下载完成
+            NSDictionary *fileInfo = [mixDownloadCacheManager queryFileInfoWithUrl:url.absoluteString];
+            if (fileInfo && complet) {
+                complet(fileInfo,nil);
+            }else {
+                complet(nil,[NSError errorWithDomain:@"构建下载任务失败" code:-1 userInfo:nil]);
+            }
+            return;
+        }
+        
+        [self.operations addObject:operation];
+    }
+    
+    if ([self getOperationDoing].count < self.maxCount) { // 下载中任务数少于最大任务限制
+        [operation.dataTask resume];
+        [self operationStartWithOperation:operation];
+    }else { // 下载中任务数大于最大任务限制
+//        [operation.dataTask suspend];
+        [self operationWaitingWithOperation:operation];
+       HLog(@"下载中任务数等于最大任务限制:%zd",[self getOperationDoing].count);
+    }
+}
+
+
+- (void)startAllTasksWithSession:(NSURLSession *)session {
+    
+    // 开始所有的任务
+    [self.operations enumerateObjectsUsingBlock:^(mixDownloadOperation * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        
+        mixDownloadOperation *operation = (mixDownloadOperation *)obj;
+        if (!operation.dataTask) { // 给plist里的任务添加dataTask 添加到operations
+            operation.dataTask = [self.session mix_downloadDataTaskWithURLString:operation.url startSize:operation.currentSize];
+        }
+  
+        if ([self getOperationDoing].count < self.maxCount) { // 下载中任务数少于最大任务限制
+            
+            switch (operation.dataTask.state) {
+                case NSURLSessionTaskStateRunning:
+                    HLog(@"NSURLSessionTaskStateRunning");
+                    break;
+                
+                case NSURLSessionTaskStateSuspended:
+                    HLog(@"NSURLSessionTaskStateSuspended");
+                    break;
+                    
+                case NSURLSessionTaskStateCanceling:
+                    HLog(@"NSURLSessionTaskStateCanceling");
+                    operation.dataTask = [self.session mix_downloadDataTaskWithURLString:operation.url startSize:operation.currentSize];
+                    break;
+                    
+                case NSURLSessionTaskStateCompleted:
+                    HLog(@"NSURLSessionTaskStateCompleted");
+                    break;
+                    
+                default:
+                    break;
+            }
+            
+            [operation.dataTask resume]; // 开始
+            [self operationStartWithOperation:operation];
+        }else { // 下载中任务数大于最大任务限制
+//            [operation.dataTask suspend];
+            [self operationWaitingWithOperation:operation];
+           HLog(@"下载中任务数等于最大任务限制:%zd",[self getOperationDoing].count);
+        }
+
+    }];
+}
+
+// 重启某一个operation 保存本地 通知外界
+- (void)operationStartWithOperation:(mixDownloadOperation *)operation {
+    operation.downloadState = DownloadStateDoing;
+    [mixDownloadCacheManager saveFileInfoWithDict:[operation downLoadInfoWithFinished:NO]];
+    
+    //[[NSNotificationCenter defaultCenter] postNotificationName:SGDownloadTaskExeing object:nil userInfo:@{@"operation" : operation}];
+}
+
+// 等待某一个operation 保存本地 通知外界
+- (void)operationWaitingWithOperation:(mixDownloadOperation *)operation {
+    operation.downloadState = DownloadStateWaiting;
+    [mixDownloadCacheManager saveFileInfoWithDict:[operation downLoadInfoWithFinished:NO]];
+    
+    //[[NSNotificationCenter defaultCenter] postNotificationName:SGDownloadTaskExeSuspend object:nil userInfo:@{@"operation" : operation}];
+}
+    
+#pragma mark - query operation
+- (mixDownloadOperation *)operationWithUrl:(NSString *)url{
+    __block mixDownloadOperation *operation = nil;
+    
+    [self.operations enumerateObjectsUsingBlock:^(mixDownloadOperation * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        if ([obj.url isEqualToString:url]) {
+            operation = obj;
+            *stop = YES;
+        }
+    }];
+    
+    return operation;
+}
+
+#pragma mark - lazy load
+- (NSMutableArray<mixDownloadOperation *> *)operations {
+    
+    if (!_operations) {
+        _operations = [NSMutableArray array];
+        [self addOperationsFromPlist];
+    }
+    return _operations;
+}
+
+- (void)addOperationsFromPlist {
+    
+    [self.operations removeAllObjects];
+    
+    NSMutableArray *operations = [[mixDownloadManager shareManager] getAllOperation];
+    for (mixDownloadOperation *operationPlist in operations) {
+        
+        // 1、任务列表里取任务
+        mixDownloadOperation *operation = [self operationWithUrl:operationPlist.url];
+        
+        // 2、本地plist文件里提取的任务
+        if (!operation) {
+            NSDictionary *dict = [mixDownloadCacheManager queryFileInfoWithUrl:operationPlist.url];
+            operation = [mixDownloadOperation mj_objectWithKeyValues:dict];
+        }
+
+        // 3、本地plist文件里提取的任务不存在dataTask
+        if(operation){
+            if (!operation.dataTask) {
+                operation.dataTask = [self.session mix_downloadDataTaskWithURLString:operation.url startSize:operation.currentSize];
+                operation.handle = [NSFileHandle fileHandleForWritingAtPath:operation.fullPath];
+
+                [self.operations addObject:operation];
+            }
+        }
+        else{
+            HLog(@"%@ --- 没找到",operationPlist.url)
+        }
+    }
+}
+@end

+ 24 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadSession.h

@@ -0,0 +1,24 @@
+//
+//  mixDownloadSession.h
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface mixDownloadSession : NSObject
+// 接口回调
+- (void)downloadWithURL:(NSURL *)url
+                  begin:(void(^)(NSString *))begin
+               progress:(void(^)(NSInteger,NSInteger))progress
+               complete:(void(^)(NSDictionary *,NSError *))complet;
+
+
+- (void)startAllDownloads;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 59 - 0
创维盒子/双子星云手机/Class/Set/uploadFile/mixDownloadManager/mixDownloadSession.m

@@ -0,0 +1,59 @@
+//
+//  mixDownloadSession.m
+//  双子星云手机
+//
+//  Created by xd h on 2024/6/27.
+//
+
+#import "mixDownloadSession.h"
+#import "mixDownloadQueue.h"
+#import "mixDownloadOperation.h"
+
+@interface mixDownloadSession () <NSURLSessionDataDelegate>
+
+/** session 可以支持多个任务下载,创建一次就可以 */
+@property (nonatomic,strong) NSURLSession *session;
+
+/** 下载列队管理 专门负责接收到数据时分配给不同operation */
+@property (nonatomic,strong) mixDownloadQueue *queue;
+
+@end
+
+@implementation mixDownloadSession
+
+// 添加任务
+- (void)downloadWithURL:(NSURL *)url begin:(void(^)(NSString *))begin progress:(void(^)(NSInteger,NSInteger))progress complete:(void(^)(NSDictionary *,NSError *))complet {
+    // 交给列队管理
+    [self.queue addDownloadWithSession:self.session URL:url begin:begin progress:progress complete:complet];
+    
+}
+
+- (void)startAllDownloads {
+    [self.queue startAllTasksWithSession:self.session];
+}
+
+#pragma mark - lazy load
+- (NSURLSession *)session {
+    if (!_session) {
+        NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
+        // 设置请求超时
+        config.timeoutIntervalForRequest = -1;
+//        config.networkServiceType = NSURLNetworkServiceTypeVideo;
+        config.timeoutIntervalForResource = -1;
+//        config.TLSMaximumSupportedProtocol = kSSLProtocolAll;
+        
+        _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue currentQueue]];
+    }
+    
+    return _session;
+}
+
+- (mixDownloadQueue *)queue {
+    if (!_queue) {
+        _queue = [[mixDownloadQueue alloc] init];
+        _queue.session = self.session;
+    }
+    return _queue;
+}
+
+@end