Browse Source

课件缓存

Steven 11 months ago
parent
commit
7364cddcd8
27 changed files with 5637 additions and 4318 deletions
  1. 26 0
      KulexiuForTeacher/KulexiuForTeacher.xcodeproj/project.pbxproj
  2. 2 1
      KulexiuForTeacher/KulexiuForTeacher.xcworkspace/xcshareddata/swiftpm/Package.resolved
  3. 9 0
      KulexiuForTeacher/KulexiuForTeacher/AppDelegate.h
  4. 67 1
      KulexiuForTeacher/KulexiuForTeacher/AppDelegate.m
  5. 2 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/BaseViewContolller/KSBaseViewController.h
  6. 22 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/BaseViewContolller/KSBaseViewController.m
  7. 37 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/CoursewareDownloadManager.h
  8. 321 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/CoursewareDownloadManager.m
  9. 21 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/KnowledgePointListModel.h
  10. 135 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/KnowledgePointListModel.m
  11. 29 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/MaterialList.h
  12. 162 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/MaterialList.m
  13. 3 1
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSNetworkingManager.h
  14. 4 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSNetworkingManager.m
  15. 1 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/WebView/KSBaseWKWebViewController.h
  16. 84 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/WebView/KSBaseWKWebViewController.m
  17. 4 4
      KulexiuForTeacher/KulexiuForTeacher/Common/MediaMerge/AudioMerge/KSNewAlertView.xib
  18. 3 0
      KulexiuForTeacher/Podfile
  19. 15 1
      KulexiuForTeacher/Podfile.lock
  20. 15 1
      KulexiuForTeacher/Pods/Manifest.lock
  21. 4533 4305
      KulexiuForTeacher/Pods/Pods.xcodeproj/project.pbxproj
  22. 20 0
      KulexiuForTeacher/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/xcschememanagement.plist
  23. 49 0
      KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher-acknowledgements.markdown
  24. 67 0
      KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher-acknowledgements.plist
  25. 4 0
      KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher-resources.sh
  26. 1 2
      KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher.debug.xcconfig
  27. 1 2
      KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher.release.xcconfig

+ 26 - 0
KulexiuForTeacher/KulexiuForTeacher.xcodeproj/project.pbxproj

@@ -453,6 +453,9 @@
 		BC32E10C286AB31C001434DD /* KSPublicAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC32E10B286AB31C001434DD /* KSPublicAlertView.m */; };
 		BC32E10E286AB326001434DD /* KSPublicAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC32E10D286AB326001434DD /* KSPublicAlertView.xib */; };
 		BC3300042BBA67D8003D4921 /* KSToolLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC3300032BBA67D8003D4921 /* KSToolLibrary.framework */; };
+		BC33000E2BBAB5ED003D4921 /* CoursewareDownloadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BC3300082BBAB5ED003D4921 /* CoursewareDownloadManager.m */; };
+		BC33000F2BBAB5ED003D4921 /* KnowledgePointListModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC33000A2BBAB5ED003D4921 /* KnowledgePointListModel.m */; };
+		BC3300102BBAB5ED003D4921 /* MaterialList.m in Sources */ = {isa = PBXBuildFile; fileRef = BC33000C2BBAB5ED003D4921 /* MaterialList.m */; };
 		BC332DB3284866BE005AEF95 /* KSOrderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BC332DB1284866BE005AEF95 /* KSOrderManager.m */; };
 		BC3673D428A606A500059721 /* musicRoom_animation_3.png in Resources */ = {isa = PBXBuildFile; fileRef = BC3673C828A606A400059721 /* musicRoom_animation_3.png */; };
 		BC3673D528A606A500059721 /* live_animation_2.png in Resources */ = {isa = PBXBuildFile; fileRef = BC3673C928A606A400059721 /* live_animation_2.png */; };
@@ -1874,6 +1877,12 @@
 		BC32E10B286AB31C001434DD /* KSPublicAlertView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSPublicAlertView.m; sourceTree = "<group>"; };
 		BC32E10D286AB326001434DD /* KSPublicAlertView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KSPublicAlertView.xib; sourceTree = "<group>"; };
 		BC3300032BBA67D8003D4921 /* KSToolLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = KSToolLibrary.framework; sourceTree = "<group>"; };
+		BC3300072BBAB5ED003D4921 /* CoursewareDownloadManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoursewareDownloadManager.h; sourceTree = "<group>"; };
+		BC3300082BBAB5ED003D4921 /* CoursewareDownloadManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoursewareDownloadManager.m; sourceTree = "<group>"; };
+		BC3300092BBAB5ED003D4921 /* KnowledgePointListModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KnowledgePointListModel.h; sourceTree = "<group>"; };
+		BC33000A2BBAB5ED003D4921 /* KnowledgePointListModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KnowledgePointListModel.m; sourceTree = "<group>"; };
+		BC33000B2BBAB5ED003D4921 /* MaterialList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MaterialList.h; sourceTree = "<group>"; };
+		BC33000C2BBAB5ED003D4921 /* MaterialList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MaterialList.m; sourceTree = "<group>"; };
 		BC332DB1284866BE005AEF95 /* KSOrderManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSOrderManager.m; sourceTree = "<group>"; };
 		BC332DB2284866BE005AEF95 /* KSOrderManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSOrderManager.h; sourceTree = "<group>"; };
 		BC3673C828A606A400059721 /* musicRoom_animation_3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = musicRoom_animation_3.png; sourceTree = "<group>"; };
@@ -3177,6 +3186,7 @@
 		2779309627E30F2D0010E277 /* Base */ = {
 			isa = PBXGroup;
 			children = (
+				BC33000D2BBAB5ED003D4921 /* CoursewareDownload */,
 				BC3A557B2BAA8633002E1616 /* AlertView */,
 				BC3A55782BAA8633002E1616 /* AccompanyWebView */,
 				BC3A557A2BAA8633002E1616 /* BaseViewContolller */,
@@ -4902,6 +4912,19 @@
 			path = Metronome;
 			sourceTree = "<group>";
 		};
+		BC33000D2BBAB5ED003D4921 /* CoursewareDownload */ = {
+			isa = PBXGroup;
+			children = (
+				BC3300072BBAB5ED003D4921 /* CoursewareDownloadManager.h */,
+				BC3300082BBAB5ED003D4921 /* CoursewareDownloadManager.m */,
+				BC3300092BBAB5ED003D4921 /* KnowledgePointListModel.h */,
+				BC33000A2BBAB5ED003D4921 /* KnowledgePointListModel.m */,
+				BC33000B2BBAB5ED003D4921 /* MaterialList.h */,
+				BC33000C2BBAB5ED003D4921 /* MaterialList.m */,
+			);
+			path = CoursewareDownload;
+			sourceTree = "<group>";
+		};
 		BC38C3FF2AF900E100ABFCC2 /* MediaMerge */ = {
 			isa = PBXGroup;
 			children = (
@@ -7764,8 +7787,10 @@
 				2755C07027EC7F21007D9070 /* ChatComplainBodyView.m in Sources */,
 				2755C06727EC71BB007D9070 /* GroupSettingBodyView.m in Sources */,
 				BC71DF052A89F470003F165E /* TXFullVideoCell.m in Sources */,
+				BC33000E2BBAB5ED003D4921 /* CoursewareDownloadManager.m in Sources */,
 				BCA353DF285976CF00377661 /* MusicRoomCourseInfoCell.m in Sources */,
 				BC02BCEB28B324FE005CB483 /* LiveMemberSeatCell.m in Sources */,
+				BC3300102BBAB5ED003D4921 /* MaterialList.m in Sources */,
 				BCA9CE2E27FD8A9200D558C6 /* AccompanyNavView.m in Sources */,
 				BCC9F44727F69BD200647449 /* ClassSongMessage.m in Sources */,
 				BC38C4802AFA1F4B00ABFCC2 /* MineWorksOpenDisplayCell.m in Sources */,
@@ -8014,6 +8039,7 @@
 				BC71DF212A89FABD003F165E /* TxRTCRoomConfig.m in Sources */,
 				BC1553482AB31EEC00C1C347 /* TenangGroupCreateBottomView.m in Sources */,
 				277931EA27E30FC20010E277 /* UIAlertController+Extend.m in Sources */,
+				BC33000F2BBAB5ED003D4921 /* KnowledgePointListModel.m in Sources */,
 				BCC0F7032A8CF13D00C4EFA4 /* TXDanBottomView.m in Sources */,
 				BC71DE932A89C937003F165E /* TXClassroomDeviceMsg.m in Sources */,
 				BCB908FB2850C9C300F5FF69 /* MusicChooseSearchView.m in Sources */,

+ 2 - 1
KulexiuForTeacher/KulexiuForTeacher.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -1,4 +1,5 @@
 {
+  "originHash" : "a837f8bf89850bead33f45d5daae366332606889619596429a3c91b8a957e646",
   "pins" : [
     {
       "identity" : "audiokit",
@@ -37,5 +38,5 @@
       }
     }
   ],
-  "version" : 2
+  "version" : 3
 }

+ 9 - 0
KulexiuForTeacher/KulexiuForTeacher/AppDelegate.h

@@ -9,6 +9,7 @@
 #import "KSTabBarViewController.h"
 #import "LoginViewController.h"
 #import "CustomNavViewController.h"
+#import <HTTPServer.h>
 
 @interface AppDelegate : UIResponder <UIApplicationDelegate>
 
@@ -24,6 +25,14 @@
 
 @property (nonatomic, assign) BOOL isShowMemoAlert;
 
+/**本地服务器*/
+@property (strong, nonatomic) HTTPServer *httpServer;
+/**是否启动了本地服务器*/
+@property(nonatomic,assign)BOOL isServiceStart;
+
+@property (nonatomic, strong) NSString *serverPort;
+
+
 
 - (void)initTableBar;
 - (void)requestRongCloudToken;

+ 67 - 1
KulexiuForTeacher/KulexiuForTeacher/AppDelegate.m

@@ -143,6 +143,9 @@
         
         [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[UIDocumentBrowserViewController class]]].tintColor = THEMECOLOR;
     }
+    
+    [self openServer];
+
     return YES;
 }
 
@@ -416,7 +419,9 @@ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
     
     // 退到后台发送消息
     [[NSNotificationCenter defaultCenter] postNotificationName:@"appEnterBackground" object:nil];
-    
+    if (_isServiceStart){//停止本地服务器
+        [self stopServer];
+    }
     
 }
 - (void)quitClassRoom {
@@ -435,6 +440,9 @@ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
     [self checkConnectionStatus];
     
     [[NSNotificationCenter defaultCenter] postNotificationName:@"appBecomeActive" object:nil];
+    if (!_isServiceStart){
+        _isServiceStart = [self startServer];
+    }
 }
 
 - (void)checkConnectionStatus {
@@ -955,4 +963,62 @@ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
     }
 }
 
+
+- (void)openServer {//开启本地服务器
+    self.httpServer = [[HTTPServer alloc]init];
+    [self.httpServer setType:@"_http._tcp."];
+    [self.httpServer setPort:6050];
+    NSString *webPath = [self getCourewareSavePath];
+    
+    NSFileManager *fileManager = [[NSFileManager alloc] init];
+    NSLog(@"%@",webPath);
+    
+    if (![fileManager fileExistsAtPath:webPath]){
+        NSLog(@"File path error!");
+    }else{
+        [self.httpServer setDocumentRoot:webPath];
+        NSLog(@"服务器路径:%@", webPath);
+        self.isServiceStart = [self startServer];
+    }
+    
+}
+
+
+- (NSString *)getCourewareSavePath {
+    //  在Documents目录下创建一个名为CoursewarePath的文件夹
+    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"CoursewarePath"];
+    
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    BOOL isDir = FALSE;
+    BOOL isDirExist = [fileManager fileExistsAtPath:path isDirectory:&isDir];
+    if(!(isDirExist && isDir)) {
+        BOOL bCreateDir = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
+        if(!bCreateDir){
+            NSLog(@"创建文件夹失败!");
+        }
+//        NSLog(@"创建文件夹成功,文件路径%@",path);
+    }
+    return path;
+}
+
+- (BOOL)startServer {//启动服务
+    BOOL ret = NO;
+    NSError *error = nil;
+    if([self.httpServer start:&error]){
+        NSLog(@"HTTP服务器启动成功端口号为: %hu", [_httpServer listeningPort]);
+        self.serverPort = [NSString stringWithFormat:@"%d",[self.httpServer listeningPort]];
+        ret = YES;
+    }else{
+        NSLog(@"启动HTTP服务器出错: %@", error);
+    }
+    return ret;
+}
+
+- (void)stopServer{//停止服务
+    if (self.httpServer != nil){
+        [self.httpServer stop];
+        self.isServiceStart = NO;
+    }
+}
+
 @end

+ 2 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/BaseViewContolller/KSBaseViewController.h

@@ -54,6 +54,8 @@ NS_ASSUME_NONNULL_BEGIN
 -(UIImage *)imageCompressForSize:(UIImage *)sourceImage targetSize:(CGSize)size;
 -(BOOL) isConnectionAvailable;
 
+// 判断当前是否Wi-Fi环境
+- (BOOL)isWiFiEnable;
 
 - (void)backAction; // 返回
 -(void)allocTitle:(NSString*)Ntitle withColor:(UIColor *)color;

+ 22 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/BaseViewContolller/KSBaseViewController.m

@@ -162,6 +162,28 @@
     leftButton.tintColor = HexRGB(0x000000);
     self.navigationItem.leftBarButtonItem = leftButton;
 }
+
+// 判断当前是否Wi-Fi环境
+- (BOOL)isWiFiEnable {
+    BOOL isWiFi = NO;
+    Reachability *reach = [Reachability reachabilityWithHostName:@"www.apple.com"];
+    switch ([reach currentReachabilityStatus]) {
+        case NotReachable:
+            isWiFi = NO;
+            //NSLog(@"notReachable");
+            break;
+        case ReachableViaWiFi:
+            isWiFi = YES;
+            //NSLog(@"WIFI");
+            break;
+        case ReachableViaWWAN:
+            isWiFi = NO;
+            //NSLog(@"3G");
+            break;
+    }
+    return isWiFi;
+}
+
 - (void)backAction {
     [self.view endEditing:YES];
     // 根据需要返回到不同页面

+ 37 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/CoursewareDownloadManager.h

@@ -0,0 +1,37 @@
+//
+//  CoursewareDownloadManager.h
+//  GuanYueTeamTeacher
+//
+//  Created by 王智 on 2023/1/10.
+//
+
+#import <Foundation/Foundation.h>
+
+#define COURSEWARE_MANAGER ([CoursewareDownloadManager shareInstance])
+
+NS_ASSUME_NONNULL_BEGIN
+// downloadStatus:1下载中 2下载完成 3下载失败,
+// progress:0-100取值范围
+typedef void(^CoursewareDownloadCallback)(NSDictionary *sendParm);
+
+typedef void(^CoursewareCacheCallback)(NSDictionary *parm);
+
+@interface CoursewareDownloadManager : NSObject
+
+@property (nonatomic, strong) NSString *lessonCoursewareDetailId;
+
+@property (nonatomic, assign) BOOL isDownloading;
+
++ (instancetype)shareInstance;
+
+- (void)checkCourseCacheStatus:(NSDictionary *)parm callback:(CoursewareCacheCallback)callback;
+
+- (void)downloadCourseWithParm:(NSDictionary *)parm callback:(CoursewareDownloadCallback)callback;
+
+- (NSString *)queryFileUrlWithParm:(NSDictionary *)parm;
+
+- (void)cancleDownloadCourseware;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 321 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/CoursewareDownloadManager.m

@@ -0,0 +1,321 @@
+//
+//  CoursewareDownloadManager.m
+//  GuanYueTeamTeacher
+//
+//  Created by 王智 on 2023/1/10.
+//
+
+#import "CoursewareDownloadManager.h"
+#import "KnowledgePointListModel.h"
+
+@interface CoursewareDownloadManager ()
+
+@property (nonatomic, copy) CoursewareDownloadCallback callback;
+
+@property (nonatomic, strong) NSMutableArray *knowledgePointArray;
+
+@property (nonatomic, strong) NSMutableArray *undownloadFileArray;
+
+@property (nonatomic, assign) NSInteger currentSuccessIndex;
+
+@property (nonatomic, assign) NSInteger totalSouceCount;
+
+@property (nonatomic, copy) CoursewareCacheCallback cacheCallback;
+
+@property (nonatomic, copy) NSMutableDictionary *lessonCoursewareParm;
+
+@property (nonatomic, assign) float singleFileRate;
+
+@property (nonatomic, assign) BOOL isCancelDownload; // 是否取消下载
+
+@end
+
+@implementation CoursewareDownloadManager
+
++ (instancetype)shareInstance {
+    static CoursewareDownloadManager *manager = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        manager = [[CoursewareDownloadManager alloc] init];
+    });
+    return manager;
+}
+
+#pragma mark ---- 检测缓存
+- (void)checkCourseCacheStatus:(NSDictionary *)parm callback:(CoursewareCacheCallback)callback {
+    if (callback) {
+        self.cacheCallback = callback;
+    }
+    [self checkCacheWithParm:parm];
+}
+
+- (void)checkCacheWithParm:(NSDictionary *)parm {
+    NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
+    [sendParm setValue:[parm ks_stringValueForKey:@"api"] forKey:@"api"];
+    
+    NSMutableDictionary *content = [NSMutableDictionary dictionaryWithDictionary:[parm ks_dictionaryValueForKey:@"content"]];
+    NSMutableArray *courewareArray = [NSMutableArray arrayWithArray:[content ks_arrayValueForKey:@"data"]];
+    NSMutableArray *sourceArray = [NSMutableArray array];
+    for (NSDictionary *parm in courewareArray) {
+        NSArray *knowledgePointList = [parm ks_arrayValueForKey:@"knowledgePointList"];
+        
+        NSMutableArray *listArray = [NSMutableArray array];
+        for (NSDictionary *sourceParm in knowledgePointList) {
+            KnowledgePointListModel *model = [[KnowledgePointListModel alloc] initWithDictionary:sourceParm];
+            [listArray addObject:model];
+        }
+        BOOL isCache = [self checkPointIsCache:listArray];
+        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:parm];
+        [dic setValue:@(isCache) forKey:@"hasCache"];
+        [sourceArray addObject:dic];
+    }
+    [content setValue:sourceArray forKey:@"data"];
+    [sendParm setValue:content forKey:@"content"];
+    
+    if (self.cacheCallback) {
+        self.cacheCallback(sendParm);
+    }
+}
+
+// 判断当前课件是否缓存
+- (BOOL)checkPointIsCache:(NSArray *)listArray {
+    
+    for (KnowledgePointListModel *model in listArray) {
+        for (MaterialList *listModel in model.materialList) {
+            if ([listModel.type isEqualToString:@"SONG"]) { // 曲目
+                
+            }
+            else { // 下载图片和视频
+                NSString *url = listModel.content;
+                NSString *fileName = [url getUrlFileName];
+                if ([self isNomalFile:fileName]) {
+                    fileName = [NSString stringWithFormat:@"%@%@%@", listModel.materialListIdentifier, [listModel.updateTime replaceAll:@" " WithString:@""],fileName];
+                    NSString *filePath = [[self getCourewareSavePath] stringByAppendingPathComponent:fileName];
+                    BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
+                    if (isExist == NO) {
+                        return NO;
+                    }
+                }
+            }
+        }
+    }
+    return YES;
+}
+
+
+#pragma mark ---- 下载
+- (void)downloadCourseWithParm:(NSDictionary *)parm callback:(CoursewareDownloadCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+    if (self.isDownloading) {
+        return;
+    }
+    self.currentSuccessIndex = 0;
+    self.totalSouceCount = 0;
+    [self downloadCourseMessage:parm];
+}
+
+- (void)downloadCourseMessage:(NSDictionary *)parm {
+    self.knowledgePointArray = [NSMutableArray array];
+    NSMutableDictionary *content = [NSMutableDictionary dictionaryWithDictionary:[parm ks_dictionaryValueForKey:@"content"]];
+    NSDictionary *coureParm = [content ks_dictionaryValueForKey:@"data"];
+    self.lessonCoursewareDetailId = [coureParm ks_stringValueForKey:@"lessonCoursewareDetailId"];
+    NSArray *sourceArray = [coureParm ks_arrayValueForKey:@"knowledgePointList"];
+    for (NSDictionary *parm in sourceArray) {
+        KnowledgePointListModel *model = [[KnowledgePointListModel alloc] initWithDictionary:parm];
+        [self.knowledgePointArray addObject:model];
+    }
+    
+    [self checkCoursewareStatus];
+}
+
+- (void)checkCoursewareStatus {
+    
+    self.undownloadFileArray = [NSMutableArray array];
+    for (KnowledgePointListModel *model in self.knowledgePointArray) {
+        for (MaterialList *listModel in model.materialList) {
+            if ([listModel.type isEqualToString:@"SONG"]) { // 曲目
+                
+            }
+            else { // 下载图片和视频
+                self.totalSouceCount++;
+                NSString *url = listModel.content;
+                NSString *fileName = [url getUrlFileName];
+                if ([self isNomalFile:fileName]) {
+                    fileName = [NSString stringWithFormat:@"%@%@%@", listModel.materialListIdentifier, [listModel.updateTime replaceAll:@" " WithString:@""],fileName];
+                    NSString *filePath = [[self getCourewareSavePath] stringByAppendingPathComponent:fileName];
+                    BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
+                    if (isExist == NO) {
+                        [self.undownloadFileArray addObject:listModel];
+                    }
+                }
+            }
+        }
+    }
+    self.currentSuccessIndex = self.totalSouceCount - self.undownloadFileArray.count;
+    self.singleFileRate =  1.0 / self.totalSouceCount * 100;
+    
+    [self downloadAllSourceFile];
+}
+
+- (BOOL)isNomalFile:(NSString *)fileName {
+    if ([fileName hasSuffix:@".png"] || [fileName hasSuffix:@".jpg"] || [fileName hasSuffix:@".jepg"] || [fileName hasSuffix:@".mp4"] || [fileName hasSuffix:@".flv"] || [fileName hasSuffix:@".avi"] || [fileName hasSuffix:@".mov"]) {
+        return YES;
+    }
+    return NO;
+}
+
+#pragma mark ---- 课件其他资源
+- (void)downloadAllSourceFile {
+    [self downloadFileIndex:0];
+}
+
+- (NSMutableDictionary *)configParmWithSource:(NSInteger)status progress:(NSInteger)progress {
+    NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
+    [sendParm setValue:@"downloadCoursewareToCache" forKey:@"api"];
+    NSMutableDictionary *content = [NSMutableDictionary dictionary];
+    [content setValue:@(status) forKey:@"downloadStatus"];
+    [content setValue:@(progress) forKey:@"progress"];
+    [content setValue:self.lessonCoursewareDetailId forKey:@"lessonCoursewareDetailId"];
+    [sendParm setValue:content forKey:@"content"];
+    return sendParm;
+}
+
+- (void)downloadFileIndex:(NSInteger)fileIndex {
+    if (self.isCancelDownload) {
+        self.isCancelDownload = NO;
+        self.isDownloading = NO;
+        return;
+    }
+    if (self.undownloadFileArray.count == 0) {
+        NSDictionary *parm = [self configParmWithSource:2 progress:100];
+        if (self.callback) {
+            self.callback(parm);
+        }
+        self.isDownloading = NO;
+        return;
+    }
+    else if (fileIndex > self.undownloadFileArray.count - 1) {
+        if (self.callback) {
+            NSInteger rate = self.currentSuccessIndex * 100 / self.totalSouceCount;
+            if (self.undownloadFileArray.count == 0) {
+                rate = 100;
+            }
+            NSDictionary *parm = [self configParmWithSource:2 progress:rate];
+            if (self.callback) {
+                self.callback(parm);
+            }
+            self.isDownloading = NO;
+        }
+        return;
+    }
+    self.isDownloading = YES;
+    MaterialList *model = self.undownloadFileArray[fileIndex];
+    NSString *url = model.content;
+    [KSNetworkingManager downloadFileRequestWithFileUrl:url progress:^(int64_t bytesRead, int64_t totalBytes) {
+        double progress = bytesRead * 1.0 / totalBytes;
+        NSLog(@"%f",progress);
+        NSInteger rate = (NSInteger) (progress * self.singleFileRate);
+        NSInteger preDownloadRate = self.currentSuccessIndex * 100 / self.totalSouceCount;
+        NSInteger totalRate = rate + preDownloadRate;
+        if (totalRate > 100) {
+            totalRate = 100;
+        }
+        NSDictionary *parm = [self configParmWithSource:1 progress:totalRate];
+        if (self.callback) {
+            self.callback(parm);
+        }
+    } success:^(NSURL * _Nonnull fileUrl) {
+        [self savePathWithLocalPath:[fileUrl resourceSpecifier] sourceModel:model fileIndex:fileIndex];
+
+    } faliure:^(NSError * _Nonnull error) {
+        NSInteger nextIndex = fileIndex + 1;
+        [self downloadFileIndex:nextIndex];
+    }];
+}
+
+- (void)savePathWithLocalPath:(NSString *)localPath sourceModel:(MaterialList *)model fileIndex:(NSInteger)fileIndex {
+    NSString *url = model.content;
+    NSString *fileName = [NSString stringWithFormat:@"%@%@%@", model.materialListIdentifier, [model.updateTime replaceAll:@" " WithString:@""],[url getUrlFileName]];
+    NSString *filePath = [[self getCourewareSavePath] stringByAppendingPathComponent:fileName];
+    NSError *error;
+    
+    BOOL isSuccess = [[NSFileManager defaultManager] moveItemAtPath:localPath toPath:filePath error:&error];
+    if (isSuccess) {
+        self.currentSuccessIndex++;
+        NSLog(@"rename success");
+        // 如果旧文件存在 就删除
+        if ([[NSFileManager defaultManager] fileExistsAtPath:localPath]) {
+            BOOL isDelSuccess = [[NSFileManager defaultManager] removeItemAtPath:localPath error:nil];
+            if (isDelSuccess) {
+                NSLog(@"remove success");
+            } else {
+                NSLog(@"remove fail");
+            }
+        }
+        
+        if (self.callback) {
+            NSInteger rate = self.currentSuccessIndex * 100 / self.totalSouceCount;
+            NSDictionary *parm = [self configParmWithSource:1 progress:rate];
+            if (self.callback) {
+                self.callback(parm);
+            }
+        }
+        NSInteger nextIndex = fileIndex + 1;
+        [self downloadFileIndex:nextIndex];
+    }else{
+        NSLog(@"rename fail");
+        NSInteger nextIndex = fileIndex + 1;
+        [self downloadFileIndex:nextIndex];
+    }
+}
+
+- (NSString *)getCourewareSavePath {
+    //  在Documents目录下创建一个名为CoursewarePath的文件夹
+    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"CoursewarePath"];
+    
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    BOOL isDir = FALSE;
+    BOOL isDirExist = [fileManager fileExistsAtPath:path isDirectory:&isDir];
+    if(!(isDirExist && isDir)) {
+        BOOL bCreateDir = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
+        if(!bCreateDir){
+            NSLog(@"创建文件夹失败!");
+        }
+//        NSLog(@"创建文件夹成功,文件路径%@",path);
+    }
+    return path;
+}
+
+
+- (NSString *)queryFileUrlWithParm:(NSDictionary *)parm {
+    NSString *locaPath = @"";
+    NSString *url = [parm ks_stringValueForKey:@"url"];
+    NSString *fileName = [NSString stringWithFormat:@"%@%@%@", [parm ks_stringValueForKey:@"materialId"], [[parm ks_stringValueForKey:@"updateTime"] replaceAll:@" " WithString:@""],[url getUrlFileName]];
+    locaPath = [[self getCourewareSavePath] stringByAppendingPathComponent:fileName];
+    BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:locaPath];
+    if (isExist) {
+        return locaPath;
+    }
+    else {
+        return @"";
+    }
+}
+
+- (void)cancleDownloadCourseware {
+
+    self.isCancelDownload = YES;
+    [KSNetworkingManager cancelAllRequest];
+}
+
+
+#pragma mark --- lazying
+- (NSMutableArray *)knowledgePointArray {
+    if (!_knowledgePointArray) {
+        _knowledgePointArray = [NSMutableArray array];
+    }
+    return _knowledgePointArray;
+}
+
+@end

+ 21 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/KnowledgePointListModel.h

@@ -0,0 +1,21 @@
+//
+//  KnowledgePointListModel.h
+//
+//  Created by Steven  on 2023/1/10
+//  Copyright (c) 2023 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "MaterialList.h"
+
+@interface KnowledgePointListModel : NSObject <NSCoding, NSCopying>
+
+@property (nonatomic, strong) NSString *internalBaseClassIdentifier;
+@property (nonatomic, strong) NSString *name;
+@property (nonatomic, strong) NSArray *materialList;
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
+- (instancetype)initWithDictionary:(NSDictionary *)dict;
+- (NSDictionary *)dictionaryRepresentation;
+
+@end

+ 135 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/KnowledgePointListModel.m

@@ -0,0 +1,135 @@
+//
+//  KnowledgePointListModel.m
+//
+//  Created by Steven  on 2023/1/10
+//  Copyright (c) 2023 __MyCompanyName__. All rights reserved.
+//
+
+#import "KnowledgePointListModel.h"
+
+
+NSString *const kKnowledgePointListModelId = @"id";
+NSString *const kKnowledgePointListModelName = @"name";
+NSString *const kKnowledgePointListModelMaterialList = @"materialList";
+
+
+@interface KnowledgePointListModel ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation KnowledgePointListModel
+
+@synthesize internalBaseClassIdentifier = _internalBaseClassIdentifier;
+@synthesize name = _name;
+@synthesize materialList = _materialList;
+
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
+{
+    return [[self alloc] initWithDictionary:dict];
+}
+
+- (instancetype)initWithDictionary:(NSDictionary *)dict
+{
+    self = [super init];
+    
+    // This check serves to make sure that a non-NSDictionary object
+    // passed into the model class doesn't break the parsing.
+    if(self && [dict isKindOfClass:[NSDictionary class]]) {
+            self.internalBaseClassIdentifier = [self objectOrNilForKey:kKnowledgePointListModelId fromDictionary:dict];
+            self.name = [self objectOrNilForKey:kKnowledgePointListModelName fromDictionary:dict];
+    NSObject *receivedMaterialList = [dict objectForKey:kKnowledgePointListModelMaterialList];
+    NSMutableArray *parsedMaterialList = [NSMutableArray array];
+    if ([receivedMaterialList isKindOfClass:[NSArray class]]) {
+        for (NSDictionary *item in (NSArray *)receivedMaterialList) {
+            if ([item isKindOfClass:[NSDictionary class]]) {
+                [parsedMaterialList addObject:[MaterialList modelObjectWithDictionary:item]];
+            }
+       }
+    } else if ([receivedMaterialList isKindOfClass:[NSDictionary class]]) {
+       [parsedMaterialList addObject:[MaterialList modelObjectWithDictionary:(NSDictionary *)receivedMaterialList]];
+    }
+
+    self.materialList = [NSArray arrayWithArray:parsedMaterialList];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:self.internalBaseClassIdentifier forKey:kKnowledgePointListModelId];
+    [mutableDict setValue:self.name forKey:kKnowledgePointListModelName];
+    NSMutableArray *tempArrayForMaterialList = [NSMutableArray array];
+    for (NSObject *subArrayObject in self.materialList) {
+        if([subArrayObject respondsToSelector:@selector(dictionaryRepresentation)]) {
+            // This class is a model object
+            [tempArrayForMaterialList addObject:[subArrayObject performSelector:@selector(dictionaryRepresentation)]];
+        } else {
+            // Generic object
+            [tempArrayForMaterialList addObject:subArrayObject];
+        }
+    }
+    [mutableDict setValue:[NSArray arrayWithArray:tempArrayForMaterialList] forKey:kKnowledgePointListModelMaterialList];
+
+    return [NSDictionary dictionaryWithDictionary:mutableDict];
+}
+
+- (NSString *)description 
+{
+    return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
+}
+
+#pragma mark - Helper Method
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict
+{
+    id object = [dict objectForKey:aKey];
+    if ([object isKindOfClass:[NSNumber class]]) {
+        NSNumber *number = object;
+        object = [number stringValue];
+    }
+    return [object isEqual:[NSNull null]] ? nil : object;
+}
+
+
+#pragma mark - NSCoding Methods
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super init];
+
+    self.internalBaseClassIdentifier = [aDecoder decodeObjectForKey:kKnowledgePointListModelId];
+    self.name = [aDecoder decodeObjectForKey:kKnowledgePointListModelName];
+    self.materialList = [aDecoder decodeObjectForKey:kKnowledgePointListModelMaterialList];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeObject:_internalBaseClassIdentifier forKey:kKnowledgePointListModelId];
+    [aCoder encodeObject:_name forKey:kKnowledgePointListModelName];
+    [aCoder encodeObject:_materialList forKey:kKnowledgePointListModelMaterialList];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    KnowledgePointListModel *copy = [[KnowledgePointListModel alloc] init];
+    
+    if (copy) {
+
+        copy.internalBaseClassIdentifier = [self.internalBaseClassIdentifier copyWithZone:zone];
+        copy.name = [self.name copyWithZone:zone];
+        copy.materialList = [self.materialList copyWithZone:zone];
+    }
+    
+    return copy;
+}
+
+
+@end

+ 29 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/MaterialList.h

@@ -0,0 +1,29 @@
+//
+//  MaterialList.h
+//
+//  Created by Steven  on 2023/5/14
+//  Copyright (c) 2023 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+
+@interface MaterialList : NSObject <NSCoding, NSCopying>
+
+@property (nonatomic, assign) id adviseStudyTimeSecond;
+@property (nonatomic, strong) NSString *content;
+@property (nonatomic, strong) NSString *knowledgePointId;
+@property (nonatomic, strong) NSString *updateTime;
+@property (nonatomic, strong) NSString *materialListIdentifier;
+@property (nonatomic, strong) NSString *courseTypeCode;
+@property (nonatomic, strong) NSString *sn;
+@property (nonatomic, strong) NSString *type;
+@property (nonatomic, strong) NSString *name;
+@property (nonatomic, strong) NSString *knowledgePointMaterialRelationId;
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
+- (instancetype)initWithDictionary:(NSDictionary *)dict;
+- (NSDictionary *)dictionaryRepresentation;
+
+@end

+ 162 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/CoursewareDownload/MaterialList.m

@@ -0,0 +1,162 @@
+//
+//  MaterialList.m
+//
+//  Created by Steven  on 2023/5/14
+//  Copyright (c) 2023 __MyCompanyName__. All rights reserved.
+//
+
+#import "MaterialList.h"
+
+
+NSString *const kMaterialListAdviseStudyTimeSecond = @"adviseStudyTimeSecond";
+NSString *const kMaterialListContent = @"content";
+NSString *const kMaterialListKnowledgePointId = @"knowledgePointId";
+NSString *const kMaterialListUpdateTime = @"updateTime";
+NSString *const kMaterialListId = @"id";
+NSString *const kMaterialListCourseTypeCode = @"courseTypeCode";
+NSString *const kMaterialListSn = @"sn";
+NSString *const kMaterialListType = @"type";
+NSString *const kMaterialListName = @"name";
+NSString *const kMaterialListKnowledgePointMaterialRelationId = @"knowledgePointMaterialRelationId";
+
+
+@interface MaterialList ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation MaterialList
+
+@synthesize adviseStudyTimeSecond = _adviseStudyTimeSecond;
+@synthesize content = _content;
+@synthesize knowledgePointId = _knowledgePointId;
+@synthesize updateTime = _updateTime;
+@synthesize materialListIdentifier = _materialListIdentifier;
+@synthesize courseTypeCode = _courseTypeCode;
+@synthesize sn = _sn;
+@synthesize type = _type;
+@synthesize name = _name;
+@synthesize knowledgePointMaterialRelationId = _knowledgePointMaterialRelationId;
+
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
+{
+    return [[self alloc] initWithDictionary:dict];
+}
+
+- (instancetype)initWithDictionary:(NSDictionary *)dict
+{
+    self = [super init];
+    
+    // This check serves to make sure that a non-NSDictionary object
+    // passed into the model class doesn't break the parsing.
+    if(self && [dict isKindOfClass:[NSDictionary class]]) {
+            self.adviseStudyTimeSecond = [self objectOrNilForKey:kMaterialListAdviseStudyTimeSecond fromDictionary:dict];
+            self.content = [self objectOrNilForKey:kMaterialListContent fromDictionary:dict];
+            self.knowledgePointId = [self objectOrNilForKey:kMaterialListKnowledgePointId fromDictionary:dict];
+            self.updateTime = [self objectOrNilForKey:kMaterialListUpdateTime fromDictionary:dict];
+            self.materialListIdentifier = [self objectOrNilForKey:kMaterialListId fromDictionary:dict];
+            self.courseTypeCode = [self objectOrNilForKey:kMaterialListCourseTypeCode fromDictionary:dict];
+            self.sn = [self objectOrNilForKey:kMaterialListSn fromDictionary:dict];
+            self.type = [self objectOrNilForKey:kMaterialListType fromDictionary:dict];
+            self.name = [self objectOrNilForKey:kMaterialListName fromDictionary:dict];
+            self.knowledgePointMaterialRelationId = [self objectOrNilForKey:kMaterialListKnowledgePointMaterialRelationId fromDictionary:dict];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:self.adviseStudyTimeSecond forKey:kMaterialListAdviseStudyTimeSecond];
+    [mutableDict setValue:self.content forKey:kMaterialListContent];
+    [mutableDict setValue:self.knowledgePointId forKey:kMaterialListKnowledgePointId];
+    [mutableDict setValue:self.updateTime forKey:kMaterialListUpdateTime];
+    [mutableDict setValue:self.materialListIdentifier forKey:kMaterialListId];
+    [mutableDict setValue:self.courseTypeCode forKey:kMaterialListCourseTypeCode];
+    [mutableDict setValue:self.sn forKey:kMaterialListSn];
+    [mutableDict setValue:self.type forKey:kMaterialListType];
+    [mutableDict setValue:self.name forKey:kMaterialListName];
+    [mutableDict setValue:self.knowledgePointMaterialRelationId forKey:kMaterialListKnowledgePointMaterialRelationId];
+
+    return [NSDictionary dictionaryWithDictionary:mutableDict];
+}
+
+- (NSString *)description 
+{
+    return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
+}
+
+#pragma mark - Helper Method
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict
+{
+    id object = [dict objectForKey:aKey];
+    if ([object isKindOfClass:[NSNumber class]]) {
+        NSNumber *number = object;
+        object = [number stringValue];
+    }
+    return [object isEqual:[NSNull null]] ? nil : object;
+}
+
+
+#pragma mark - NSCoding Methods
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super init];
+
+    self.adviseStudyTimeSecond = [aDecoder decodeObjectForKey:kMaterialListAdviseStudyTimeSecond];
+    self.content = [aDecoder decodeObjectForKey:kMaterialListContent];
+    self.knowledgePointId = [aDecoder decodeObjectForKey:kMaterialListKnowledgePointId];
+    self.updateTime = [aDecoder decodeObjectForKey:kMaterialListUpdateTime];
+    self.materialListIdentifier = [aDecoder decodeObjectForKey:kMaterialListId];
+    self.courseTypeCode = [aDecoder decodeObjectForKey:kMaterialListCourseTypeCode];
+    self.sn = [aDecoder decodeObjectForKey:kMaterialListSn];
+    self.type = [aDecoder decodeObjectForKey:kMaterialListType];
+    self.name = [aDecoder decodeObjectForKey:kMaterialListName];
+    self.knowledgePointMaterialRelationId = [aDecoder decodeObjectForKey:kMaterialListKnowledgePointMaterialRelationId];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeObject:_adviseStudyTimeSecond forKey:kMaterialListAdviseStudyTimeSecond];
+    [aCoder encodeObject:_content forKey:kMaterialListContent];
+    [aCoder encodeObject:_knowledgePointId forKey:kMaterialListKnowledgePointId];
+    [aCoder encodeObject:_updateTime forKey:kMaterialListUpdateTime];
+    [aCoder encodeObject:_materialListIdentifier forKey:kMaterialListId];
+    [aCoder encodeObject:_courseTypeCode forKey:kMaterialListCourseTypeCode];
+    [aCoder encodeObject:_sn forKey:kMaterialListSn];
+    [aCoder encodeObject:_type forKey:kMaterialListType];
+    [aCoder encodeObject:_name forKey:kMaterialListName];
+    [aCoder encodeObject:_knowledgePointMaterialRelationId forKey:kMaterialListKnowledgePointMaterialRelationId];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    MaterialList *copy = [[MaterialList alloc] init];
+    
+    if (copy) {
+
+        copy.adviseStudyTimeSecond = [self.adviseStudyTimeSecond copyWithZone:zone];
+        copy.content = [self.content copyWithZone:zone];
+        copy.knowledgePointId = [self.knowledgePointId copyWithZone:zone];
+        copy.updateTime = [self.updateTime copyWithZone:zone];
+        copy.materialListIdentifier = [self.materialListIdentifier copyWithZone:zone];
+        copy.courseTypeCode = [self.courseTypeCode copyWithZone:zone];
+        copy.sn = [self.sn copyWithZone:zone];
+        copy.type = [self.type copyWithZone:zone];
+        copy.name = [self.name copyWithZone:zone];
+        copy.knowledgePointMaterialRelationId = [self.knowledgePointMaterialRelationId copyWithZone:zone];
+    }
+    
+    return copy;
+}
+
+
+@end

+ 3 - 1
KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSNetworkingManager.h

@@ -26,8 +26,10 @@ NS_ASSUME_NONNULL_BEGIN
 + (void)configRequestMethodJSON;
 // 退出登录操作
 + (void)logoutAction;
+// 取消所有请求操作
++ (void)cancelAllRequest;
 
-#pragma mark -------- CLASS REQUEST 
+#pragma mark -------- CLASS REQUEST
 + (void)classroomRequest:(NSString *)method url:(NSString *)url parms:(NSDictionary *)parms success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
 #pragma mark -------- LIVE ROOM
 + (void)LiveRoomRequest:(NSString *)method url:(NSString *)url parms:(id)parms success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;

+ 4 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSNetworkingManager.m

@@ -184,6 +184,10 @@
     [APPLOGIN_MANAGER logoutAction];
 }
 
+/// 移除所以当前请求
++ (void)cancelAllRequest {
+    [[VoNetworking sharedManager] cancleAllRequest];
+}
 
 // 提示信息
 + (void)showMessage:(NSString *)message {

+ 1 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/WebView/KSBaseWKWebViewController.h

@@ -8,6 +8,7 @@
 #import "KSBaseViewController.h"
 #import <WebKit/WebKit.h>
 #import <KSToolLibrary/WeakWebViewScriptMessageDelegate.h>
+#import "CoursewareDownloadManager.h"
 
 NS_ASSUME_NONNULL_BEGIN
 

+ 84 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/WebView/KSBaseWKWebViewController.m

@@ -37,6 +37,8 @@
 // 错误刷新web 页面
 #import "KSWebLoadRefreshView.h"
 
+#import "KSNewAlertView.h"
+
 typedef NS_ENUM(NSInteger, CHOOSETYPE) {
     CHOOSETYPE_XML,
     CHOOSETYPE_MIDI,
@@ -73,6 +75,8 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
 
 @property (nonatomic, assign) BOOL isDownloadFile;
 
+@property (nonatomic, strong) KSNewAlertView *wifiAlert;
+
 @end
 
 @implementation KSBaseWKWebViewController
@@ -657,6 +661,86 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
         NSString *type = [[parm ks_dictionaryValueForKey:@"content"] ks_stringValueForKey:@"type"];
         [USER_MANAGER sendUMEvent:type];
     }
+    // 课件相关
+    else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"getCourseFilePath"]) { // 课件资源查询
+        NSDictionary *valueDic = [parm ks_dictionaryValueForKey:@"content"];
+        NSString *localPath = [COURSEWARE_MANAGER queryFileUrlWithParm:valueDic];
+        BOOL isServiceStart = [AppDelegate shareAppDelegate].httpServer.isRunning;
+        if (![NSString isEmptyString:localPath] && isServiceStart) {
+            localPath = [[localPath componentsSeparatedByString:@"CoursewarePath/"] lastObject];
+            localPath = [NSString stringWithFormat:@"%@%@/%@",@"http://localhost:",[AppDelegate shareAppDelegate].serverPort,localPath];
+            NSMutableDictionary *contentParm = [NSMutableDictionary dictionaryWithDictionary:valueDic];
+            [contentParm setValue:localPath forKey:@"localPath"];
+            NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
+            [sendParm setValue:@"getCourseFilePath" forKey:@"api"];
+            [sendParm setValue:contentParm forKey:@"content"];
+            [self postMessage:sendParm];
+        }
+        else {
+            [self postMessage:parm];
+        }
+    }
+    else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"checkCoursewareCache"]) {
+        MJWeakSelf;
+        [COURSEWARE_MANAGER checkCourseCacheStatus:parm callback:^(NSDictionary * _Nonnull parm) {
+            [weakSelf postMessage:parm];
+        }];
+    }
+    else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"downloadCoursewareToCache"]) {
+        NSDictionary *valueDic = [parm ks_dictionaryValueForKey:@"content"];
+        NSString *lessonCoursewareDetailId = [[valueDic ks_dictionaryValueForKey:@"data"] ks_stringValueForKey:@"lessonCoursewareDetailId"];
+        if (COURSEWARE_MANAGER.isDownloading) {
+            if ([lessonCoursewareDetailId isEqualToString:COURSEWARE_MANAGER.lessonCoursewareDetailId]) {
+                [LOADING_MANAGER MBShowAUTOHidingInWindow:@"当前已有课件资源下载中"];
+                [self downloadWithParm:parm];
+            }
+            else {
+                [LOADING_MANAGER MBShowAUTOHidingInWindow:@"当前已有课件资源下载中"];
+                NSMutableDictionary *contentParm = [NSMutableDictionary dictionary];
+                [contentParm setValue:@(3) forKey:@"status"];
+                [contentParm setValue:@(0) forKey:@"progress"];
+                [contentParm setValue:lessonCoursewareDetailId forKey:@"lessonCoursewareDetailId"];
+
+                NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
+                [sendParm setValue:@"downloadCoursewareToCache" forKey:@"api"];
+                [sendParm setValue:contentParm forKey:@"content"];
+                [self postMessage:sendParm];
+            }
+        }
+        else {
+            if ([self isWiFiEnable] == NO) {
+                self.wifiAlert = [KSNewAlertView shareInstance];
+                MJWeakSelf;
+                [self.wifiAlert configTitle:@"提示" descMessage:@"当前非Wi-Fi环境,是否开始下载?" leftButtonTitle:@"取消" rightButtonTitle:@"确认" leftButtonAction:^{
+                    
+                } rightButtonAction:^{
+                    [weakSelf downloadWithParm:parm];
+                }];
+                [self.wifiAlert showAlert];
+            }
+            else {
+                [self downloadWithParm:parm];
+            }
+        }
+    }
+    else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cancelDownloadCourseware"]) { // 取消下载课件
+        if (COURSEWARE_MANAGER.isDownloading) { // 如果在下载 取消
+            [COURSEWARE_MANAGER cancleDownloadCourseware];
+        }
+        NSMutableDictionary *content = [NSMutableDictionary dictionaryWithDictionary:[parm ks_dictionaryValueForKey:@"content"]];
+        [content setValue:@(YES) forKey:@"status"];
+        NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
+        [sendParm setValue:@"cancelDownloadCourseware" forKey:@"api"];
+        [sendParm setValue:content forKey:@"content"];
+        [self postMessage:sendParm];
+    }
+}
+
+- (void)downloadWithParm:(NSDictionary *)parm {
+    MJWeakSelf;
+    [COURSEWARE_MANAGER downloadCourseWithParm:parm callback:^(NSDictionary * _Nonnull sendParm) {
+        [weakSelf postMessage:sendParm];
+    }];
 }
 
 - (void)videCropImage:(UIImage *)cover content:(NSDictionary *)content {

+ 4 - 4
KulexiuForTeacher/KulexiuForTeacher/Common/MediaMerge/AudioMerge/KSNewAlertView.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
     <device id="retina6_12" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -55,12 +55,13 @@
                         </button>
                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hO7-EM-ujs">
                             <rect key="frame" x="165" y="109.33333333333337" width="135" height="40"/>
+                            <color key="backgroundColor" red="0.1764705882352941" green="0.7803921568627451" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
                             <constraints>
                                 <constraint firstAttribute="height" constant="40" id="bbj-dv-61F"/>
                             </constraints>
                             <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
                             <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
-                            <state key="normal" title="确认" backgroundImage="sureButton_img"/>
+                            <state key="normal" title="确认"/>
                             <userDefinedRuntimeAttributes>
                                 <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
                                     <real key="value" value="20"/>
@@ -118,7 +119,6 @@
         </view>
     </objects>
     <resources>
-        <image name="sureButton_img" width="122" height="40"/>
         <systemColor name="systemBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
         </systemColor>

+ 3 - 0
KulexiuForTeacher/Podfile

@@ -63,6 +63,9 @@ install! 'cocoapods', :disable_input_output_paths => true
     pod 'TXLiteAVSDK_Professional'
     # 腾讯云存储
     pod 'QCloudCOSXML/Transfer'
+    
+    pod 'CocoaHTTPServer'
+    
   # Pods for KulexiuForTeacher b
 
 

+ 15 - 1
KulexiuForTeacher/Podfile.lock

@@ -16,6 +16,13 @@ PODS:
     - AFNetworking/NSURLSession
   - AlipaySDK-iOS (15.8.8)
   - Bugly (2.5.91)
+  - CocoaAsyncSocket (7.6.5)
+  - CocoaHTTPServer (2.4):
+    - CocoaAsyncSocket
+    - CocoaLumberjack
+  - CocoaLumberjack (3.8.5):
+    - CocoaLumberjack/Core (= 3.8.5)
+  - CocoaLumberjack/Core (3.8.5)
   - iOS-KS3SDK (1.0.5)
   - IQKeyboardManager (6.5.9)
   - JCore (2.7.1-noidfa)
@@ -258,6 +265,7 @@ DEPENDENCIES:
   - AFNetworking (~> 4.0)
   - AlipaySDK-iOS
   - Bugly
+  - CocoaHTTPServer
   - iOS-KS3SDK (~> 1.0.5)
   - IQKeyboardManager
   - JCore (= 2.7.1-noidfa)
@@ -289,6 +297,9 @@ SPEC REPOS:
     - AFNetworking
     - AlipaySDK-iOS
     - Bugly
+    - CocoaAsyncSocket
+    - CocoaHTTPServer
+    - CocoaLumberjack
     - iOS-KS3SDK
     - IQKeyboardManager
     - JCore
@@ -326,6 +337,9 @@ SPEC CHECKSUMS:
   AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58
   AlipaySDK-iOS: 9289d94792535cd14c5c241c720a7e981edd7035
   Bugly: afe841bba2ea6de6d432a3c125240a5e75949c55
+  CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
+  CocoaHTTPServer: 71538be9be526cf950cb4d9c9465153ea45cac99
+  CocoaLumberjack: 6a459bc897d6d80bd1b8c78482ec7ad05dffc3f0
   iOS-KS3SDK: 688f6c6a3b91af8e0bd0bd9c1e727cd5315293dd
   IQKeyboardManager: 241cc94ccabc9deb8f8bd7d12f00d73288d13ecc
   JCore: b9d49b2e5364cce65dec86056c60b1b72825893a
@@ -359,6 +373,6 @@ SPEC CHECKSUMS:
   Whiteboard: 4622f3866b7c35a9c757955619ba0a2b26d968f5
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
 
-PODFILE CHECKSUM: 3e4b6ce7c042c7295fa47cbcf0447dcb76f188d4
+PODFILE CHECKSUM: 409015a7b6d294d1b0057c9e5290353dee49a410
 
 COCOAPODS: 1.15.2

+ 15 - 1
KulexiuForTeacher/Pods/Manifest.lock

@@ -16,6 +16,13 @@ PODS:
     - AFNetworking/NSURLSession
   - AlipaySDK-iOS (15.8.8)
   - Bugly (2.5.91)
+  - CocoaAsyncSocket (7.6.5)
+  - CocoaHTTPServer (2.4):
+    - CocoaAsyncSocket
+    - CocoaLumberjack
+  - CocoaLumberjack (3.8.5):
+    - CocoaLumberjack/Core (= 3.8.5)
+  - CocoaLumberjack/Core (3.8.5)
   - iOS-KS3SDK (1.0.5)
   - IQKeyboardManager (6.5.9)
   - JCore (2.7.1-noidfa)
@@ -258,6 +265,7 @@ DEPENDENCIES:
   - AFNetworking (~> 4.0)
   - AlipaySDK-iOS
   - Bugly
+  - CocoaHTTPServer
   - iOS-KS3SDK (~> 1.0.5)
   - IQKeyboardManager
   - JCore (= 2.7.1-noidfa)
@@ -289,6 +297,9 @@ SPEC REPOS:
     - AFNetworking
     - AlipaySDK-iOS
     - Bugly
+    - CocoaAsyncSocket
+    - CocoaHTTPServer
+    - CocoaLumberjack
     - iOS-KS3SDK
     - IQKeyboardManager
     - JCore
@@ -326,6 +337,9 @@ SPEC CHECKSUMS:
   AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58
   AlipaySDK-iOS: 9289d94792535cd14c5c241c720a7e981edd7035
   Bugly: afe841bba2ea6de6d432a3c125240a5e75949c55
+  CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
+  CocoaHTTPServer: 71538be9be526cf950cb4d9c9465153ea45cac99
+  CocoaLumberjack: 6a459bc897d6d80bd1b8c78482ec7ad05dffc3f0
   iOS-KS3SDK: 688f6c6a3b91af8e0bd0bd9c1e727cd5315293dd
   IQKeyboardManager: 241cc94ccabc9deb8f8bd7d12f00d73288d13ecc
   JCore: b9d49b2e5364cce65dec86056c60b1b72825893a
@@ -359,6 +373,6 @@ SPEC CHECKSUMS:
   Whiteboard: 4622f3866b7c35a9c757955619ba0a2b26d968f5
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
 
-PODFILE CHECKSUM: 3e4b6ce7c042c7295fa47cbcf0447dcb76f188d4
+PODFILE CHECKSUM: 409015a7b6d294d1b0057c9e5290353dee49a410
 
 COCOAPODS: 1.15.2

File diff suppressed because it is too large
+ 4533 - 4305
KulexiuForTeacher/Pods/Pods.xcodeproj/project.pbxproj


+ 20 - 0
KulexiuForTeacher/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -19,6 +19,26 @@
 			<key>isShown</key>
 			<false/>
 		</dict>
+		<key>CocoaAsyncSocket.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
+		<key>CocoaHTTPServer.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
+		<key>CocoaLumberjack-CocoaLumberjackPrivacy.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
+		<key>CocoaLumberjack.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
 		<key>IQKeyboardManager.xcscheme</key>
 		<dict>
 			<key>isShown</key>

+ 49 - 0
KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher-acknowledgements.markdown

@@ -54,6 +54,55 @@ SOFTWARE.
 Copyright (C) 2017 Tencent Bugly, Inc. All rights reserved.
 
 
+## CocoaAsyncSocket
+
+Public Domain License
+
+The CocoaAsyncSocket project is in the public domain.
+
+The original TCP version (AsyncSocket) was created by Dustin Voss in January 2003.
+Updated and maintained by Deusty LLC and the Apple development community.
+
+
+## CocoaHTTPServer
+
+Software License Agreement (BSD License)
+
+Copyright (c) 2011, Deusty, LLC
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Neither the name of Deusty nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of Deusty, LLC.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+## CocoaLumberjack
+
+BSD 3-Clause License
+
+Copyright (c) 2010-2024, Deusty, LLC
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of Deusty nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of Deusty, LLC.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
 ## IQKeyboardManager
 
 MIT License

+ 67 - 0
KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher-acknowledgements.plist

@@ -85,6 +85,73 @@ SOFTWARE.
 		</dict>
 		<dict>
 			<key>FooterText</key>
+			<string>Public Domain License
+
+The CocoaAsyncSocket project is in the public domain.
+
+The original TCP version (AsyncSocket) was created by Dustin Voss in January 2003.
+Updated and maintained by Deusty LLC and the Apple development community.
+</string>
+			<key>License</key>
+			<string>public domain</string>
+			<key>Title</key>
+			<string>CocoaAsyncSocket</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>Software License Agreement (BSD License)
+
+Copyright (c) 2011, Deusty, LLC
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Neither the name of Deusty nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of Deusty, LLC.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</string>
+			<key>License</key>
+			<string>BSD</string>
+			<key>Title</key>
+			<string>CocoaHTTPServer</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>BSD 3-Clause License
+
+Copyright (c) 2010-2024, Deusty, LLC
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of Deusty nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of Deusty, LLC.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+</string>
+			<key>License</key>
+			<string>BSD</string>
+			<key>Title</key>
+			<string>CocoaLumberjack</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
 			<string>MIT License
 
 Copyright (c) 2013-2017 Iftekhar Qurashi

+ 4 - 0
KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher-resources.sh

@@ -98,6 +98,7 @@ EOM
 }
 if [[ "$CONFIGURATION" == "Debug" ]]; then
   install_resource "${PODS_ROOT}/AlipaySDK-iOS/AlipaySDK.bundle"
+  install_resource "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack/CocoaLumberjackPrivacy.bundle"
   install_resource "${PODS_ROOT}/MJRefresh/MJRefresh/MJRefresh.bundle"
   install_resource "${PODS_ROOT}/RSKImageCropper/RSKImageCropper/RSKImageCropperStrings.bundle"
   install_resource "${PODS_ROOT}/TIMCommon/TIMCommon/Resources/TIMCommon.bundle"
@@ -126,6 +127,7 @@ if [[ "$CONFIGURATION" == "Debug" ]]; then
 fi
 if [[ "$CONFIGURATION" == "DEV" ]]; then
   install_resource "${PODS_ROOT}/AlipaySDK-iOS/AlipaySDK.bundle"
+  install_resource "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack/CocoaLumberjackPrivacy.bundle"
   install_resource "${PODS_ROOT}/MJRefresh/MJRefresh/MJRefresh.bundle"
   install_resource "${PODS_ROOT}/RSKImageCropper/RSKImageCropper/RSKImageCropperStrings.bundle"
   install_resource "${PODS_ROOT}/TIMCommon/TIMCommon/Resources/TIMCommon.bundle"
@@ -154,6 +156,7 @@ if [[ "$CONFIGURATION" == "DEV" ]]; then
 fi
 if [[ "$CONFIGURATION" == "TEST" ]]; then
   install_resource "${PODS_ROOT}/AlipaySDK-iOS/AlipaySDK.bundle"
+  install_resource "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack/CocoaLumberjackPrivacy.bundle"
   install_resource "${PODS_ROOT}/MJRefresh/MJRefresh/MJRefresh.bundle"
   install_resource "${PODS_ROOT}/RSKImageCropper/RSKImageCropper/RSKImageCropperStrings.bundle"
   install_resource "${PODS_ROOT}/TIMCommon/TIMCommon/Resources/TIMCommon.bundle"
@@ -182,6 +185,7 @@ if [[ "$CONFIGURATION" == "TEST" ]]; then
 fi
 if [[ "$CONFIGURATION" == "Release" ]]; then
   install_resource "${PODS_ROOT}/AlipaySDK-iOS/AlipaySDK.bundle"
+  install_resource "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack/CocoaLumberjackPrivacy.bundle"
   install_resource "${PODS_ROOT}/MJRefresh/MJRefresh/MJRefresh.bundle"
   install_resource "${PODS_ROOT}/RSKImageCropper/RSKImageCropper/RSKImageCropperStrings.bundle"
   install_resource "${PODS_ROOT}/TIMCommon/TIMCommon/Resources/TIMCommon.bundle"

File diff suppressed because it is too large
+ 1 - 2
KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher.debug.xcconfig


File diff suppressed because it is too large
+ 1 - 2
KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher.release.xcconfig


Some files were not shown because too many files changed in this diff