Browse Source

更新whiteBoard SDK

Steven 2 years ago
parent
commit
9748113bbb
96 changed files with 2696 additions and 3899 deletions
  1. 4 4
      KulexiuForTeacher/KulexiuForTeacher.xcodeproj/project.pbxproj
  2. BIN
      KulexiuForTeacher/KulexiuForTeacher.xcworkspace/xcuserdata/wangzhi.xcuserdatad/UserInterfaceState.xcuserstate
  3. 1 17
      KulexiuForTeacher/KulexiuForTeacher.xcworkspace/xcuserdata/wangzhi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  4. 1 1
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSBaseWKWebViewController.m
  5. 2 2
      KulexiuForTeacher/KulexiuForTeacher/Module/Classroom/View/CloseCourse/KSCloseCourseView.xib
  6. 4 1
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/AccompanyCourse/Controller/AccompanyDetailViewController.m
  7. 3 5
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/Controller/CourseViewController.m
  8. 6 2
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/MusicRoom/Controller/MusicRoomViewController.m
  9. 1 1
      KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/MyLessonBodyView.m
  10. 1 1
      KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/MyMusicRoomBodyView.m
  11. 1 3
      KulexiuForTeacher/KulexiuForTeacher/Module/SealClass/Sections/NewWhiteboard/KSWhiteboardView.m
  12. 0 0
      KulexiuForTeacher/KulexiuForTeacher/Module/SealClass/Services/Classroom/ClassroomService.m
  13. 3 3
      KulexiuForTeacher/KulexiuForTeacher/Module/SealClass/Services/Classroom/Message/ControlDeviceNotifyMessage.h
  14. 21 21
      KulexiuForTeacher/Podfile.lock
  15. 1 1
      KulexiuForTeacher/Pods/Headers/Private/Whiteboard/WhiteConversionInfo.h
  16. 1 1
      KulexiuForTeacher/Pods/Headers/Private/Whiteboard/WhiteConverter.h
  17. 0 1
      KulexiuForTeacher/Pods/Headers/Private/dsBridge/DSCallInfo.h
  18. 0 1
      KulexiuForTeacher/Pods/Headers/Private/dsBridge/DWKWebView.h
  19. 0 1
      KulexiuForTeacher/Pods/Headers/Private/dsBridge/InternalApis.h
  20. 0 1
      KulexiuForTeacher/Pods/Headers/Private/dsBridge/JSBUtil.h
  21. 0 1
      KulexiuForTeacher/Pods/Headers/Private/dsBridge/dsbridge.h
  22. 1 1
      KulexiuForTeacher/Pods/Headers/Public/Whiteboard/WhiteConversionInfo.h
  23. 1 1
      KulexiuForTeacher/Pods/Headers/Public/Whiteboard/WhiteConverter.h
  24. 0 1
      KulexiuForTeacher/Pods/Headers/Public/dsBridge/DSCallInfo.h
  25. 0 1
      KulexiuForTeacher/Pods/Headers/Public/dsBridge/DWKWebView.h
  26. 0 1
      KulexiuForTeacher/Pods/Headers/Public/dsBridge/InternalApis.h
  27. 0 1
      KulexiuForTeacher/Pods/Headers/Public/dsBridge/JSBUtil.h
  28. 0 1
      KulexiuForTeacher/Pods/Headers/Public/dsBridge/dsbridge.h
  29. 21 21
      KulexiuForTeacher/Pods/Manifest.lock
  30. 1841 1789
      KulexiuForTeacher/Pods/Pods.xcodeproj/project.pbxproj
  31. 5 57
      KulexiuForTeacher/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/xcschememanagement.plist
  32. 25 0
      KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher-acknowledgements.markdown
  33. 31 0
      KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher-acknowledgements.plist
  34. 4 4
      KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher.debug.xcconfig
  35. 4 4
      KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher.release.xcconfig
  36. 1 1
      KulexiuForTeacher/Pods/Target Support Files/Whiteboard/ResourceBundle-Whiteboard-Whiteboard-Info.plist
  37. 1 1
      KulexiuForTeacher/Pods/Target Support Files/Whiteboard/Whiteboard.debug.xcconfig
  38. 1 1
      KulexiuForTeacher/Pods/Target Support Files/Whiteboard/Whiteboard.release.xcconfig
  39. 0 5
      KulexiuForTeacher/Pods/Target Support Files/dsBridge/dsBridge-dummy.m
  40. 0 12
      KulexiuForTeacher/Pods/Target Support Files/dsBridge/dsBridge-prefix.pch
  41. 0 12
      KulexiuForTeacher/Pods/Target Support Files/dsBridge/dsBridge.debug.xcconfig
  42. 0 12
      KulexiuForTeacher/Pods/Target Support Files/dsBridge/dsBridge.release.xcconfig
  43. 116 13
      KulexiuForTeacher/Pods/Whiteboard/README-zh.md
  44. 0 68
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Converter/WhiteConversionInfo.h
  45. 0 45
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Converter/WhiteConversionInfo.m
  46. 0 132
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Converter/WhiteConverter.h
  47. 0 358
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Converter/WhiteConverter.m
  48. 5 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteBoardView.h
  49. 7 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteBoardView.m
  50. 15 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteDisplayer.h
  51. 23 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteDisplayer.m
  52. 4 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteDisplayerState.h
  53. 13 2
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteDisplayerState.m
  54. 1 2
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Model/WhiteObject.h
  55. 0 5
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Model/WhiteObject.m
  56. 12 3
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/NativeReplayer/WhiteCombinePlayer.h
  57. 41 20
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/NativeReplayer/WhiteCombinePlayer.m
  58. 21 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteAppParam.h
  59. 28 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteAppParam.m
  60. 1 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteCameraBound.h
  61. 4 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhitePptPage.h
  62. 2 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhitePptPage.m
  63. 1 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteSceneState.h
  64. 7 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteWindowParams.m
  65. 31 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Replayer/WhitePlayer.h
  66. 10 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Replayer/WhitePlayer.m
  67. 5 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoom+Private.h
  68. 108 5
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoom.h
  69. 134 5
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoom.m
  70. 24 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoomConfig.h
  71. 12 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoomConfig.m
  72. 36 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteSDK+Room.m
  73. 9 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSDK.h
  74. 26 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSDK.m
  75. 1 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSdkConfiguration+Private.h
  76. 5 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSdkConfiguration.h
  77. 4 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSdkConfiguration.m
  78. 3 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Whiteboard.h
  79. 0 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/f17ecb7
  80. 1 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/index.html
  81. 0 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/main.419dbe84.js
  82. 0 1
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/main.css
  83. 0 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/netless.3d40c396.js
  84. 0 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/vendor.7dc7ced9.js
  85. 0 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/vendor.css
  86. 0 0
      KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/web-sdk.47b8d54d.js
  87. 0 8
      KulexiuForTeacher/Pods/dsBridge/dsbridge/DSCallInfo.h
  88. 0 13
      KulexiuForTeacher/Pods/dsBridge/dsbridge/DSCallInfo.m
  89. 0 54
      KulexiuForTeacher/Pods/dsBridge/dsbridge/DWKWebView.h
  90. 0 488
      KulexiuForTeacher/Pods/dsBridge/dsbridge/DWKWebView.m
  91. 0 8
      KulexiuForTeacher/Pods/dsBridge/dsbridge/InternalApis.h
  92. 0 25
      KulexiuForTeacher/Pods/dsBridge/dsbridge/InternalApis.m
  93. 0 17
      KulexiuForTeacher/Pods/dsBridge/dsbridge/JSBUtil.h
  94. 0 105
      KulexiuForTeacher/Pods/dsBridge/dsbridge/JSBUtil.m
  95. 0 4
      KulexiuForTeacher/Pods/dsBridge/dsbridge/dsbridge.h
  96. 0 515
      KulexiuForTeacher/Pods/dsBridge/readme-chs.md

+ 4 - 4
KulexiuForTeacher/KulexiuForTeacher.xcodeproj/project.pbxproj

@@ -779,7 +779,7 @@
 		BCC9F44627F69BD200647449 /* RoomMember.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC9F3F827F69BD200647449 /* RoomMember.m */; };
 		BCC9F44727F69BD200647449 /* ClassSongMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC9F3F927F69BD200647449 /* ClassSongMessage.m */; };
 		BCC9F44827F69BD200647449 /* Classroom.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC9F3FA27F69BD200647449 /* Classroom.m */; };
-		BCC9F44927F69BD200647449 /* x.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC9F40027F69BD200647449 /* x.m */; };
+		BCC9F44927F69BD200647449 /* ClassroomService.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC9F40027F69BD200647449 /* ClassroomService.m */; };
 		BCC9F44A27F69BD200647449 /* RTCService.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC9F40227F69BD200647449 /* RTCService.m */; };
 		BCC9F44B27F69BD200647449 /* KSIMService.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC9F40627F69BD200647449 /* KSIMService.m */; };
 		BCD457A5286319660010B493 /* CourseTimeSegView.m in Sources */ = {isa = PBXBuildFile; fileRef = BCD457A4286319660010B493 /* CourseTimeSegView.m */; };
@@ -2267,7 +2267,7 @@
 		BCC9F3FD27F69BD200647449 /* ClassSongMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClassSongMessage.h; sourceTree = "<group>"; };
 		BCC9F3FE27F69BD200647449 /* RoomMember.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMember.h; sourceTree = "<group>"; };
 		BCC9F3FF27F69BD200647449 /* ClassroomDefine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClassroomDefine.h; sourceTree = "<group>"; };
-		BCC9F40027F69BD200647449 /* x.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = x.m; sourceTree = "<group>"; };
+		BCC9F40027F69BD200647449 /* ClassroomService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ClassroomService.m; sourceTree = "<group>"; };
 		BCC9F40227F69BD200647449 /* RTCService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RTCService.m; sourceTree = "<group>"; };
 		BCC9F40327F69BD200647449 /* RTCService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCService.h; sourceTree = "<group>"; };
 		BCC9F40527F69BD200647449 /* KSIMService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSIMService.h; sourceTree = "<group>"; };
@@ -5825,7 +5825,7 @@
 			children = (
 				BCC9F3FF27F69BD200647449 /* ClassroomDefine.h */,
 				BCC9F3D227F69BD200647449 /* ClassroomService.h */,
-				BCC9F40027F69BD200647449 /* x.m */,
+				BCC9F40027F69BD200647449 /* ClassroomService.m */,
 				BCC9F3D327F69BD200647449 /* Message */,
 				BCC9F3F627F69BD200647449 /* Model */,
 			);
@@ -6739,7 +6739,7 @@
 				BC5EB5C42804087000B4A3B0 /* MyStyleBottomView.m in Sources */,
 				275E3DE027F467410010EC30 /* KSChatEmojiBoardView.m in Sources */,
 				BC542E4628407B3D00633781 /* UseBodyView.m in Sources */,
-				BCC9F44927F69BD200647449 /* x.m in Sources */,
+				BCC9F44927F69BD200647449 /* ClassroomService.m in Sources */,
 				277931CC27E30FC20010E277 /* KSGifRefreshFooter.m in Sources */,
 				2779321127E30FC30010E277 /* YKMultiLevelTableView.m in Sources */,
 				BCF1BA5127F5C4DD00FA36C4 /* KSLiveChatroomMemberCount.m in Sources */,

BIN
KulexiuForTeacher/KulexiuForTeacher.xcworkspace/xcuserdata/wangzhi.xcuserdatad/UserInterfaceState.xcuserstate


+ 1 - 17
KulexiuForTeacher/KulexiuForTeacher.xcworkspace/xcuserdata/wangzhi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -324,7 +324,7 @@
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
             uuid = "4447F7D7-1B25-4FBA-9799-D9760D200B63"
-            shouldBeEnabled = "Yes"
+            shouldBeEnabled = "No"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "KulexiuForTeacher/Module/SealClass/Sections/NewWhiteboard/WhiteUtils.m"
@@ -616,22 +616,6 @@
       <BreakpointProxy
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "289E6237-EF1C-4ACF-8BFF-6855E14AF4C6"
-            shouldBeEnabled = "Yes"
-            ignoreCount = "0"
-            continueAfterRunningActions = "No"
-            filePath = "KulexiuForTeacher/Module/SealClass/Services/Classroom/ClassroomService.m"
-            startingColumnNumber = "9223372036854775807"
-            endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "220"
-            endingLineNumber = "220"
-            landmarkName = "-queryNoJoinRoomList:"
-            landmarkType = "7">
-         </BreakpointContent>
-      </BreakpointProxy>
-      <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
-         <BreakpointContent
             uuid = "A2B1BE97-A470-4E36-A860-CEC997E807A0"
             shouldBeEnabled = "No"
             ignoreCount = "0"

+ 1 - 1
KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSBaseWKWebViewController.m

@@ -526,7 +526,7 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
         }
         else if ([[valueDic stringValueForKey:@"type"] isEqualToString:@"multi"]) { // 群聊
             if ([NSString isEmptyString:targetId]) {
-                [self MBPShow:@"群组id不存在"];
+                [self MBPShow:@"报名未结束,暂无群组"];
                 return;
             }
             KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];

+ 2 - 2
KulexiuForTeacher/KulexiuForTeacher/Module/Classroom/View/CloseCourse/KSCloseCourseView.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina6_1" orientation="landscape" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>

+ 4 - 1
KulexiuForTeacher/KulexiuForTeacher/Module/Course/AccompanyCourse/Controller/AccompanyDetailViewController.m

@@ -57,7 +57,6 @@
     // Do any additional setup after loading the view.
     self.ks_prefersNavigationBarHidden = YES;
     [self configUI];
-    [self requestCourseInfoMessage];
 }
 
 - (void)requestCourseInfoMessage {
@@ -66,6 +65,10 @@
     [self requestRoomConfig];
 }
 
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    [self requestCourseInfoMessage];
+}
 
 - (void)requestRoomConfig {
     [KSNetworkingManager selectRoomConfigRequest:KS_GET success:^(NSDictionary * _Nonnull dic) {

+ 3 - 5
KulexiuForTeacher/KulexiuForTeacher/Module/Course/Controller/CourseViewController.m

@@ -582,10 +582,8 @@
     switch (action) {
         case LIVECOURSEACTION_CHAT:  // 聊天
         {
-            if ([NSString isEmptyString:source.imGroupId]) {
-                return;
-            }
-            [self chatAction:source.imGroupId groupName:source.name isGroup:YES];
+
+            [self chatAction:source.imGroupId groupName:@"" isGroup:YES];
         }
             break;
         case LIVECOURSEACTION_LIVEROOM: // 直播课上课
@@ -600,7 +598,7 @@
 
 - (void)chatAction:(NSString *)targetId groupName:(NSString *)targetName isGroup:(BOOL)isGroup {
     if ([NSString isEmptyString:targetId] && isGroup) {
-        [self MBPShow:@"群组id不存在"];
+        [self MBPShow:@"报名未结束,暂无群组"];
         return;
     }
     KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];

+ 6 - 2
KulexiuForTeacher/KulexiuForTeacher/Module/Course/MusicRoom/Controller/MusicRoomViewController.m

@@ -48,7 +48,6 @@
     // Do any additional setup after loading the view.
     [self allocTitle:@"课程详情"];
     [self configUI];
-    [self requestCourseInfoMessage];
 }
 
 - (void)configUI {
@@ -60,6 +59,11 @@
     }];
 }
 
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    [self requestCourseInfoMessage];
+}
+
 - (void)requestCourseInfoMessage {
     [self requestStudentList];
     [self requestRoomConfig];
@@ -177,7 +181,7 @@
 
 - (void)chatAction:(NSString *)targetId {
     if ([NSString isEmptyString:targetId]) {
-        [self MBPShow:@"群组id不存在"];
+        [self MBPShow:@"报名未结束,暂无群组"];
         return;
     }
     KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];

+ 1 - 1
KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/MyLessonBodyView.m

@@ -465,7 +465,7 @@
 
 - (void)chatAction:(NSString *)targetId {
     if ([NSString isEmptyString:targetId]) {
-        [self MBPShow:@"群组id不存在"];
+        [self MBPShow:@"报名未结束,暂无群组"];
         return;
     }
     KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];

+ 1 - 1
KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/MyMusicRoomBodyView.m

@@ -358,7 +358,7 @@
 
 - (void)chatAction:(NSString *)targetId {
     if ([NSString isEmptyString:targetId]) {
-        [self MBPShow:@"群组id不存在"];
+        [self MBPShow:@"报名未结束,暂无群组"];
         return;
     }
     KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];

+ 1 - 3
KulexiuForTeacher/KulexiuForTeacher/Module/SealClass/Sections/NewWhiteboard/KSWhiteboardView.m

@@ -613,9 +613,7 @@
 
 - (void)joinRoomWithToken:(NSString *)roomToken
 {
-    
-    NSDictionary *payload = @{@"avatar": @"https://white-pan.oss-cn-shanghai.aliyuncs.com/40/image/mask.jpg"};
-    WhiteRoomConfig *roomConfig = [[WhiteRoomConfig alloc] initWithUUID:self.roomUuid roomToken:roomToken uid:UserDefault(UIDKey) userPayload:payload];
+    WhiteRoomConfig *roomConfig = [[WhiteRoomConfig alloc] initWithUUID:self.roomUuid roomToken:roomToken uid:UserDefault(UIDKey) userPayload:nil];
     roomConfig.disableEraseImage = YES;
     
     [self.sdk joinRoomWithConfig:roomConfig callbacks:self.roomCallbackDelegate completionHandler:^(BOOL success, WhiteRoom * _Nonnull room, NSError * _Nonnull error) {

+ 0 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/SealClass/Services/Classroom/x.m → KulexiuForTeacher/KulexiuForTeacher/Module/SealClass/Services/Classroom/ClassroomService.m


+ 3 - 3
KulexiuForTeacher/KulexiuForTeacher/Module/SealClass/Services/Classroom/Message/ControlDeviceNotifyMessage.h

@@ -11,11 +11,11 @@
 
 typedef NS_ENUM(NSUInteger, ControlDeviceAction) {
     //邀请
-    ControlDeviceActionInvite = 1,
+    ControlDeviceActionInvite = 0,
     //拒绝
-    ControlDeviceActionReject = 2,
+    ControlDeviceActionReject = 1,
     //同意
-    ControlDeviceActionApprove = 3
+    ControlDeviceActionApprove = 2
 };
 
 NS_ASSUME_NONNULL_BEGIN

+ 21 - 21
KulexiuForTeacher/Podfile.lock

@@ -16,7 +16,6 @@ PODS:
     - AFNetworking/NSURLSession
   - AlipaySDK-iOS (15.8.8)
   - Bugly (2.5.91)
-  - dsBridge (3.0.6)
   - iOS-KS3SDK (1.0.5)
   - IQKeyboardManager (6.5.9)
   - JCore (2.7.1-noidfa)
@@ -28,6 +27,7 @@ PODS:
   - MBProgressHUD (1.2.0)
   - MJExtension (3.3.0)
   - MJRefresh (3.1.17)
+  - NTLBridge (3.1.2)
   - Reachability (3.2)
   - RongCloudIM/ChatRoom (5.2.3):
     - RongCloudIM/IMLibCore
@@ -62,29 +62,29 @@ PODS:
   - SocketRocket (0.6.0)
   - SSZipArchive (2.4.3)
   - TYCyclePagerView (1.2.0)
-  - Whiteboard (2.16.0):
-    - Whiteboard/Base (= 2.16.0)
-    - Whiteboard/Converter (= 2.16.0)
-    - Whiteboard/Model (= 2.16.0)
-    - Whiteboard/NativeReplayer (= 2.16.0)
-    - Whiteboard/Object (= 2.16.0)
-    - Whiteboard/Replayer (= 2.16.0)
-    - Whiteboard/Room (= 2.16.0)
-  - Whiteboard/Base (2.16.0):
-    - dsBridge (~> 3.0.2)
+  - Whiteboard (2.16.27):
+    - Whiteboard/Whiteboard-YYModel (= 2.16.27)
+  - Whiteboard/Base (2.16.27):
+    - NTLBridge (~> 3.1.2)
     - Whiteboard/Object
-  - Whiteboard/Converter (2.16.0):
+  - Whiteboard/Converter (2.16.27):
     - Whiteboard/Object
-  - Whiteboard/Model (2.16.0):
-    - YYModel (~> 1.0.4)
-  - Whiteboard/NativeReplayer (2.16.0):
+  - Whiteboard/Model (2.16.27):
+    - YYModel
+  - Whiteboard/NativeReplayer (2.16.27):
     - Whiteboard/Replayer
-  - Whiteboard/Object (2.16.0):
+  - Whiteboard/Object (2.16.27):
     - Whiteboard/Model
-  - Whiteboard/Replayer (2.16.0):
+  - Whiteboard/Replayer (2.16.27):
     - Whiteboard/Base
-  - Whiteboard/Room (2.16.0):
+  - Whiteboard/Resource (2.16.27)
+  - Whiteboard/Room (2.16.27):
     - Whiteboard/Base
+  - Whiteboard/Whiteboard-YYModel (2.16.27):
+    - Whiteboard/Converter
+    - Whiteboard/NativeReplayer
+    - Whiteboard/Resource
+    - Whiteboard/Room
   - YYModel (1.0.4)
 
 DEPENDENCIES:
@@ -119,7 +119,6 @@ SPEC REPOS:
     - AFNetworking
     - AlipaySDK-iOS
     - Bugly
-    - dsBridge
     - iOS-KS3SDK
     - IQKeyboardManager
     - JCore
@@ -130,6 +129,7 @@ SPEC REPOS:
     - MBProgressHUD
     - MJExtension
     - MJRefresh
+    - NTLBridge
     - Reachability
     - RongCloudIM
     - RongCloudRTC
@@ -145,7 +145,6 @@ SPEC CHECKSUMS:
   AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
   AlipaySDK-iOS: 9289d94792535cd14c5c241c720a7e981edd7035
   Bugly: afe841bba2ea6de6d432a3c125240a5e75949c55
-  dsBridge: 48b62ee8a411ad601a88d6f6c8cf6cb634b206b7
   iOS-KS3SDK: 688f6c6a3b91af8e0bd0bd9c1e727cd5315293dd
   IQKeyboardManager: 241cc94ccabc9deb8f8bd7d12f00d73288d13ecc
   JCore: b9d49b2e5364cce65dec86056c60b1b72825893a
@@ -156,6 +155,7 @@ SPEC CHECKSUMS:
   MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406
   MJExtension: 01704cca2b60a214c10761b6491eab74069d68a9
   MJRefresh: ee5b68f639775462faba4db0fd243baf4d42c2cf
+  NTLBridge: b3433dc0dbe85c803e92a742328dc3119e331ed3
   Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
   RongCloudIM: be2941344f84bfa7ec6ea60e6379333a652bd8e3
   RongCloudRTC: 6b9921f0680b2d95742e21210ef6eb79722a2dd8
@@ -164,7 +164,7 @@ SPEC CHECKSUMS:
   SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
   SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
   TYCyclePagerView: 2b051dade0615c70784aa34f40c646feeddb7344
-  Whiteboard: 16568e7e14f7f451d2aad2536f5fab9c06119934
+  Whiteboard: dc3d59f1f826e6065bd054bf499650c829753aff
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
 
 PODFILE CHECKSUM: 0caee30b8f6bff6e69eccce77afbaa62f4038a98

+ 1 - 1
KulexiuForTeacher/Pods/Headers/Private/Whiteboard/WhiteConversionInfo.h

@@ -1 +1 @@
-../../../Whiteboard/Whiteboard/Classes/Converter/WhiteConversionInfo.h
+../../../Whiteboard/Whiteboard/Classes/Converter/V4/WhiteConversionInfo.h

+ 1 - 1
KulexiuForTeacher/Pods/Headers/Private/Whiteboard/WhiteConverter.h

@@ -1 +1 @@
-../../../Whiteboard/Whiteboard/Classes/Converter/WhiteConverter.h
+../../../Whiteboard/Whiteboard/Classes/Converter/V4/WhiteConverter.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Private/dsBridge/DSCallInfo.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/DSCallInfo.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Private/dsBridge/DWKWebView.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/DWKWebView.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Private/dsBridge/InternalApis.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/InternalApis.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Private/dsBridge/JSBUtil.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/JSBUtil.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Private/dsBridge/dsbridge.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/dsbridge.h

+ 1 - 1
KulexiuForTeacher/Pods/Headers/Public/Whiteboard/WhiteConversionInfo.h

@@ -1 +1 @@
-../../../Whiteboard/Whiteboard/Classes/Converter/WhiteConversionInfo.h
+../../../Whiteboard/Whiteboard/Classes/Converter/V4/WhiteConversionInfo.h

+ 1 - 1
KulexiuForTeacher/Pods/Headers/Public/Whiteboard/WhiteConverter.h

@@ -1 +1 @@
-../../../Whiteboard/Whiteboard/Classes/Converter/WhiteConverter.h
+../../../Whiteboard/Whiteboard/Classes/Converter/V4/WhiteConverter.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Public/dsBridge/DSCallInfo.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/DSCallInfo.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Public/dsBridge/DWKWebView.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/DWKWebView.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Public/dsBridge/InternalApis.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/InternalApis.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Public/dsBridge/JSBUtil.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/JSBUtil.h

+ 0 - 1
KulexiuForTeacher/Pods/Headers/Public/dsBridge/dsbridge.h

@@ -1 +0,0 @@
-../../../dsBridge/dsbridge/dsbridge.h

+ 21 - 21
KulexiuForTeacher/Pods/Manifest.lock

@@ -16,7 +16,6 @@ PODS:
     - AFNetworking/NSURLSession
   - AlipaySDK-iOS (15.8.8)
   - Bugly (2.5.91)
-  - dsBridge (3.0.6)
   - iOS-KS3SDK (1.0.5)
   - IQKeyboardManager (6.5.9)
   - JCore (2.7.1-noidfa)
@@ -28,6 +27,7 @@ PODS:
   - MBProgressHUD (1.2.0)
   - MJExtension (3.3.0)
   - MJRefresh (3.1.17)
+  - NTLBridge (3.1.2)
   - Reachability (3.2)
   - RongCloudIM/ChatRoom (5.2.3):
     - RongCloudIM/IMLibCore
@@ -62,29 +62,29 @@ PODS:
   - SocketRocket (0.6.0)
   - SSZipArchive (2.4.3)
   - TYCyclePagerView (1.2.0)
-  - Whiteboard (2.16.0):
-    - Whiteboard/Base (= 2.16.0)
-    - Whiteboard/Converter (= 2.16.0)
-    - Whiteboard/Model (= 2.16.0)
-    - Whiteboard/NativeReplayer (= 2.16.0)
-    - Whiteboard/Object (= 2.16.0)
-    - Whiteboard/Replayer (= 2.16.0)
-    - Whiteboard/Room (= 2.16.0)
-  - Whiteboard/Base (2.16.0):
-    - dsBridge (~> 3.0.2)
+  - Whiteboard (2.16.27):
+    - Whiteboard/Whiteboard-YYModel (= 2.16.27)
+  - Whiteboard/Base (2.16.27):
+    - NTLBridge (~> 3.1.2)
     - Whiteboard/Object
-  - Whiteboard/Converter (2.16.0):
+  - Whiteboard/Converter (2.16.27):
     - Whiteboard/Object
-  - Whiteboard/Model (2.16.0):
-    - YYModel (~> 1.0.4)
-  - Whiteboard/NativeReplayer (2.16.0):
+  - Whiteboard/Model (2.16.27):
+    - YYModel
+  - Whiteboard/NativeReplayer (2.16.27):
     - Whiteboard/Replayer
-  - Whiteboard/Object (2.16.0):
+  - Whiteboard/Object (2.16.27):
     - Whiteboard/Model
-  - Whiteboard/Replayer (2.16.0):
+  - Whiteboard/Replayer (2.16.27):
     - Whiteboard/Base
-  - Whiteboard/Room (2.16.0):
+  - Whiteboard/Resource (2.16.27)
+  - Whiteboard/Room (2.16.27):
     - Whiteboard/Base
+  - Whiteboard/Whiteboard-YYModel (2.16.27):
+    - Whiteboard/Converter
+    - Whiteboard/NativeReplayer
+    - Whiteboard/Resource
+    - Whiteboard/Room
   - YYModel (1.0.4)
 
 DEPENDENCIES:
@@ -119,7 +119,6 @@ SPEC REPOS:
     - AFNetworking
     - AlipaySDK-iOS
     - Bugly
-    - dsBridge
     - iOS-KS3SDK
     - IQKeyboardManager
     - JCore
@@ -130,6 +129,7 @@ SPEC REPOS:
     - MBProgressHUD
     - MJExtension
     - MJRefresh
+    - NTLBridge
     - Reachability
     - RongCloudIM
     - RongCloudRTC
@@ -145,7 +145,6 @@ SPEC CHECKSUMS:
   AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
   AlipaySDK-iOS: 9289d94792535cd14c5c241c720a7e981edd7035
   Bugly: afe841bba2ea6de6d432a3c125240a5e75949c55
-  dsBridge: 48b62ee8a411ad601a88d6f6c8cf6cb634b206b7
   iOS-KS3SDK: 688f6c6a3b91af8e0bd0bd9c1e727cd5315293dd
   IQKeyboardManager: 241cc94ccabc9deb8f8bd7d12f00d73288d13ecc
   JCore: b9d49b2e5364cce65dec86056c60b1b72825893a
@@ -156,6 +155,7 @@ SPEC CHECKSUMS:
   MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406
   MJExtension: 01704cca2b60a214c10761b6491eab74069d68a9
   MJRefresh: ee5b68f639775462faba4db0fd243baf4d42c2cf
+  NTLBridge: b3433dc0dbe85c803e92a742328dc3119e331ed3
   Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
   RongCloudIM: be2941344f84bfa7ec6ea60e6379333a652bd8e3
   RongCloudRTC: 6b9921f0680b2d95742e21210ef6eb79722a2dd8
@@ -164,7 +164,7 @@ SPEC CHECKSUMS:
   SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
   SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
   TYCyclePagerView: 2b051dade0615c70784aa34f40c646feeddb7344
-  Whiteboard: 16568e7e14f7f451d2aad2536f5fab9c06119934
+  Whiteboard: dc3d59f1f826e6065bd054bf499650c829753aff
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
 
 PODFILE CHECKSUM: 0caee30b8f6bff6e69eccce77afbaa62f4038a98

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


+ 5 - 57
KulexiuForTeacher/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -8,183 +8,131 @@
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>0</integer>
 		</dict>
 		<key>AlipaySDK-iOS.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>1</integer>
 		</dict>
 		<key>Bugly.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>2</integer>
 		</dict>
 		<key>IQKeyboardManager.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>5</integer>
 		</dict>
 		<key>JCore.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>6</integer>
 		</dict>
 		<key>JPush.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>7</integer>
 		</dict>
 		<key>JXCategoryView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>8</integer>
 		</dict>
 		<key>JXPagingView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>9</integer>
 		</dict>
 		<key>MBProgressHUD.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>11</integer>
 		</dict>
 		<key>MJExtension.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>12</integer>
 		</dict>
 		<key>MJRefresh.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>13</integer>
 		</dict>
 		<key>Masonry.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>10</integer>
+		</dict>
+		<key>NTLBridge.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
 		</dict>
 		<key>Pods-KulexiuForTeacher.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>14</integer>
 		</dict>
 		<key>RSKImageCropper.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>18</integer>
 		</dict>
 		<key>Reachability.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>15</integer>
 		</dict>
 		<key>RongCloudIM.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>16</integer>
 		</dict>
 		<key>RongCloudRTC.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>17</integer>
 		</dict>
 		<key>SDWebImage.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>19</integer>
 		</dict>
 		<key>SSZipArchive.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>21</integer>
 		</dict>
 		<key>SocketRocket.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>20</integer>
 		</dict>
 		<key>TYCyclePagerView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>22</integer>
 		</dict>
 		<key>Whiteboard-Whiteboard.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>24</integer>
 		</dict>
 		<key>Whiteboard.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>23</integer>
 		</dict>
 		<key>YYModel.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>25</integer>
-		</dict>
-		<key>dsBridge.xcscheme</key>
-		<dict>
-			<key>isShown</key>
-			<false/>
-			<key>orderHint</key>
-			<integer>3</integer>
 		</dict>
 		<key>iOS-KS3SDK.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
-			<key>orderHint</key>
-			<integer>4</integer>
 		</dict>
 	</dict>
 	<key>SuppressBuildableAutocreation</key>

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

@@ -227,6 +227,31 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 
+## NTLBridge
+
+MIT License
+
+Copyright (c) 2022 netless
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
 ## RSKImageCropper
 
 Copyright (c) 2014 Ruslan Skorb, http://lnkd.in/gsBbvb

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

@@ -312,6 +312,37 @@ THE SOFTWARE.</string>
 		</dict>
 		<dict>
 			<key>FooterText</key>
+			<string>MIT License
+
+Copyright (c) 2022 netless
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>NTLBridge</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
 			<string>Copyright (c) 2014 Ruslan Skorb, http://lnkd.in/gsBbvb
 
 Permission is hereby granted, free of charge, to any person obtaining a copy

+ 4 - 4
KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher.debug.xcconfig

@@ -2,11 +2,11 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
 EXCLUDED_ARCHS[sdk=iphonesimulator*] = arm64
 FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/AlipaySDK-iOS" "${PODS_ROOT}/Bugly" "${PODS_ROOT}/RongCloudIM/RongCloudIM" "${PODS_ROOT}/RongCloudRTC/RongCloudRTC" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/ChatRoom" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/CustomerService" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Discussion" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMKit" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLib" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLibCore" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Location" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/PublicService" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Sight" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongFaceBeautifier" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongRTCLib"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/IQKeyboardManager" "${PODS_ROOT}/Headers/Public/JPush" "${PODS_ROOT}/Headers/Public/JXCategoryView" "${PODS_ROOT}/Headers/Public/JXPagingView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MJExtension" "${PODS_ROOT}/Headers/Public/MJRefresh" "${PODS_ROOT}/Headers/Public/Masonry" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/Reachability" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SSZipArchive" "${PODS_ROOT}/Headers/Public/SocketRocket" "${PODS_ROOT}/Headers/Public/TYCyclePagerView" "${PODS_ROOT}/Headers/Public/Whiteboard" "${PODS_ROOT}/Headers/Public/YYModel" "${PODS_ROOT}/Headers/Public/dsBridge" "${PODS_ROOT}/Headers/Public/iOS-KS3SDK"
+HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/IQKeyboardManager" "${PODS_ROOT}/Headers/Public/JPush" "${PODS_ROOT}/Headers/Public/JXCategoryView" "${PODS_ROOT}/Headers/Public/JXPagingView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MJExtension" "${PODS_ROOT}/Headers/Public/MJRefresh" "${PODS_ROOT}/Headers/Public/Masonry" "${PODS_ROOT}/Headers/Public/NTLBridge" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/Reachability" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SSZipArchive" "${PODS_ROOT}/Headers/Public/SocketRocket" "${PODS_ROOT}/Headers/Public/TYCyclePagerView" "${PODS_ROOT}/Headers/Public/Whiteboard" "${PODS_ROOT}/Headers/Public/YYModel" "${PODS_ROOT}/Headers/Public/iOS-KS3SDK"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
-LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManager" "${PODS_CONFIGURATION_BUILD_DIR}/JXCategoryView" "${PODS_CONFIGURATION_BUILD_DIR}/JXPagingView" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/Reachability" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive" "${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket" "${PODS_CONFIGURATION_BUILD_DIR}/TYCyclePagerView" "${PODS_CONFIGURATION_BUILD_DIR}/Whiteboard" "${PODS_CONFIGURATION_BUILD_DIR}/YYModel" "${PODS_CONFIGURATION_BUILD_DIR}/dsBridge" "${PODS_CONFIGURATION_BUILD_DIR}/iOS-KS3SDK" "${PODS_ROOT}/JCore" "${PODS_ROOT}/JPush"
-OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_ROOT}/Headers/Public/SSZipArchive/SSZipArchive.modulemap" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/IQKeyboardManager" -isystem "${PODS_ROOT}/Headers/Public/JPush" -isystem "${PODS_ROOT}/Headers/Public/JXCategoryView" -isystem "${PODS_ROOT}/Headers/Public/JXPagingView" -isystem "${PODS_ROOT}/Headers/Public/MBProgressHUD" -isystem "${PODS_ROOT}/Headers/Public/MJExtension" -isystem "${PODS_ROOT}/Headers/Public/MJRefresh" -isystem "${PODS_ROOT}/Headers/Public/Masonry" -isystem "${PODS_ROOT}/Headers/Public/RSKImageCropper" -isystem "${PODS_ROOT}/Headers/Public/Reachability" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/SocketRocket" -isystem "${PODS_ROOT}/Headers/Public/TYCyclePagerView" -isystem "${PODS_ROOT}/Headers/Public/Whiteboard" -isystem "${PODS_ROOT}/Headers/Public/YYModel" -isystem "${PODS_ROOT}/Headers/Public/dsBridge" -isystem "${PODS_ROOT}/Headers/Public/iOS-KS3SDK" -iframework "${PODS_ROOT}/AlipaySDK-iOS" -iframework "${PODS_ROOT}/Bugly" -iframework "${PODS_ROOT}/RongCloudIM/RongCloudIM" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/ChatRoom" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/CustomerService" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Discussion" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMKit" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLib" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLibCore" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Location" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/PublicService" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Sight" -iframework "${PODS_ROOT}/RongCloudRTC/RongCloudRTC" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongFaceBeautifier" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongRTCLib"
-OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"IQKeyboardManager" -l"JXCategoryView" -l"JXPagingView" -l"MBProgressHUD" -l"MJExtension" -l"MJRefresh" -l"Masonry" -l"RSKImageCropper" -l"Reachability" -l"SDWebImage" -l"SSZipArchive" -l"SocketRocket" -l"TYCyclePagerView" -l"Whiteboard" -l"YYModel" -l"c++" -l"dsBridge" -l"iOS-KS3SDK" -l"iconv" -l"icucore" -l"jcore-noidfa-ios-2.7.1" -l"jpush-ios-4.3.0" -l"resolv" -l"z" -framework "AVFoundation" -framework "AlipaySDK" -framework "Bugly" -framework "CFNetwork" -framework "CoreFoundation" -framework "CoreGraphics" -framework "CoreMotion" -framework "CoreTelephony" -framework "CoreText" -framework "Foundation" -framework "GLKit" -framework "ImageIO" -framework "QuartzCore" -framework "RongChatRoom" -framework "RongCustomerService" -framework "RongDiscussion" -framework "RongFaceBeautifier" -framework "RongIMKit" -framework "RongIMLib" -framework "RongIMLibCore" -framework "RongLocation" -framework "RongPublicService" -framework "RongRTCLib" -framework "RongSight" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit" -framework "VideoToolbox" -framework "WebKit" -weak_framework "UserNotifications"
+LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManager" "${PODS_CONFIGURATION_BUILD_DIR}/JXCategoryView" "${PODS_CONFIGURATION_BUILD_DIR}/JXPagingView" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/NTLBridge" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/Reachability" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive" "${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket" "${PODS_CONFIGURATION_BUILD_DIR}/TYCyclePagerView" "${PODS_CONFIGURATION_BUILD_DIR}/Whiteboard" "${PODS_CONFIGURATION_BUILD_DIR}/YYModel" "${PODS_CONFIGURATION_BUILD_DIR}/iOS-KS3SDK" "${PODS_ROOT}/JCore" "${PODS_ROOT}/JPush"
+OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_ROOT}/Headers/Public/SSZipArchive/SSZipArchive.modulemap" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/IQKeyboardManager" -isystem "${PODS_ROOT}/Headers/Public/JPush" -isystem "${PODS_ROOT}/Headers/Public/JXCategoryView" -isystem "${PODS_ROOT}/Headers/Public/JXPagingView" -isystem "${PODS_ROOT}/Headers/Public/MBProgressHUD" -isystem "${PODS_ROOT}/Headers/Public/MJExtension" -isystem "${PODS_ROOT}/Headers/Public/MJRefresh" -isystem "${PODS_ROOT}/Headers/Public/Masonry" -isystem "${PODS_ROOT}/Headers/Public/NTLBridge" -isystem "${PODS_ROOT}/Headers/Public/RSKImageCropper" -isystem "${PODS_ROOT}/Headers/Public/Reachability" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/SocketRocket" -isystem "${PODS_ROOT}/Headers/Public/TYCyclePagerView" -isystem "${PODS_ROOT}/Headers/Public/Whiteboard" -isystem "${PODS_ROOT}/Headers/Public/YYModel" -isystem "${PODS_ROOT}/Headers/Public/iOS-KS3SDK" -iframework "${PODS_ROOT}/AlipaySDK-iOS" -iframework "${PODS_ROOT}/Bugly" -iframework "${PODS_ROOT}/RongCloudIM/RongCloudIM" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/ChatRoom" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/CustomerService" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Discussion" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMKit" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLib" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLibCore" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Location" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/PublicService" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Sight" -iframework "${PODS_ROOT}/RongCloudRTC/RongCloudRTC" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongFaceBeautifier" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongRTCLib"
+OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"IQKeyboardManager" -l"JXCategoryView" -l"JXPagingView" -l"MBProgressHUD" -l"MJExtension" -l"MJRefresh" -l"Masonry" -l"NTLBridge" -l"RSKImageCropper" -l"Reachability" -l"SDWebImage" -l"SSZipArchive" -l"SocketRocket" -l"TYCyclePagerView" -l"Whiteboard" -l"YYModel" -l"c++" -l"iOS-KS3SDK" -l"iconv" -l"icucore" -l"jcore-noidfa-ios-2.7.1" -l"jpush-ios-4.3.0" -l"resolv" -l"z" -framework "AVFoundation" -framework "AlipaySDK" -framework "Bugly" -framework "CFNetwork" -framework "CoreFoundation" -framework "CoreGraphics" -framework "CoreMotion" -framework "CoreTelephony" -framework "CoreText" -framework "Foundation" -framework "GLKit" -framework "ImageIO" -framework "QuartzCore" -framework "RongChatRoom" -framework "RongCustomerService" -framework "RongDiscussion" -framework "RongFaceBeautifier" -framework "RongIMKit" -framework "RongIMLib" -framework "RongIMLibCore" -framework "RongLocation" -framework "RongPublicService" -framework "RongRTCLib" -framework "RongSight" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit" -framework "VideoToolbox" -framework "WebKit" -weak_framework "UserNotifications"
 OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SSZipArchive/SSZipArchive.modulemap"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

+ 4 - 4
KulexiuForTeacher/Pods/Target Support Files/Pods-KulexiuForTeacher/Pods-KulexiuForTeacher.release.xcconfig

@@ -2,11 +2,11 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
 EXCLUDED_ARCHS[sdk=iphonesimulator*] = arm64
 FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/AlipaySDK-iOS" "${PODS_ROOT}/Bugly" "${PODS_ROOT}/RongCloudIM/RongCloudIM" "${PODS_ROOT}/RongCloudRTC/RongCloudRTC" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/ChatRoom" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/CustomerService" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Discussion" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMKit" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLib" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLibCore" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Location" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/PublicService" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Sight" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongFaceBeautifier" "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongRTCLib"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/IQKeyboardManager" "${PODS_ROOT}/Headers/Public/JPush" "${PODS_ROOT}/Headers/Public/JXCategoryView" "${PODS_ROOT}/Headers/Public/JXPagingView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MJExtension" "${PODS_ROOT}/Headers/Public/MJRefresh" "${PODS_ROOT}/Headers/Public/Masonry" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/Reachability" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SSZipArchive" "${PODS_ROOT}/Headers/Public/SocketRocket" "${PODS_ROOT}/Headers/Public/TYCyclePagerView" "${PODS_ROOT}/Headers/Public/Whiteboard" "${PODS_ROOT}/Headers/Public/YYModel" "${PODS_ROOT}/Headers/Public/dsBridge" "${PODS_ROOT}/Headers/Public/iOS-KS3SDK"
+HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/IQKeyboardManager" "${PODS_ROOT}/Headers/Public/JPush" "${PODS_ROOT}/Headers/Public/JXCategoryView" "${PODS_ROOT}/Headers/Public/JXPagingView" "${PODS_ROOT}/Headers/Public/MBProgressHUD" "${PODS_ROOT}/Headers/Public/MJExtension" "${PODS_ROOT}/Headers/Public/MJRefresh" "${PODS_ROOT}/Headers/Public/Masonry" "${PODS_ROOT}/Headers/Public/NTLBridge" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/Reachability" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SSZipArchive" "${PODS_ROOT}/Headers/Public/SocketRocket" "${PODS_ROOT}/Headers/Public/TYCyclePagerView" "${PODS_ROOT}/Headers/Public/Whiteboard" "${PODS_ROOT}/Headers/Public/YYModel" "${PODS_ROOT}/Headers/Public/iOS-KS3SDK"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
-LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManager" "${PODS_CONFIGURATION_BUILD_DIR}/JXCategoryView" "${PODS_CONFIGURATION_BUILD_DIR}/JXPagingView" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/Reachability" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive" "${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket" "${PODS_CONFIGURATION_BUILD_DIR}/TYCyclePagerView" "${PODS_CONFIGURATION_BUILD_DIR}/Whiteboard" "${PODS_CONFIGURATION_BUILD_DIR}/YYModel" "${PODS_CONFIGURATION_BUILD_DIR}/dsBridge" "${PODS_CONFIGURATION_BUILD_DIR}/iOS-KS3SDK" "${PODS_ROOT}/JCore" "${PODS_ROOT}/JPush"
-OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_ROOT}/Headers/Public/SSZipArchive/SSZipArchive.modulemap" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/IQKeyboardManager" -isystem "${PODS_ROOT}/Headers/Public/JPush" -isystem "${PODS_ROOT}/Headers/Public/JXCategoryView" -isystem "${PODS_ROOT}/Headers/Public/JXPagingView" -isystem "${PODS_ROOT}/Headers/Public/MBProgressHUD" -isystem "${PODS_ROOT}/Headers/Public/MJExtension" -isystem "${PODS_ROOT}/Headers/Public/MJRefresh" -isystem "${PODS_ROOT}/Headers/Public/Masonry" -isystem "${PODS_ROOT}/Headers/Public/RSKImageCropper" -isystem "${PODS_ROOT}/Headers/Public/Reachability" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/SocketRocket" -isystem "${PODS_ROOT}/Headers/Public/TYCyclePagerView" -isystem "${PODS_ROOT}/Headers/Public/Whiteboard" -isystem "${PODS_ROOT}/Headers/Public/YYModel" -isystem "${PODS_ROOT}/Headers/Public/dsBridge" -isystem "${PODS_ROOT}/Headers/Public/iOS-KS3SDK" -iframework "${PODS_ROOT}/AlipaySDK-iOS" -iframework "${PODS_ROOT}/Bugly" -iframework "${PODS_ROOT}/RongCloudIM/RongCloudIM" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/ChatRoom" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/CustomerService" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Discussion" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMKit" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLib" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLibCore" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Location" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/PublicService" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Sight" -iframework "${PODS_ROOT}/RongCloudRTC/RongCloudRTC" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongFaceBeautifier" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongRTCLib"
-OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"IQKeyboardManager" -l"JXCategoryView" -l"JXPagingView" -l"MBProgressHUD" -l"MJExtension" -l"MJRefresh" -l"Masonry" -l"RSKImageCropper" -l"Reachability" -l"SDWebImage" -l"SSZipArchive" -l"SocketRocket" -l"TYCyclePagerView" -l"Whiteboard" -l"YYModel" -l"c++" -l"dsBridge" -l"iOS-KS3SDK" -l"iconv" -l"icucore" -l"jcore-noidfa-ios-2.7.1" -l"jpush-ios-4.3.0" -l"resolv" -l"z" -framework "AVFoundation" -framework "AlipaySDK" -framework "Bugly" -framework "CFNetwork" -framework "CoreFoundation" -framework "CoreGraphics" -framework "CoreMotion" -framework "CoreTelephony" -framework "CoreText" -framework "Foundation" -framework "GLKit" -framework "ImageIO" -framework "QuartzCore" -framework "RongChatRoom" -framework "RongCustomerService" -framework "RongDiscussion" -framework "RongFaceBeautifier" -framework "RongIMKit" -framework "RongIMLib" -framework "RongIMLibCore" -framework "RongLocation" -framework "RongPublicService" -framework "RongRTCLib" -framework "RongSight" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit" -framework "VideoToolbox" -framework "WebKit" -weak_framework "UserNotifications"
+LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManager" "${PODS_CONFIGURATION_BUILD_DIR}/JXCategoryView" "${PODS_CONFIGURATION_BUILD_DIR}/JXPagingView" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/NTLBridge" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/Reachability" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive" "${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket" "${PODS_CONFIGURATION_BUILD_DIR}/TYCyclePagerView" "${PODS_CONFIGURATION_BUILD_DIR}/Whiteboard" "${PODS_CONFIGURATION_BUILD_DIR}/YYModel" "${PODS_CONFIGURATION_BUILD_DIR}/iOS-KS3SDK" "${PODS_ROOT}/JCore" "${PODS_ROOT}/JPush"
+OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_ROOT}/Headers/Public/SSZipArchive/SSZipArchive.modulemap" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/IQKeyboardManager" -isystem "${PODS_ROOT}/Headers/Public/JPush" -isystem "${PODS_ROOT}/Headers/Public/JXCategoryView" -isystem "${PODS_ROOT}/Headers/Public/JXPagingView" -isystem "${PODS_ROOT}/Headers/Public/MBProgressHUD" -isystem "${PODS_ROOT}/Headers/Public/MJExtension" -isystem "${PODS_ROOT}/Headers/Public/MJRefresh" -isystem "${PODS_ROOT}/Headers/Public/Masonry" -isystem "${PODS_ROOT}/Headers/Public/NTLBridge" -isystem "${PODS_ROOT}/Headers/Public/RSKImageCropper" -isystem "${PODS_ROOT}/Headers/Public/Reachability" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/SocketRocket" -isystem "${PODS_ROOT}/Headers/Public/TYCyclePagerView" -isystem "${PODS_ROOT}/Headers/Public/Whiteboard" -isystem "${PODS_ROOT}/Headers/Public/YYModel" -isystem "${PODS_ROOT}/Headers/Public/iOS-KS3SDK" -iframework "${PODS_ROOT}/AlipaySDK-iOS" -iframework "${PODS_ROOT}/Bugly" -iframework "${PODS_ROOT}/RongCloudIM/RongCloudIM" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/ChatRoom" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/CustomerService" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Discussion" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMKit" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLib" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/IMLibCore" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Location" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/PublicService" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudIM/Sight" -iframework "${PODS_ROOT}/RongCloudRTC/RongCloudRTC" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongFaceBeautifier" -iframework "${PODS_XCFRAMEWORKS_BUILD_DIR}/RongCloudRTC/RongRTCLib"
+OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"IQKeyboardManager" -l"JXCategoryView" -l"JXPagingView" -l"MBProgressHUD" -l"MJExtension" -l"MJRefresh" -l"Masonry" -l"NTLBridge" -l"RSKImageCropper" -l"Reachability" -l"SDWebImage" -l"SSZipArchive" -l"SocketRocket" -l"TYCyclePagerView" -l"Whiteboard" -l"YYModel" -l"c++" -l"iOS-KS3SDK" -l"iconv" -l"icucore" -l"jcore-noidfa-ios-2.7.1" -l"jpush-ios-4.3.0" -l"resolv" -l"z" -framework "AVFoundation" -framework "AlipaySDK" -framework "Bugly" -framework "CFNetwork" -framework "CoreFoundation" -framework "CoreGraphics" -framework "CoreMotion" -framework "CoreTelephony" -framework "CoreText" -framework "Foundation" -framework "GLKit" -framework "ImageIO" -framework "QuartzCore" -framework "RongChatRoom" -framework "RongCustomerService" -framework "RongDiscussion" -framework "RongFaceBeautifier" -framework "RongIMKit" -framework "RongIMLib" -framework "RongIMLibCore" -framework "RongLocation" -framework "RongPublicService" -framework "RongRTCLib" -framework "RongSight" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit" -framework "VideoToolbox" -framework "WebKit" -weak_framework "UserNotifications"
 OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SSZipArchive/SSZipArchive.modulemap"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

+ 1 - 1
KulexiuForTeacher/Pods/Target Support Files/Whiteboard/ResourceBundle-Whiteboard-Whiteboard-Info.plist

@@ -13,7 +13,7 @@
   <key>CFBundlePackageType</key>
   <string>BNDL</string>
   <key>CFBundleShortVersionString</key>
-  <string>2.16.0</string>
+  <string>2.16.27</string>
   <key>CFBundleSignature</key>
   <string>????</string>
   <key>CFBundleVersion</key>

+ 1 - 1
KulexiuForTeacher/Pods/Target Support Files/Whiteboard/Whiteboard.debug.xcconfig

@@ -1,7 +1,7 @@
 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Whiteboard
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Whiteboard" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Whiteboard" "${PODS_ROOT}/Headers/Public/YYModel" "${PODS_ROOT}/Headers/Public/dsBridge"
+HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Whiteboard" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/NTLBridge" "${PODS_ROOT}/Headers/Public/Whiteboard" "${PODS_ROOT}/Headers/Public/YYModel"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_ROOT = ${SRCROOT}

+ 1 - 1
KulexiuForTeacher/Pods/Target Support Files/Whiteboard/Whiteboard.release.xcconfig

@@ -1,7 +1,7 @@
 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Whiteboard
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Whiteboard" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Whiteboard" "${PODS_ROOT}/Headers/Public/YYModel" "${PODS_ROOT}/Headers/Public/dsBridge"
+HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Whiteboard" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/NTLBridge" "${PODS_ROOT}/Headers/Public/Whiteboard" "${PODS_ROOT}/Headers/Public/YYModel"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_ROOT = ${SRCROOT}

+ 0 - 5
KulexiuForTeacher/Pods/Target Support Files/dsBridge/dsBridge-dummy.m

@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_dsBridge : NSObject
-@end
-@implementation PodsDummy_dsBridge
-@end

+ 0 - 12
KulexiuForTeacher/Pods/Target Support Files/dsBridge/dsBridge-prefix.pch

@@ -1,12 +0,0 @@
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#else
-#ifndef FOUNDATION_EXPORT
-#if defined(__cplusplus)
-#define FOUNDATION_EXPORT extern "C"
-#else
-#define FOUNDATION_EXPORT extern
-#endif
-#endif
-#endif
-

+ 0 - 12
KulexiuForTeacher/Pods/Target Support Files/dsBridge/dsBridge.debug.xcconfig

@@ -1,12 +0,0 @@
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/dsBridge
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/dsBridge" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/dsBridge"
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_ROOT = ${SRCROOT}
-PODS_TARGET_SRCROOT = ${PODS_ROOT}/dsBridge
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
-SKIP_INSTALL = YES
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 0 - 12
KulexiuForTeacher/Pods/Target Support Files/dsBridge/dsBridge.release.xcconfig

@@ -1,12 +0,0 @@
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/dsBridge
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/dsBridge" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/dsBridge"
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_ROOT = ${SRCROOT}
-PODS_TARGET_SRCROOT = ${PODS_ROOT}/dsBridge
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
-SKIP_INSTALL = YES
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 116 - 13
KulexiuForTeacher/Pods/Whiteboard/README-zh.md

@@ -2,15 +2,26 @@
 
 本项目为 White-SDK-iOS 的开源版本,为了更好的显示源码结构,`Whiteboard` 将项目分为了多个`subpod`,更有利于开发者查看项目源码层级。为此需要修改引用关系。
 
-## TOC
-
-- [官方文档](#文档)
-- [Example](#Example)
-    - [快速调试](#快速调试)
-- [项目结构](#项目结构)
-- [音视频支持](#Native音视频)
-- [动态PPT本地资源包](#动态ppt本地资源包)
-- [部分问题](#部分问题)
+[![bridge-check](https://github.com/netless-io/Whiteboard-iOS/actions/workflows/bridge.yml/badge.svg)](https://github.com/netless-io/Whiteboard-iOS/actions/workflows/bridge.yml) [![iOS13+Test](https://github.com/netless-io/Whiteboard-iOS/actions/workflows/test.yml/badge.svg)](https://github.com/netless-io/Whiteboard-iOS/actions/workflows/test.yml)
+
+- [Whiteboard](#whiteboard)
+  - [文档](#文档)
+  - [引用](#引用)
+    - [White-SDK-iOS 迁移](#white-sdk-ios-迁移)
+  - [Example](#example)
+    - [调试特定房间](#调试特定房间)
+    - [单元测试](#单元测试)
+  - [要求设备](#要求设备)
+  - [项目结构](#项目结构)
+  - [Native音视频](#native音视频)
+  - [动态ppt本地资源包](#动态ppt本地资源包)
+  - [fpa加速(iOS 13 及其以上)](#fpa加速ios-13-及其以上)
+  - [自定义App插件](#自定义app插件)
+    - [注册自定义App插件](#注册自定义app插件)
+    - [添加自定义App插件到白板中](#添加自定义app插件到白板中)
+  - [使用YYKit](#使用yykit)
+  - [部分问题](#部分问题)
+  - [Whiteboard - Framework 拖拽方式集成](#whiteboard---framework-拖拽方式集成)
 
 ## 文档
 
@@ -18,12 +29,19 @@
 
 ## 引用
 
-在 Podfile 中写入
+- ### CocoaPods
 
 ```
 pod 'Whiteboard'
 ```
 
+- ### Swift Package Manager
+```swift
+ dependencies: [
+    .package(url: "https://github.com/netless-io/Whiteboard-iOS.git", .upToNextMajor(from: "2.15.0"))
+]
+```
+
 <details><summary>White-SDK-iOS 闭源库迁移</summary>
 ### White-SDK-iOS 迁移
 
@@ -97,7 +115,7 @@ pod install
 
 ## 要求设备
 
-运行设备:iOS 9 + (推荐iOS 10以上使用,以获得更佳体验)
+运行设备:iOS 10 + 
 开发环境:Xcode 10+
 
 ## 项目结构
@@ -221,11 +239,96 @@ sdk 现在支持使用 CombinePlayer,在 Native 端播放音视频,sdk 会
 [动态转换资源包](https://developer.netless.link/server-zh/home/server-dynamic-conversion-zip)
 
 
-## 部分问题
+## fpa加速(iOS 13 及其以上)
 
-1. 目前 SDK 关键字为`White`,未严格使用前置三大写字母做前缀。
+1. podfile 添加 `pod 'Whiteboard/fpa'` 依赖
+2. 配置 WhiteRoomConfig 的 `nativeWebSocket` 为 YES
+3. 如需监听FPA连接状态,可以调用 `[[FpaProxyService sharedFpaProxyService] setupDelegate:(id<FpaProxyServiceDelegate>)self];`
+
+注意:如果是M1的电脑想要在模拟器调试,请在Podfile里加入如下声明:
+```ruby
+  post_install do |installer|
+    installer.pods_project.build_configurations.each do |config|
+      config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
+    end
+```
+
+## 自定义App插件
+
+自定义App插件可以扩展白板功能,用户通过编写js代码来实现自己的白板插件。
+
+[如何开发自定义白板App](https://github.com/netless-io/window-manager/blob/master/docs/develop-app.md)
+
+### 注册自定义App插件
+
+Native端在使用自定义App时需要注册对应的App到SDK中。
+
+注册方法时`WhiteSDk`的`registerAppWithParams:`
+
+其中`WhiteRegisterAppParams`有两种生成方式:
+ 1. 复制js代码到本地工程,直接注入js字符串。使用这种方法要注意,需要在variable中提供自定义App的变量名,也就是variable。
+   
+ ```Objective-C
+ @interface WhiteRegisterAppParams : WhiteObject
+ 
+/** 创建一个由js代码生成的自定义app
+ @param javascriptString js代码字符串
+ @param kind 插件类型名称,需要在多端保持一致
+ @param appOptions 插件注册额外参数,按需填
+ @param variable 在上述注入的javascript中,要插入的app变量名
+ */
++ (instancetype)paramsWithJavascriptString: (NSString *)javascriptString kind:(NSString *)kind appOptions:(NSDictionary *)appOptions variable:(NSString *)variable;
+ ```
+ 2. 提供一个js代码的下载地址,由sdk完成下载和注入。使用这种方法要注意,App变量的查找将由kind参数决定。请保持js中App变量名与kind一致。
+   ```Objective-C
+@interface WhiteRegisterAppParams : WhiteObject
+
+/** 创建一个由远端js生成的自定义app
+ @param url js地址
+ @param kind 插件类型名称,需要在多端保持一致。(白板会利用这个名字去寻找app入口)
+ @param appOptions 插件注册额外参数,按需填
+ */
++ (instancetype)paramsWithUrl: (NSString *)url kind:(NSString *)kind appOptions:(NSDictionary *)appOptions;
+   ```
+
+### 添加自定义App插件到白板中
+
+添加自定义App方法是`WhiteRoom`的`addApp:comletionHandler:`
 
+其中`WhiteAppParam`用来描述你的自定义App
 
+请调用该方法完成`WhiteAppParam`初始化
+
+```Objective-C
+@interface WhiteAppParam : WhiteObject
+
+/** 特定的App,一般用来创建自定义的App插入参数
+ @param kind 注册App时使用的kind
+ @param options 详见[WhiteAppOptions](WhiteAppOptions)
+ @param attrs 初始化App的参数,按需填
+ */
+- (instancetype)initWithKind:(NSString *)kind options:(WhiteAppOptions *)options attrs:(NSDictionary *)attrs;
+```
+
+## 使用YYKit
+
+本SDK默认依赖为YYModel,部分使用者若使用YYKit,依赖关系将会发生错误。
+
+解决方法为修改Podfile:
+
+``` ruby
+pod 'Whiteboard/Whiteboard-YYKit'
+```
+
+如果你引用了fpa你可以这样声明:
+
+``` ruby
+pod 'Whiteboard/fpa-YYKit'
+```
+
+## 部分问题
+
+1. 目前 SDK 关键字为`White`,未严格使用前置三大写字母做前缀。
 
 ## Whiteboard - Framework 拖拽方式集成
 

+ 0 - 68
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Converter/WhiteConversionInfo.h

@@ -1,68 +0,0 @@
-//
-//  PptProgress.h
-//  WhiteSDK
-//
-//  Created by yleaf on 2019/6/25.
-//
-
-#import "WhiteObject.h"
-#import "WhiteScene.h"
-#import "WhitePptPage.h"
-NS_ASSUME_NONNULL_BEGIN
-
-
-/** 服务器端文档转换状态。*/
-typedef NS_ENUM(NSInteger, ServerConversionStatus) {
-    /** 文档转换服务排队中。*/
-    ServerConversionStatusWaiting,
-    /** 文档正在转换。 */
-    ServerConversionStatusConverting,
-    /** 未查询到文档转换服务,请检查 `taskId`,与转换类型(动态,静态)是否正确。 */
-    ServerConversionStatusNotFound,
-    /** 文档转换完成。 */
-    ServerConversionStatusFinished,
-    /** 文档转换失败,错误原因详见服务器 `reason` 字段。 */
-    ServerConversionStatusFail
-};
-
-/** PPT 转换类型。*/
-typedef NS_ENUM(NSInteger, ConvertType) {
-    /** 未知,初始状态。 */
-    ConvertTypeUnknown = -1,
-    /** 静态 ppt,即每一页 PPT 都会被转换为图片。 */
-    ConvertTypeStatic,
-    /** 动态 PPT,即每一页 PPT 会被转化为动态版本。 */
-    ConvertTypeDynamic
-};
-
-/** 服务器中文档转换的进度信息。*/
-@interface WhiteConversionInfo : WhiteObject
-
-@property (nonatomic, assign, readonly) ServerConversionStatus convertStatus;
-@property (nonatomic, copy, readonly) NSString *reason;
-@property (nonatomic, assign, readonly) NSInteger totalPageSize;
-@property (nonatomic, assign, readonly) NSInteger convertedPageSize;
-@property (nonatomic, assign, readonly) CGFloat convertedPercentage;
-
-/** 转换成功时,资源文件所用前缀。*/
-@property (nonatomic, copy, readonly, nullable) NSString *prefix;
-
-/** 转换结果。*/
-@property (nonatomic, copy, readonly, nullable) NSArray<WhitePptPage *> *convertedFileList;
-@end
-
-/** 将服务器转换好的数据,转化为 SDK 可用的格式,直接将 scenes 插入 sdk 即可。*/
-@interface ConvertedFiles : NSObject
-
-@property (nonatomic, copy) NSString *taskId;
-@property (nonatomic, assign) ConvertType type;
-@property (nonatomic, assign) CGFloat width;
-@property (nonatomic, assign) CGFloat height;
-@property (nonatomic, copy) NSArray<NSString *> *slideURLs;
-
-/** 白板可接受,能够直接使用场景数据。*/
-@property (nonatomic, copy) NSArray<WhiteScene *> *scenes;
-@end
-
-
-NS_ASSUME_NONNULL_END

+ 0 - 45
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Converter/WhiteConversionInfo.m

@@ -1,45 +0,0 @@
-//
-//  PptProgress.m
-//  WhiteSDK
-//
-//  Created by yleaf on 2019/6/25.
-//
-
-#import "WhiteConversionInfo.h"
-
-
-#pragma mark - PptProgress
-
-@interface WhiteConversionInfo ()
-
-@property (nonatomic, assign, readwrite) ServerConversionStatus convertStatus;
-@property (nonatomic, copy, readwrite) NSString *reason;
-@property (nonatomic, assign, readwrite) NSInteger totalPageSize;
-@property (nonatomic, assign, readwrite) NSInteger convertedPageSize;
-@property (nonatomic, assign, readwrite) CGFloat convertedPercentage;
-@property (nonatomic, copy, readwrite, nullable) NSString *prefix;
-@property (nonatomic, copy, readwrite, nullable) NSArray<WhitePptPage *> *convertedFileList;
-@end
-
-@implementation WhiteConversionInfo
-
-- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
-    NSString *statusString = dic[@"convertStatus"];
-    statusString = [statusString lowercaseString];
-    NSDictionary *map = @{@"waiting": @(ServerConversionStatusWaiting), @"converting": @(ServerConversionStatusConverting), @"notfound": @(ServerConversionStatusNotFound), @"finished": @(ServerConversionStatusFinished), @"fail": @(ServerConversionStatusFail)};
-    _convertStatus = [map[statusString] integerValue];
-    return YES;
-}
-
-
-+ (nullable NSDictionary<NSString *, id> *)modelContainerPropertyGenericClass
-{
-    return @{@"convertedFileList": WhitePptPage.class};
-}
-
-@end
-
-#pragma mark - ConvertedPpt
-
-@implementation ConvertedFiles
-@end

+ 0 - 132
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Converter/WhiteConverter.h

@@ -1,132 +0,0 @@
-//
-//  Converterter.h
-//  WhiteSDK
-//
-//  Created by yleaf on 2019/6/25.
-//
-
-#import <Foundation/Foundation.h>
-#import "WhiteConversionInfo.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-
-/**
- 查询成功后回调
-
- @param success 是否成功
- @param ppt 转换后的 ppt,已经有默认的 ppt.scenes 可以直接调用 whiteSDK WhiteRoom 的 putScenes API
- @param info 从服务器获取到的 转换进度信息
- @param error 报错信息
- */
-typedef void(^ConvertCompletionHandler)(BOOL success, ConvertedFiles * _Nullable ppt, WhiteConversionInfo * _Nullable info, NSError * _Nullable error);
-typedef void(^ConvertProgress)(CGFloat progress, WhiteConversionInfo * _Nullable info);
-
-/**
- 本地 Converter 状态
- 只有一个转换服务器,完整结束(成功,失败)才可以创建下一个转换服务。
- */
-typedef NS_ENUM(NSInteger, ConverterStatus) {
-    /** 初始化状态,可以开始新转换服务 */
-    ConverterStatusIdle,
-    /** 本地转换创建成功,无法创建新转换服务 */
-    ConverterStatusCreated,
-    /**
-     创建转换任务失败
-     在对应回调 error 中查看具体原因,
-     一般为网络错误请求失败,或者未开启文档转换服务
-     可以开始新转换服务
-     */
-    ConverterStatusCreateFail,
-    /** 正在向服务器查询转换状态,无法创建新转换服务 */
-    ConverterStatusChecking,
-    /**
-     向服务器查询转换状态失败
-     重启查询服务,查询服务器转换状态
-     无法创建新转换服务
-     */
-    ConverterStatusCheckFail,
-    /** 等待下次查询转换服务状态,无法创建新转换服务 */
-    ConverterStatusWaitingForNextCheck,
-    /** 查询服务超时,已停止检查,可以手动重启查询服务,无法创建新转换服务 */
-    ConverterStatusTimeout,
-    /** 转换服务完成,可以开启新转换服务 */
-    ConverterStatusSuccess,
-    /**
-     转换服务失败
-     在对应回调 error 中查看具体原因,
-     可以开启新转换服务
-     */
-    ConverterStatusFail,
-};
-
-typedef NS_ENUM(NSInteger, ConverterErrorCode) {
-    /** 创建转换服务失败,请重新创建 */
-    ConverterErrorCodeCreatedFail = 20001,
-    /** 服务器转换失败;具体请查看 error userInfo 信息 */
-    ConverterErrorCodeConvertFail = 20002,
-    /** 服务器端不存在该任务 */
-    ConverterErrorCodeNotFound    = 20003,
-    /** 查询时出错,一般是网络问题,请重启查询服务 */
-    ConverterErrorCodeCheckFail   = 20004,
-    /** 查询时间,超过timeout时间 */
-    ConverterErrorCodeCheckTimeout= 20005,
-};
-
-@interface WhiteConverter : NSObject
-
-- (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithRoomToken:(NSString *)roomToken;
-- (instancetype)initWithRoomToken:(NSString *)roomToken pollingInterval:(NSTimeInterval)interval timeout:(NSTimeInterval)timeout;
-
-@property (nonatomic, copy, readonly) NSString *roomToken;
-
-/**
- 轮询间隔时间,默认 15s,从前一个请求完整结束,开始计时
- */
-@property (nonatomic, assign) NSTimeInterval interval;
-
-/**
- 轮询超时停止时间,默认 3 分钟
- */
-@property (nonatomic, assign) NSTimeInterval timeout;
-
-/**
- 服务器转换任务的 uuid。如遇错,可以提供 taskId 和 type 类型进行排查。
- 只有成功创建转换任务,才会有 taskId,如果未开启服务
- */
-@property (nonatomic, copy, readonly, nullable) NSString *taskId;
-
-/**
- 错误信息
- */
-@property (nonatomic, strong, readonly, nullable)  NSError *error;
-/**
- 转换类型,在创建转换任务时,传入。
- */
-@property (nonatomic, assign, readonly) ConvertType type;
-@property (nonatomic, assign, readonly) ConverterStatus status;
-
-/**
- 创建文档转换服务,并开始轮询请求服务器。
- 部分状态下无法新建服务,具体看 @link{{ConverterStatus}} 枚举
-
- @param url 文档所在网络地址,需要对外可下载(即使无法下载,也会成功创建转换服务,但是会立即变成转换失败状态),SDK 服务器会去下载,然后进行转换。
- @param type 文档类型
- @param progress 进度回调提示
- @param completionHandler 转换完成回调(主线程回调)
- */
-- (void)startConvertTask:(NSString *)url type:(ConvertType)type progress:(_Nullable  ConvertProgress)progress completionHandler:(_Nullable ConvertCompletionHandler)completionHandler;
-
-/**
- 重新轮询执行检查(外部调用时,只有ConverterStatusTimeout,才允许重新开启轮询检查)
-
- 间隔与超时时间,继承 启动文档转换服务 API 的设置
- @param progress 进度回调
- @param completionHandler 转换完成回调(主线程回调)
- */
-- (void)startPolling:(_Nullable ConvertProgress)progress completionHandler:(_Nullable ConvertCompletionHandler)completionHandler;
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 358
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Converter/WhiteConverter.m

@@ -1,358 +0,0 @@
-//
-//  Converterter.m
-//  WhiteSDK
-//
-//  Created by yleaf on 2019/6/25.
-//
-
-#import "WhiteConverter.h"
-#import "WhiteConsts.h"
-#import "WhiteConversionInfo.h"
-
-static dispatch_queue_t converter_processing_queue() {
-    static dispatch_queue_t netless_converter_processing_queue;
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        netless_converter_processing_queue = dispatch_queue_create("com.netless.convert", DISPATCH_QUEUE_CONCURRENT);
-    });
-    
-    return netless_converter_processing_queue;
-}
-
-
-static NSString * const PptApiOrigin = @"https://cloudcapiv4.herewhite.com";
-
-static NSString * const kHttpCode = @"httpCode";
-static NSString * const kErrorCode = @"errorCode";
-static NSString * const kErrorDomain = @"errorDomain";
-
-#pragma mark - Converterter
-
-@interface WhiteConverter ()
-@property (nonatomic, copy, readwrite) NSString *roomToken;
-@property (nonatomic, strong, readwrite, nullable) NSError *error;
-@property (nonatomic, copy, readwrite, nullable) NSString *taskId;
-@property (nonatomic, assign, readwrite) ConvertType type;
-@property (nonatomic, assign, readwrite) ConverterStatus status;
-
-@property (nonatomic, strong) NSDate *beginDate;
-@end
-
-@implementation WhiteConverter
-
-- (instancetype)initWithRoomToken:(NSString *)roomToken
-{
-    self = [self initWithRoomToken:roomToken pollingInterval:15 timeout:3 * 60];
-    return self;
-}
-
-- (instancetype)initWithRoomToken:(NSString *)roomToken pollingInterval:(NSTimeInterval)interval timeout:(NSTimeInterval)timeout
-{
-    self = [super init];
-    if (self) {
-        _type = ConvertTypeUnknown;
-        _roomToken = roomToken;
-        _interval = interval;
-        _timeout = timeout;
-    }
-    return self;
-}
-
-#pragma mark - Public Methods
-
-- (void)startConvertTask:(NSString *)url type:(ConvertType)type progress:(_Nullable  ConvertProgress)progress completionHandler:(_Nullable ConvertCompletionHandler)completionHandler
-{
-    if (![self canStartNewTask]) {
-        NSAssert(false, @"请勿重复启动");
-        return;
-    }
-    
-    self.beginDate = [NSDate date];
-    self.error = nil;
-    self.type = type;
-    
-    ConvertCompletionHandler result = ^ void (BOOL success, ConvertedFiles *ppt, WhiteConversionInfo *info, NSError *error) {
-        if (completionHandler) {
-            dispatch_async(dispatch_get_main_queue(), ^{
-                completionHandler(success, ppt, info, error);
-            });
-        }
-    };
-    
-    dispatch_async(converter_processing_queue(), ^{
-        
-        //多次 async 后,NSURLSession 启动的 task 会丢失 completionHandler
-        //改用 group enter leave,减少异步次数
-        dispatch_group_t group = dispatch_group_create();
-        dispatch_group_enter(group);
-        [self createConvertTask:url ppt:type result:^(BOOL success, NSString *taskId, NSError *error) {
-            if (success) {
-                self.status = ConverterStatusCreated;
-                self.taskId = taskId;
-                dispatch_group_leave(group);
-            } else {
-                self.status = ConverterStatusCreateFail;
-                self.error = error;
-                dispatch_group_leave(group);
-            }
-        }];
-        
-        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
-        
-        if (self.status == ConverterStatusCreateFail) {
-            result(NO, nil, nil, self.error);
-            return ;
-        }
-        
-        [self startPolling:progress completionHandler:completionHandler];
-    });
-}
-
-- (void)startPolling:(_Nullable ConvertProgress)progress completionHandler:(_Nullable ConvertCompletionHandler)completionHandler;
-{
-    if (![self canRestartPolling]) {
-        NSAssert(false, @"请勿重复启动轮询");
-        return;
-    }
-    
-    ConvertCompletionHandler result = ^ void (BOOL success, ConvertedFiles *ppt, WhiteConversionInfo *info, NSError *error) {
-        if (completionHandler) {
-            dispatch_async(dispatch_get_main_queue(), ^{
-                completionHandler(success, ppt, info, error);
-            });
-        }
-    };
-    
-    dispatch_async(converter_processing_queue(), ^{
-        [self pollingTask:self.taskId progress:progress result:^(WhiteConversionInfo *convertInfo, NSError *error) {
-            if (error) {
-                //报错时,在各个异常位置,自行设置 status
-                self.error = error;
-                result(NO, nil, convertInfo, error);
-            } else {
-                ConvertedFiles *cPpt = [self getStaticPptFrom:convertInfo convertType:self.type];
-                self.status = ConverterStatusSuccess;
-                result(YES, cPpt, convertInfo, nil);
-            }
-        }];
-    });
-}
-
-#pragma mark -
-#pragma mark - Private Methods
-#pragma mark -
-
-#pragma mark - Judge
-- (BOOL)canStartNewTask
-{
-    switch (self.status) {
-        case ConverterStatusIdle:
-        case ConverterStatusCreateFail:
-        case ConverterStatusSuccess:
-        case ConverterStatusFail:
-            return YES;
-        case ConverterStatusTimeout:
-        case ConverterStatusWaitingForNextCheck:
-        case ConverterStatusChecking:
-        case ConverterStatusCheckFail:
-        case ConverterStatusCreated:
-            return NO;
-    }
-}
-
-- (BOOL)canRestartPolling
-{
-    switch (self.status) {
-        case ConverterStatusIdle:
-        case ConverterStatusCreateFail:
-        case ConverterStatusSuccess:
-        case ConverterStatusFail:
-            return NO;
-        case ConverterStatusTimeout:
-        case ConverterStatusWaitingForNextCheck:
-        case ConverterStatusChecking:
-        case ConverterStatusCheckFail:
-        case ConverterStatusCreated:
-            return YES;
-    }
-}
-
-#pragma mark - HTTP
-
-- (void)createConvertTask:(NSString *)url ppt:(ConvertType)type result:(void (^)(BOOL succed, NSString *uuid, NSError *error))result
-{
-    NSString *postAPI = [PptApiOrigin stringByAppendingString:@"/services/conversion/tasks"];
-    NSString *serviceType = @"";
-    switch (type) {
-        case ConvertTypeUnknown:
-        case ConvertTypeStatic:
-            serviceType = @"static_conversion";
-            break;
-        case ConvertTypeDynamic:
-            serviceType = @"dynamic_conversion";
-            break;
-    }
-    
-    postAPI = [postAPI stringByAppendingString:[NSString stringWithFormat:@"?roomToken=%@", self.roomToken]];
-    
-    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:postAPI]];
-    NSMutableURLRequest *modifyRequest = [request mutableCopy];
-    
-    NSDictionary *body = @{@"sourceUrl": url ? : @"", @"serviceType": serviceType};
-    NSData *postData = [NSJSONSerialization dataWithJSONObject:body options:0 error:nil];
-    
-    modifyRequest.HTTPMethod = @"POST";
-    modifyRequest.HTTPBody = postData;
-    [modifyRequest addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
-    [modifyRequest addValue:@"application/json" forHTTPHeaderField:@"Accept"];
-
-    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:modifyRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
-        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
-        if (error && result) {
-            NSMutableDictionary *mutableDict = [(error.userInfo ? : @{}) mutableCopy];
-            mutableDict[kErrorDomain] = error.domain;
-            mutableDict[kErrorCode] = @(error.code);
-            NSError *error = [NSError errorWithDomain:WhiteConstConvertDomain code:ConverterErrorCodeCreatedFail userInfo:mutableDict];
-            result(NO, nil, error);
-        } else if (httpResponse.statusCode == 200) {
-            NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
-            NSString *succeed = responseObject[@"msg"][@"succeed"];
-            if ([succeed boolValue]) {
-                NSString *taskId = responseObject[@"msg"][@"taskUUID"];
-                !result ? : result(YES, taskId, nil);
-            } else {
-                NSError *error = [NSError errorWithDomain:WhiteConstConvertDomain code:ConverterErrorCodeCreatedFail userInfo:responseObject];
-                !result ? : result(NO, nil, error);
-            }
-        } else {
-            NSMutableDictionary *responseObject = [([NSJSONSerialization JSONObjectWithData:data options:0 error:nil] ? : @{}) mutableCopy];
-            responseObject[kHttpCode] = @(httpResponse.statusCode);
-            NSError *error = [NSError errorWithDomain:WhiteConstConvertDomain code:ConverterErrorCodeCreatedFail userInfo:responseObject];
-            !result ? : result(NO, nil, error);
-        }
-    }];
-    [task resume];
-}
-
-- (void)pollingTask:(NSString *)taskId progress:(_Nullable ConvertProgress)progress result:(void (^)(WhiteConversionInfo *conversionInfo, NSError *error))result
-{
-    if (self.status == ConverterStatusTimeout || self.status == ConverterStatusCheckFail) {
-        self.beginDate = [NSDate date];
-    } else if (self.status != ConverterStatusCreated || !self.taskId) {
-        NSAssert(false, @"正在查询中,请勿重复调用");
-        return;
-    }
-    
-    BOOL __block converting = YES;
-    WhiteConversionInfo __block *lastInfo;
-    while (converting && [[self.beginDate dateByAddingTimeInterval:self.timeout] compare:[NSDate date]] == NSOrderedDescending) {
-        dispatch_group_t group = dispatch_group_create();
-        dispatch_group_enter(group);
-        self.status = ConverterStatusChecking;
-        [self checkProgress:taskId result:^(WhiteConversionInfo *info, NSError *error) {
-            lastInfo = info;
-            if (!info) {
-                converting = NO;
-                self.status = ConverterStatusCheckFail;
-                !result ? : result(nil, error);
-            } else if (info.convertStatus == ServerConversionStatusFail || info.convertStatus == ServerConversionStatusNotFound) {
-                converting = NO;
-                self.status = ConverterStatusFail;
-                ConverterErrorCode errorCode = info.convertStatus == ServerConversionStatusFail ? ConverterErrorCodeConvertFail : ConverterErrorCodeNotFound;
-                error = error ? error : [NSError errorWithDomain:WhiteConstConvertDomain code:errorCode userInfo:@{@"reason": info.reason ? : @""}];
-                !result ? : result(info, error);
-            } else if (info.convertStatus == ServerConversionStatusFinished) {
-                !progress ? : progress(1, info);
-                converting = NO;
-                self.status = ConverterStatusSuccess;
-                !result ? : result(info, nil);
-            } else {
-                self.status = ConverterStatusWaitingForNextCheck;
-                !progress ? : progress(info.convertedPercentage, info);
-            }
-            
-            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-                dispatch_group_leave(group);
-            });
-            
-        }];
-        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
-    }
-    if (self.status == ConverterStatusWaitingForNextCheck) {
-        self.status = ConverterStatusTimeout;
-        NSError *error = [NSError errorWithDomain:WhiteConstConvertDomain code:ConverterErrorCodeCheckTimeout userInfo:nil];
-        !result ? : result(lastInfo, error);
-    }
-}
-
-- (void)checkProgress:(NSString *)taskId result:(void (^)(WhiteConversionInfo *conversionInfo, NSError *error))result
-{
-    NSString *typeName;
-    switch (self.type) {
-        case ConvertTypeUnknown:
-        case ConvertTypeStatic:
-            typeName = @"static_conversion";
-            break;
-        case ConvertTypeDynamic:
-            typeName = @"dynamic_conversion";
-            break;
-    }
-    NSString *questUrl = [PptApiOrigin stringByAppendingString:[NSString stringWithFormat:@"/services/conversion/tasks/%@/progress?serviceType=%@&roomToken=%@", taskId, typeName, self.roomToken]];
-    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:questUrl]];
-    NSMutableURLRequest *modifyRequest = [request mutableCopy];
-    [modifyRequest addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
-    [modifyRequest addValue:@"application/json" forHTTPHeaderField:@"Accept"];
-    
-    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:modifyRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
-        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
-        if (error && result) {
-            self.status = ConverterStatusCheckFail;
-            NSMutableDictionary *mutableDict = [(error.userInfo ? : @{}) mutableCopy];
-            mutableDict[kErrorDomain] = error.domain;
-            mutableDict[kErrorCode] = @(error.code);
-            NSError *error = [NSError errorWithDomain:WhiteConstConvertDomain code:ConverterErrorCodeCheckFail userInfo:mutableDict];
-            result(nil, error);
-        } else if (httpResponse.statusCode == 200) {
-            NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
-            NSDictionary *task = responseObject[@"msg"][@"task"];
-            WhiteConversionInfo *info = [WhiteConversionInfo modelWithJSON:task];
-            !result ? : result(info, nil);
-        } else {
-            NSMutableDictionary *responseObject = [([NSJSONSerialization JSONObjectWithData:data options:0 error:nil] ? : @{}) mutableCopy];
-            responseObject[kHttpCode] = @(httpResponse.statusCode);
-            NSError *error = [NSError errorWithDomain:WhiteConstConvertDomain code:ConverterErrorCodeCheckFail userInfo:responseObject];
-            !result ? : result(nil, error);
-        }
-    }];
-    [task resume];
-}
-
-#pragma mark - PPT transform
-
-- (ConvertedFiles *)getStaticPptFrom:(WhiteConversionInfo *)pptProgressInfo convertType:(ConvertType)type
-{
-    ConvertedFiles *cPpt = [[ConvertedFiles alloc] init];
-    cPpt.taskId = self.taskId;
-    cPpt.type = type;
-
-    NSArray *fileList = pptProgressInfo.convertedFileList;
-    NSMutableArray<NSString *> *sildeURLs = [NSMutableArray arrayWithCapacity:fileList.count];
-    NSMutableArray<WhiteScene *> *scenes = [NSMutableArray arrayWithCapacity:fileList.count];
-    
-    int i = 0;
-    for (WhitePptPage *pptPage in fileList) {
-        pptPage.src = [NSString stringWithFormat:@"%@%@", pptProgressInfo.prefix ? : @"", pptPage.src];
-        WhiteScene *scene = [[WhiteScene alloc] initWithName:[NSString stringWithFormat:@"%d", i + 1] ppt:pptPage];
-        [scenes addObject:scene];
-        [sildeURLs addObject:pptPage.src];
-        cPpt.width = pptPage.width;
-        cPpt.height = pptPage.height;
-        i ++;
-    }
-    
-    cPpt.slideURLs = sildeURLs;
-    cPpt.scenes = scenes;
-    return cPpt;
-}
-
-@end

+ 5 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteBoardView.h

@@ -5,7 +5,11 @@
 //  Created by leavesster on 2018/8/15.
 //
 
-#import <dsbridge/dsbridge.h>
+#if __has_include(<NTLBridge/dsbridge.h>)
+#import <NTLBridge/dsbridge.h>
+#else
+#import "dsbridge.h"
+#endif
 
 NS_ASSUME_NONNULL_BEGIN
 

+ 7 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteBoardView.m

@@ -172,7 +172,13 @@
 {
     // 1. 脱离 Cocoapods 时,打包成同名 bundle 就可以保证读取一致性
     // 2. 使用字符串,是为了保证使用子类时,self calss 的路径不会变化
-    return [NSBundle bundleWithPath:[[NSBundle bundleForClass:NSClassFromString(@"WhiteBoardView")] pathForResource:@"Whiteboard" ofType:@"bundle"]];
+    NSBundle *podBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:NSClassFromString(@"WhiteBoardView")] pathForResource:@"Whiteboard" ofType:@"bundle"]];
+    if (podBundle) {
+        return podBundle;
+    } else {
+        // SPM bundle
+        return [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"Whiteboard_Whiteboard" ofType:@"bundle"]];
+    }
 }
 
 @end

+ 15 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteDisplayer.h

@@ -44,6 +44,14 @@ NS_ASSUME_NONNULL_BEGIN
 #pragma mark - 页面(场景)管理 API
 
 /**
+ 根据scenePath查询指定场景
+ 
+ @param scenePath 场景路径
+ @param result 返回指定场景的查询结果,详见 [WhiteScene](WhiteScene)
+ */
+- (void)getSceneFromScenePath:(NSString *)scenePath result:(void (^) (WhiteScene* _Nullable scene))result;
+
+/**
  查询场景路径类型。
 
  你可以在该方法中指定想要查询的场景路径,SDK 会返回该路径对应的场景类型。
@@ -198,6 +206,13 @@ NS_ASSUME_NONNULL_BEGIN
  */
 - (void)getSceneSnapshotImage:(NSString *)scenePath completion:(void (^)(UIImage * _Nullable image))completionHandler;
 
+/**
+ 获取当前的 WindowManager
+ 
+ @param result 获取的attributes回调
+ */
+- (void)getWindowManagerAttributesWithResult:(void(^)(NSDictionary * attributes))result;
+
 @end
 
 NS_ASSUME_NONNULL_END

+ 23 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteDisplayer.m

@@ -69,6 +69,16 @@
 
 #pragma mark - 页面(场景)API
 
+- (void)getSceneFromScenePath:(NSString *)scenePath result:(void (^)(WhiteScene * _Nullable))result
+{
+    [self.bridge callHandler:[NSString stringWithFormat:kDisplayerNamespace, @"getScene"] arguments:@[scenePath] completionHandler:^(id  _Nullable value) {
+        if (result) {
+            WhiteScene* scene = [WhiteScene modelWithJSON:value];
+            result(scene);
+        }
+    }];
+}
+
 - (void)getScenePathType:(NSString *)pathOrDir result:(void (^) (WhiteScenePathType pathType))result;
 {
     [self.bridge callHandler:[NSString stringWithFormat:kDisplayerNamespace, @"scenePathType"] arguments:@[pathOrDir] completionHandler:^(id  _Nullable value) {
@@ -199,4 +209,17 @@ static NSString * const kAsyncDisplayerNamespace = @"displayerAsync.%@";
     }];
 }
 
+- (void)getWindowManagerAttributesWithResult:(void (^)(NSDictionary * _Nonnull))result
+{
+    [self.bridge callHandler:[NSString stringWithFormat:kDisplayerNamespace, @"getWindowManagerAttributes"] completionHandler:^(id  _Nullable value) {
+        if (result) {
+            if ([value isKindOfClass:[NSDictionary class]]) {
+                result(value);
+            } else {
+                result(nil);
+            }
+        }
+    }];
+}
+
 @end

+ 4 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteDisplayerState.h

@@ -11,6 +11,7 @@
 #import "WhiteSceneState.h"
 #import "WhiteCameraState.h"
 #import "WhiteObject.h"
+#import "WhitePageState.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -53,6 +54,9 @@ FOUNDATION_EXPORT WhiteWindowBoxState const WhiteWindowBoxStateMax;
 
 @property (nonatomic, copy, readonly, nullable) WhiteWindowBoxState windowBoxState;
 
+/** 开启多窗口后,代表主白板的页面状态。详见 [WhitePageState](WhitePageState) 。 */
+@property (nonatomic, strong, readonly, nullable) WhitePageState *pageState;
+
 @end
 
 NS_ASSUME_NONNULL_END

+ 13 - 2
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Displayer/WhiteDisplayerState.m

@@ -18,12 +18,14 @@ WhiteWindowBoxState const WhiteWindowBoxStateMax = @"maximized";
 @property (nonatomic, strong, readwrite) NSArray<WhiteRoomMember *> *roomMembers;
 @property (nonatomic, strong, readwrite) WhiteCameraState *cameraState;
 @property (nonatomic, copy, nullable, readwrite) WhiteWindowBoxState windowBoxState;
+@property (nonatomic, strong, readwrite) WhitePageState *pageState;
 
 @end
 
 @implementation WhiteDisplayerState
 
 static Class CustomGlobalClass;
+
 + (BOOL)setCustomGlobalStateClass:(Class)clazz
 {
     if ([clazz isSubclassOfClass:[WhiteGlobalState class]]) {
@@ -41,10 +43,19 @@ static Class CustomGlobalClass;
 
 - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;
 {
-    if (CustomGlobalClass) {
-        _globalState = [CustomGlobalClass modelWithJSON:dic[@"globalState"]];
+    WhiteGlobalState* customState = [WhiteDisplayerState getGlobalStateInstanceFromJSON:dic[@"globalState"]];
+    if (customState) {
+        _globalState = customState;
     }
     return YES;
 }
 
++ (WhiteGlobalState *)getGlobalStateInstanceFromJSON:(id)json
+{
+    if (CustomGlobalClass) {
+        return [CustomGlobalClass modelWithJSON:json];
+    }
+    return nil;
+}
+
 @end

+ 1 - 2
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Model/WhiteObject.h

@@ -6,13 +6,12 @@
 //
 
 #import <Foundation/Foundation.h>
-#import <YYModel/YYModel.h>
+#import "NSObject+YY.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
 @interface WhiteObject : NSObject
 
-+ (instancetype)modelWithJSON:(id)json;
 - (NSString *)jsonString;
 - (NSDictionary *)jsonDict;
 

+ 0 - 5
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Model/WhiteObject.m

@@ -9,11 +9,6 @@
 
 @implementation WhiteObject
 
-+ (instancetype)modelWithJSON:(id)json
-{
-    return [self yy_modelWithJSON:json];
-}
-
 - (NSString *)description
 {
     return [NSString stringWithFormat:@"%@ %@", [super description], [self jsonDict]];

+ 12 - 3
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/NativeReplayer/WhiteCombinePlayer.h

@@ -112,7 +112,7 @@ typedef NS_OPTIONS(NSUInteger, WhiteSyncManagerPauseReason) {
  */
 @interface WhiteCombinePlayer : NSObject
 
-@property (nonatomic, strong, readonly) AVPlayer *nativePlayer;
+@property (nonatomic, strong, readonly, nullable) AVPlayer *nativePlayer;
 
 /** 白板回放播放器。详见 [WhitePlayer](WhitePlayer)。
  */
@@ -163,7 +163,15 @@ typedef NS_OPTIONS(NSUInteger, WhiteSyncManagerPauseReason) {
 
  @return 初始化的 `WhiteCombinePlayer` 对象。
 */
-- (instancetype)initWithNativePlayer:(AVPlayer *)nativePlayer NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithNativePlayer:(AVPlayer *)nativePlayer;
+
+/**
+ 使用单独的WhitePlayer来初始化,不再设置AVPlayer
+ 
+ @param replayer 白板回放播放器。详见 [WhitePlayer](WhitePlayer)。
+ @return 初始化的 `WhiteCombinePlayer` 对象。
+ */
+- (instancetype)initWithWhitePlayer:(WhitePlayer *)replayer;
 
 /** 视频回放的持续时长。*/
 - (NSTimeInterval)videoDuration;
@@ -186,7 +194,8 @@ typedef NS_OPTIONS(NSUInteger, WhiteSyncManagerPauseReason) {
  
  - `YES`:调用已经完成。
  - `No`:调用未完成。
-
+ 
+ **NOTE:** 如果是单白板没有native player的情况下seek会直接返回YES
 */
 - (void)seekToTime:(CMTime)time completionHandler:(void (^)(BOOL finished))completionHandler;
 

+ 41 - 20
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/NativeReplayer/WhiteCombinePlayer.m

@@ -38,8 +38,7 @@
 - (instancetype)initWithNativePlayer:(AVPlayer *)nativePlayer whitePlayer:(WhitePlayer *)whitePlayer
 {
     self = [self initWithNativePlayer:nativePlayer];
-    _whitePlayer = whitePlayer;
-    [self updateWhitePlayerPhase:whitePlayer.phase];
+    [self setWhitePlayer:whitePlayer];
     return self;
 }
 
@@ -60,12 +59,22 @@
     if (self = [super init]) {
         _nativePlayer = nativePlayer;
         _playbackSpeed = 1;
-        _pauseReason = WhiteSyncManagerPauseReasonInit;
+        _pauseReason = WhiteSyncManagerPauseReasonWaitingNativePlayerBuffering | SyncManagerWaitingPauseReasonPlayerPause;
     }
     [self registerNotificationAndKVO];
     return self;
 }
 
+- (instancetype)initWithWhitePlayer:(WhitePlayer *)replayer;
+{
+    if (self = [super init]) {
+        _playbackSpeed = 1;
+        _pauseReason = WhiteSyncManagerPauseReasonWaitingWhitePlayerBuffering | SyncManagerWaitingPauseReasonPlayerPause;
+        [self setWhitePlayer:replayer];
+    }
+    return self;
+}
+
 - (void)setWhitePlayer:(WhitePlayer *)whitePlayer
 {
     _whitePlayer = whitePlayer;
@@ -75,12 +84,24 @@
 - (void)registerNotificationAndKVO
 {
     [self registerAudioSessionNotification];
-    [self.nativePlayer addObserver:self forKeyPath:kRateKey options:0 context:nil];
     [self.nativePlayer addObserver:self forKeyPath:kCurrentItemKey options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
 }
 
 #pragma mark - Private Methods
 
+- (void)setPauseReason:(NSUInteger)pauseReason
+{
+    BOOL oldCombineDesirePlaying = !(_pauseReason & SyncManagerWaitingPauseReasonPlayerPause);
+    BOOL combineDesirePlaying = !(pauseReason & SyncManagerWaitingPauseReasonPlayerPause);
+    _pauseReason = pauseReason;
+    
+    if (combineDesirePlaying != oldCombineDesirePlaying) {
+        if ([self.delegate respondsToSelector:@selector(combineVideoPlayStateChange:)]) {
+            [self.delegate combineVideoPlayStateChange:combineDesirePlaying];
+        }
+    }
+}
+
 /**
  预播放状态,可能正在缓冲或缓冲结束。
 
@@ -192,7 +213,6 @@
 }
 
 #pragma mark - KVO
-static NSString * const kRateKey = @"rate";
 static NSString * const kCurrentItemKey = @"currentItem";
 static NSString * const kStatusKey = @"status";
 static NSString * const kPlaybackLikelyToKeepUpKey = @"playbackLikelyToKeepUp";
@@ -229,10 +249,6 @@ static NSString * const kLoadedTimeRangesKey = @"loadedTimeRanges";
             [self addObserverWithPlayItem:newPlayerItem];
         }
 
-    } else if ([keyPath isEqualToString:kRateKey]) {
-        if ([self.delegate respondsToSelector:@selector(combineVideoPlayStateChange:)]) {
-            [self.delegate combineVideoPlayStateChange:[self videoDesireToPlay]];
-        }
     } else if ([keyPath isEqualToString:kStatusKey]) {
         if (self.nativePlayer.currentItem.status == AVPlayerItemStatusFailed) {
             [self pause];
@@ -284,7 +300,6 @@ static NSString * const kLoadedTimeRangesKey = @"loadedTimeRanges";
 
 - (void)removeNativePlayerKVO
 {
-    [self.nativePlayer removeObserver:self forKeyPath:kRateKey];
     [self.nativePlayer removeObserver:self forKeyPath:kCurrentItemKey];
 }
 
@@ -348,7 +363,7 @@ static NSString * const kLoadedTimeRangesKey = @"loadedTimeRanges";
 - (void)whitePlayerStartBuffing
 {
     self.pauseReason = self.pauseReason | WhiteSyncManagerPauseReasonWaitingWhitePlayerBuffering;
-
+    
     [self.nativePlayer pause];
     
     if ([self.delegate respondsToSelector:@selector(combinePlayerStartBuffering)]) {
@@ -466,15 +481,21 @@ static NSString * const kLoadedTimeRangesKey = @"loadedTimeRanges";
     DLog(@"seekTime: %f", seekTime);
     
     __weak typeof(self)weakSelf = self;
-    [self.nativePlayer seekToTime:time completionHandler:^(BOOL finished) {
-        NSTimeInterval realTime = CMTimeGetSeconds(weakSelf.nativePlayer.currentItem.currentTime);
-        DLog(@"realTime: %f", realTime);
-        // AVPlayer 的 seek 不完全准确, seek 完以后,根据 native 的真实时间,重新 seek
-        [weakSelf.whitePlayer seekToScheduleTime:realTime];
-        if (finished) {
-            completionHandler(finished);
-        }
-    }];
+    // 没有Native Player的时候,直接结束
+    // 有Native Player的时候,等待Native Player
+    if (self.nativePlayer.currentItem) {
+        [self.nativePlayer seekToTime:time completionHandler:^(BOOL finished) {
+            NSTimeInterval realTime = CMTimeGetSeconds(weakSelf.nativePlayer.currentItem.currentTime);
+            DLog(@"realTime: %f", realTime);
+            // AVPlayer 的 seek 不完全准确, seek 完以后,根据 native 的真实时间,重新 seek
+            [weakSelf.whitePlayer seekToScheduleTime:realTime];
+            if (finished) {
+                completionHandler(finished);
+            }
+        }];
+    } else {
+        completionHandler(YES);
+    }
 }
 
 @end

+ 21 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteAppParam.h

@@ -28,10 +28,31 @@ NS_ASSUME_NONNULL_BEGIN
 /** 插件所需要的一些额外可选属性,可以不填 */
 @property (nonatomic, copy, readonly) NSDictionary *attrs;
 
+/*
+ 创建一个ppt窗口。
+ 如果你使用的转码结果中带有 uuid 和 prefix,使用该方法生成 WhiteAppParam
+ uuid   字段对应的是 taskId 参数
+ prefix 字段对应的是 url 参数
+ 推荐使用
+ */
++ (instancetype)createSlideApp:(NSString *)dir taskId:(NSString *)taskId url:(NSString *)url title:(NSString *)title;
+
+/*
+ 创建一个ppt窗口。
+ 如果你使用的转码结果中带有 convertedFileList,使用该方法生成 WhiteAppParam
+ 推荐使用
+ */
 + (instancetype)createSlideApp:(NSString *)dir scenes:(NSArray <WhiteScene *>*)scenes title:(NSString *)title;
 + (instancetype)createDocsViewerApp:(NSString *)dir scenes:(NSArray <WhiteScene *>*)scenes title:(NSString *)title;
 + (instancetype)createMediaPlayerApp:(NSString *)src title:(NSString *)title;
 
+/** 特定的App,一般用来创建自定义的App插入参数
+ @param kind 注册App时使用的kind
+ @param options 详见[WhiteAppOptions](WhiteAppOptions)
+ @param attrs 初始化App的参数,按需填
+ */
+- (instancetype)initWithKind:(NSString *)kind options:(WhiteAppOptions *)options attrs:(NSDictionary *)attrs;
+
 @end
 
 NS_ASSUME_NONNULL_END

+ 28 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteAppParam.m

@@ -50,6 +50,24 @@
     return param;
 }
 
+
++ (instancetype)createSlideApp:(NSString *)dir taskId:(NSString *)taskId url:(NSString *)url title:(NSString *)title {
+    WhiteAppParam *param = [[WhiteAppParam alloc] init];
+    param.kind = @"Slide";
+    
+    WhiteAppOptions *ops = [[WhiteAppOptions alloc] init];
+    ops.scenePath = dir;
+    ops.title = title;
+    param.options = ops;
+    
+    param.attrs = @{
+        @"taskId": taskId,
+        @"url": url
+    };
+    
+    return param;
+}
+
 + (instancetype)createSlideApp:(NSString *)dir scenes:(NSArray <WhiteScene *>*)scenes title:(NSString *)title {
     WhiteAppParam *param = [[WhiteAppParam alloc] init];
     param.kind = @"Slide";
@@ -64,4 +82,14 @@
     
     return param;
 }
+
+- (instancetype)initWithKind:(NSString *)kind options:(WhiteAppOptions *)options attrs:(NSDictionary *)attrs
+{
+    if (self = [super init]) {
+        self.kind = kind;
+        self.options = options;
+        self.attrs = attrs;
+    }
+    return self;
+}
 @end

+ 1 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteCameraBound.h

@@ -5,6 +5,7 @@
 //  Created by yleaf on 2019/9/5.
 //
 
+#import <CoreGraphics/CoreGraphics.h>
 #import "WhiteObject.h"
 
 NS_ASSUME_NONNULL_BEGIN

+ 4 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhitePptPage.h

@@ -10,7 +10,10 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-/** 用于在初始化场景时配置场景的图片。 */
+/**
+ 用于插入白板的文件类型
+ pdf, doc, ppt, pptx均用这个类型表示
+ */
 @interface WhitePptPage : WhiteObject
 
 /** 设置场景的图片信息并初始化一个 `WhitePptPage` 对象。

+ 2 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhitePptPage.m

@@ -32,7 +32,8 @@
 }
 
 + (NSDictionary *)modelCustomPropertyMapper {
-    return @{@"src" : @[@"src", @"conversionFileUrl"]};
+    return @{@"src" : @[@"src", @"conversionFileUrl"],
+             @"previewURL" : @[@"previewURL", @"preview"]};
 }
 
 @end

+ 1 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteSceneState.h

@@ -10,7 +10,7 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-/** 场景状态。 */
+/** 场景状态。如果开启了多窗口,需要查看主白板页面数量状态变化,该对象不再有效,需要查看 [WhitePageState](WhitePageState) */
 @interface WhiteSceneState : WhiteObject
 
 /** 当前场景组下所有场景的列表。 */

+ 7 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Object/WhiteWindowParams.m

@@ -16,12 +16,18 @@ WhitePrefersColorScheme const WhitePrefersColorSchemeDark = @"dark";
 - (instancetype)init {
     self = [super init];
     _chessboard = YES;
-    _containerSizeRatio = @(9/16);
+    _containerSizeRatio = @(9/16.0);
     _debug = YES;
     _prefersColorScheme = WhitePrefersColorSchemeLight;
     return self;
 }
 
+- (void)setContainerSizeRatio:(NSNumber *)containerSizeRatio {
+    if (isinf([containerSizeRatio doubleValue])) { return; }
+    if (isnan([containerSizeRatio doubleValue])) { return; }
+    _containerSizeRatio = containerSizeRatio;
+}
+
 - (void)setPrefersColorScheme:(WhitePrefersColorScheme)prefersColorScheme {
     if (@available(iOS 13, *)) {
         _prefersColorScheme = prefersColorScheme;

+ 31 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Replayer/WhitePlayer.h

@@ -14,6 +14,26 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
+/** 白板播放器跳转结果 */
+typedef NSString * WhitePlayerSeekingResult NS_STRING_ENUM;
+
+/**
+ * 跳转进度条成功,并修改了进度
+*/
+extern WhitePlayerSeekingResult const WhitePlayerSeekingResultSuccess;
+ /**
+ * 跳转进度条成功,但并未更新进度
+ */
+extern WhitePlayerSeekingResult const WhitePlayerSeekingResultSuccessButUnnecessary;
+/**
+ * 跳转事件被另一个跳转操作覆盖,因此被取消
+ */
+extern WhitePlayerSeekingResult const WhitePlayerSeekingResultOverride;
+/**
+ * 播放器停止,因而终止本次跳转行为
+ */
+extern WhitePlayerSeekingResult const WhitePlayerSeekingResultStopped;
+
 @interface WhitePlayer : WhiteDisplayer
 
 #pragma mark - 同步 API
@@ -61,6 +81,17 @@ NS_ASSUME_NONNULL_BEGIN
 - (void)seekToScheduleTime:(NSTimeInterval)beginTime;
 
 /**
+ 设置白板回放的起始播放位置。
+ 白板回放的起始时间点为 0,成功调用该方法后,白板回放会在指定位置开始播放。
+
+ @param beginTime 开始播放位置(秒)
+ @param completionHandler 回调。 返回seek结果,详见 [WhitePlayerSeekingResult](WhitePlayerSeekingResult)
+ 
+ **Note:** 如果在WhitePlayerConfig中设置了`mediaURL`,该回调会立刻返回Success
+ */
+- (void)seekToScheduleTime:(NSTimeInterval)beginTime completionHandler:(void(^)(WhitePlayerSeekingResult result))completionHandler;
+
+/**
  设置白板回放的查看模式。
 
  @param mode 白板回放的查看模式,详见 [WhiteObserverMode](WhiteObserverMode)。

+ 10 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Replayer/WhitePlayer.m

@@ -13,6 +13,12 @@
 #import "WhitePlayer+Private.h"
 #import "WhiteDisplayer+Private.h"
 #import "WhiteConsts.h"
+
+WhitePlayerSeekingResult const WhitePlayerSeekingResultSuccess = @"success";
+WhitePlayerSeekingResult const WhitePlayerSeekingResultSuccessButUnnecessary = @"successButUnnecessary";
+WhitePlayerSeekingResult const WhitePlayerSeekingResultOverride = @"override";
+WhitePlayerSeekingResult const WhitePlayerSeekingResultStopped = @"stopped";
+
 @interface WhitePlayer ()
 
 @property (nonatomic, copy, readwrite) NSString *uuid;
@@ -96,6 +102,10 @@ static NSString * const PlayerNamespace = @"player.%@";
     [self.bridge callHandler:[NSString stringWithFormat:PlayerNamespace, @"seekToScheduleTime"] arguments:@[@(beginTime * WhiteConstTimeUnitRatio)]];
 }
 
+- (void)seekToScheduleTime:(NSTimeInterval)beginTime completionHandler:(void (^)(WhitePlayerSeekingResult _Nonnull))completionHandler {
+    [self.bridge callHandler:[NSString stringWithFormat:PlayerNamespace, @"seekToScheduleTime"] arguments:@[@(beginTime * WhiteConstTimeUnitRatio)] completionHandler:completionHandler];
+}
+
 - (void)setObserverMode:(WhiteObserverMode)mode
 {
     NSString *modeString = @"";

+ 5 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoom+Private.h

@@ -6,17 +6,22 @@
 //
 
 #import "WhiteRoom.h"
+#import "ApplePencilDrawHandler.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
 @interface WhiteRoom ()
 
+@property (nonatomic, strong, readwrite) ApplePencilDrawHandler *applePencilDrawHandler;
 @property (nonatomic, strong, readwrite) NSNumber *observerId;
 @property (nonatomic, assign, readwrite, getter=isWritable) BOOL writable;
+@property (nonatomic, assign) BOOL shouldCheckingRepeatSetWritable;
+@property (nonatomic, assign) BOOL isUpdatingWritable;
 
 - (instancetype)initWithUuid:(NSString *)uuid bridge:(WhiteBoardView *)bridge;
 - (void)updatePhase:(WhiteRoomPhase)phase;
 - (void)updateRoomState:(WhiteRoomState *)state;
+- (void)prepareForApplePencilDrawOnly;
 
 @end
 

+ 108 - 5
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoom.h

@@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nonatomic, strong, readonly) NSNumber *observerId;
 /** 房间 uuid */
 @property (nonatomic, copy, readonly) NSString *uuid;
-/** 全局状态,由于遗留问题,目前该 API,不支持 customGlobalState,如需获取 customGlobalState,请使用 room.state.globalState */
+/** 房间的全局状态。详见 [WhiteGlobalState](WhiteGlobalState)。 */
 @property (nonatomic, strong, readonly) WhiteGlobalState *globalState;
 /** 教具信息 */
 @property (nonatomic, strong, readonly) WhiteReadonlyMemberState *memberState;
@@ -52,6 +52,15 @@ NS_ASSUME_NONNULL_BEGIN
 /** 连接状态 */
 @property (nonatomic, assign, readonly) WhiteRoomPhase phase;
 
+#pragma mark - Apple Pencil
+
+/**
+ 设置是否只允许ApplePencil涂鸦
+ 
+ 详见 [drawOnlyApplePencil](drawOnlyApplePencil)
+ */
+- (void)setDrawOnlyApplePencil:(BOOL)drawOnlyPencil;
+
 #pragma mark - Set API
 
 /**
@@ -149,16 +158,20 @@ NS_ASSUME_NONNULL_BEGIN
 #pragma mark - PPT
 
 /**
- 播放动态 PPT 下一
+ 播放动态 PPT 下一
 
  当前 PPT 页面的动画已全部执行完成时,SDK 会将场景切换至下一页 PPT。
+ 
+ 注意,多窗口模式下该接口不再生效
  */
 - (void)pptNextStep;
 
 /**
- 返回动态 PPT 上一
+ 返回动态 PPT 上一
  
  当前 PPT 页面的动画全部回退完成时,SDK 会将场景切回至上一页 PPT。
+ 
+ 注意,多窗口模式下该接口不再生效
  */
 - (void)pptPreviousStep;
 
@@ -250,6 +263,28 @@ NS_ASSUME_NONNULL_BEGIN
 
 @interface WhiteRoom (Scene)
 
+/**
+ 多窗口下更新窗口颜色配置
+ 
+ @param colorScheme (WhitePrefersColorScheme)[WhitePrefersColorScheme]
+ */
+- (void)setPrefersColorScheme:(WhitePrefersColorScheme)colorScheme;
+
+/** 暗黑模式, 本地效果, 不会同步到远端, 默认Light, 设置auto只有在iOS13以上才会生效*/
+
+/**
+ 多窗口下更新房间尺寸比例
+ 
+ @param ratio 目标尺寸比例
+ */
+- (void)setContainerSizeRatio:(NSNumber *)ratio;
+
+/**
+ 为当前的 WindowManger 直接设置attributes
+ 
+ @param attributes 需要设置的attributes
+ */
+- (void)setWindowManagerWithAttributes:(NSDictionary *)attributes;
 
 /**
  获取房间当前场景组下的场景状态。 
@@ -376,6 +411,67 @@ NS_ASSUME_NONNULL_BEGIN
  */
 - (void)moveScene:(NSString *)source target:(NSString *)target;
 
+/**
+ 插入一个新页面
+ 该新页面会位于当前的页面的下一页
+ */
+- (void)addPage;
+
+/**
+ 插入一个新页面
+ 该新页面会位于当前的页面的下一页
+ @param completionHandler 回调
+ */
+- (void)addPage:(void(^ _Nullable)(BOOL success))completionHandler;
+
+/**
+ 删除当前页面
+ @param completionHandler 回调
+ */
+- (void)removePage:(void(^ _Nullable)(BOOL success))completionHandler;
+
+/**
+ 删除指定页面
+ @param index 页面下标
+ @param completionHandler 回调
+ */
+- (void)removePage:(NSUInteger)index completionHandler:(void(^ _Nullable)(BOOL success))completionHandler;
+
+/**
+ 插入一个新页面
+ 
+ **Note:**
+ 
+ @param scene 新插入的场景对象
+ @param afterCurrentScene 是否在当前页面之后。YES: 插入到当前页面之后。 NO: 在插入到最后一页的后面
+ */
+- (void)addPageWithScene:(WhiteScene * _Nullable )scene afterCurrentScene:(BOOL)afterCurrentScene;
+
+/**
+ 插入一个新页面
+ 
+ **Note:**
+ 
+ @param scene 新插入的场景对象
+ @param afterCurrentScene 是否在当前页面之后。YES: 插入到当前页面之后。 NO: 在插入到最后一页的后面
+ @param completionHandler 回调
+ */
+- (void)addPageWithScene:(WhiteScene * _Nullable )scene afterCurrentScene:(BOOL)afterCurrentScene completionHandler:(void(^ _Nullable)(BOOL success))completionHandler;
+
+/**
+ 切换到下一页场景
+ 
+ **Note: **
+ @param completionHandler 回调,success代表切换是否成功
+ */
+- (void)nextPage:(void(^ _Nullable)(BOOL success))completionHandler;
+/**
+ 切换到上一页场景
+ 
+ **Note: **
+ @param completionHandler 回调,success代表切换是否成功
+ */
+- (void)prevPage:(void(^ _Nullable)(BOOL success))completionHandler;
 
 /**
  * 以下方法可以对使用【选择框】的工具进行操作。
@@ -471,8 +567,7 @@ NS_ASSUME_NONNULL_BEGIN
  **Note:**
 
  - 该方法为异步调用。
- - 通过 [setCustomGlobalStateClass](setCustomGlobalStateClass) 设置自定义状态后,如需异步获取,可以通过 [getRoomStateWithResult](getRoomStateWithResult) 获取自定义 [GlobalState](GlobalState)。
- - 调用 [setGlobalState](setGlobalState) 方法后,可以立刻调用该方法。 
+ - 调用 [setGlobalState](setGlobalState) 方法后,可以立刻调用该方法。
  @param result 回调。返回房间的全局状态,详见 [GlobalState](GlobalState)。 
  */
 - (void)getGlobalStateWithResult:(void (^) (WhiteGlobalState *state))result;
@@ -537,6 +632,14 @@ NS_ASSUME_NONNULL_BEGIN
  */
 - (void)addApp:(WhiteAppParam *)appParams completionHandler:(void (^)(NSString *appId))completionHandler;
 
+/**
+ * 关闭窗口
+ * 该方法仅在多窗口下有效, 无论appId是否有效都会触发回调
+ *
+ * @param appId 添加app时返回的id
+ */
+- (void)closeApp:(NSString *)appId completionHandler:(void (^)(void))completionHandler;
+
 
 /** 获取 syncedState 所有状态值 */
 - (void)getSyncedState:(void (^)(NSDictionary *state))result;

+ 134 - 5
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoom.m

@@ -11,6 +11,7 @@
 #import "WhiteConsts.h"
 #import "WhiteDisplayer+Private.h"
 #import "WhiteObject.h"
+#import "WhiteDisplayerState+Private.h"
 
 @interface WhiteRoom()
 @property (nonatomic, assign, readwrite) NSTimeInterval delay;
@@ -28,18 +29,20 @@
 {
     self = [super initWithUuid:uuid bridge:bridge];
     _state = [[WhiteRoomState alloc] init];
-    _globalState = [[WhiteGlobalState alloc] init];
     _uuid = uuid;
+    _isUpdatingWritable = NO;
     return self;
 }
 
 #pragma mark - Property
 
+- (WhiteGlobalState *)globalState {
+    return self.bridge.room.state.globalState;
+}
+
 - (void)setGlobalState:(WhiteGlobalState *)modifyState
 {
     [self.bridge callHandler:@"room.setGlobalState" arguments:@[modifyState]];
-    NSDictionary *update = [modifyState jsonDict];
-    [_globalState yy_modelSetWithJSON:update];
 }
 
 - (void)setMemberState:(WhiteMemberState *)modifyState
@@ -79,6 +82,25 @@
 
 - (void)updateRoomState:(WhiteRoomState *)state {
     [_state yy_modelSetWithJSON:[state yy_modelToJSONObject]];
+    
+    if (state.memberState.currentApplianceName) {
+        [self.applePencilDrawHandler roomApplianceDidUpdate];
+    }
+}
+
+#pragma mark - Apple Pencil
+- (void)setDrawOnlyApplePencil:(BOOL)drawOnlyPencil
+{
+    if (self.applePencilDrawHandler) {
+        self.applePencilDrawHandler.drawOnlyApplePencil = drawOnlyPencil;
+    } else if (drawOnlyPencil && UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
+        [self prepareForApplePencilDrawOnly];
+    }
+}
+
+- (void)prepareForApplePencilDrawOnly
+{
+    self.applePencilDrawHandler = [[ApplePencilDrawHandler alloc] initWithRoom:self drawOnlyPencil:YES];
 }
 
 #pragma mark - Set Action
@@ -107,6 +129,7 @@
 - (void)disconnect:(void (^ _Nullable) (void))completeHandler
 {
     self.disconnectedBySelf = YES;
+    [self.applePencilDrawHandler recoverApplianceFromTempRemove];
     [self.bridge callHandler:@"room.disconnect" completionHandler:^(id  _Nullable value) {
         if (completeHandler) {
             completeHandler();
@@ -147,6 +170,21 @@
 
 #pragma mark - Scene API
 
+- (void)setPrefersColorScheme:(WhitePrefersColorScheme)colorScheme
+{
+    [self.bridge callHandler:@"room.setPrefersColorScheme" arguments:@[colorScheme]];
+}
+
+- (void)setContainerSizeRatio:(NSNumber *)ratio
+{
+    [self.bridge callHandler:@"room.setContainerSizeRatio" arguments:@[ratio]];
+}
+
+- (void)setWindowManagerWithAttributes:(NSDictionary *)attributes
+{
+    [self.bridge callHandler:@"room.setWindowManagerAttributes" arguments:@[attributes]];
+}
+
 - (void)putScenes:(NSString *)dir scenes:(NSArray<WhiteScene *> *)scenes index:(NSUInteger)index
 {
     [self.bridge callHandler:@"room.putScenes" arguments:@[dir, scenes, @(index)]];
@@ -202,7 +240,10 @@
 
 - (void)setWritable:(BOOL)writable completionHandler:(void (^ _Nullable)(BOOL isWritable, NSError * _Nullable error))completionHandler;
 {
+    NSAssert(!self.isUpdatingWritable, @"Do not set writable when you are setting writable");
+    self.isUpdatingWritable = YES;
     [self.bridge callHandler:@"room.setWritable" arguments:@[@(writable)] completionHandler:^(id  _Nullable value) {
+        self.isUpdatingWritable = NO;
         if (completionHandler) {
             NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
             NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
@@ -233,6 +274,87 @@
     [self.bridge callHandler:@"room.moveScene" arguments:@[source, target]];
 }
 
+- (void)addPage
+{
+    [self addPage:nil];
+}
+
+- (void)addPage:(void (^)(BOOL))completionHandler
+{
+    [self addPageWithScene:nil afterCurrentScene:YES completionHandler:completionHandler];
+}
+
+- (void)removePage:(void (^)(BOOL))completionHandler
+{
+    [self removePage:-1 completionHandler:completionHandler];
+}
+
+- (void)removePage:(NSUInteger)index completionHandler:(void (^ _Nullable)(BOOL))completionHandler
+{
+    NSDictionary *params = (index == -1) ? @{} : @{@"index": @(index)};
+    [self.bridge callHandler:@"room.removePage" arguments:@[params] completionHandler:^(id  _Nullable value) {
+        if (completionHandler) {
+            
+            if ([value isKindOfClass:[NSNumber class]]) {
+                return completionHandler([(NSNumber *)value boolValue]);
+            }
+            if (value) {
+                NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
+                NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+                NSDictionary *error = dict[@"__error"];
+                if (error) {
+                    completionHandler(NO);
+                    return;
+                }
+            }
+            completionHandler(YES);
+        }
+    }];
+}
+
+- (void)addPageWithScene:(WhiteScene *)scene afterCurrentScene:(BOOL)afterCurrentScene
+{
+    [self addPageWithScene:scene afterCurrentScene:afterCurrentScene completionHandler:nil];
+}
+
+- (void)addPageWithScene:(WhiteScene *)scene afterCurrentScene:(BOOL)afterCurrentScene completionHandler:(void (^)(BOOL))completionHandler
+{
+    NSArray *args;
+    if (scene) {
+        args = @[@{@"after": @(afterCurrentScene), @"scene": scene}];
+    } else {
+        args = @[@{@"after": @(afterCurrentScene)}];
+    }
+    [self.bridge callHandler:@"room.addPage" arguments:args completionHandler:^(id  _Nullable value) {
+        if (completionHandler) {
+            if (value) {
+                NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
+                NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+                NSDictionary *error = dict[@"__error"];
+                if (error) {
+                    completionHandler(NO);
+                    return;
+                }
+            }
+            completionHandler(YES);
+        }
+    }];
+}
+
+- (void)nextPage:(void(^ _Nullable)(BOOL success))completionHandler
+{
+    [self.bridge callHandler:@"room.nextPage" completionHandler:^(id  _Nullable value) {
+        if (completionHandler) { completionHandler([value boolValue]); }
+    }];
+}
+
+- (void)prevPage:(void(^ _Nullable)(BOOL success))completionHandler
+{
+    [self.bridge callHandler:@"room.prevPage" completionHandler:^(id  _Nullable value) {
+        if (completionHandler) { completionHandler([value boolValue]); }
+    }];
+}
+
 #pragma mark - Text API
 
 - (void)insertText:(CGFloat)x y:(CGFloat)y textContent:(NSString *)textContent completionHandler:(void (^)(NSString * _Nonnull))completionHandler {
@@ -299,8 +421,7 @@
 {
     [self.bridge callHandler:@"room.getGlobalState" completionHandler:^(id  _Nullable value) {
         if (result) {
-            WhiteGlobalState *jsState = [WhiteGlobalState modelWithJSON:value];
-            result(jsState);
+            result([WhiteDisplayerState getGlobalStateInstanceFromJSON:value]);
         }
     }];
 }
@@ -445,6 +566,14 @@ static NSString * const RoomSyncNamespace = @"room.sync.%@";
     }];
 }
 
+- (void)closeApp:(NSString *)appId completionHandler:(void (^)(void))completionHandler {
+    [self.bridge callHandler:@"room.closeApp" arguments:@[appId] completionHandler:^(id  _Nullable value) {
+        if (completionHandler) {
+            completionHandler();
+        }
+    }];
+}
+
 - (void)getSyncedState:(void (^)(NSDictionary *state))result {
     [self.bridge callHandler:@"room.getSyncedState" completionHandler:^(id  _Nullable value) {
         NSString *string = value;

+ 24 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoomConfig.h

@@ -176,6 +176,30 @@ NS_ASSUME_NONNULL_BEGIN
 /** 多窗口用的本地参数,只影响本地客户 */
 @property (nonatomic, strong, nullable) WhiteWindowParams *windowParams;
 
+/** 是否启用可写状态监控。
+ 若开启,在非可写状态调用需要可写权限的房间操作会触发NSAssert,以此来强制正确的api调用。
+ 监控仅在开发环境生效,生产环境自动失效。
+ 该参数默认为`NO`
+ */
+@property (nonatomic, assign) BOOL enableWritableAssert;
+
+/**
+ 是否只允许用ApplePencil涂鸦
+ 
+ 开启后,禁止手指涂鸦,只有ApplePencil的笔迹会被识别。
+ 在涂鸦时如果有手指误触,将触发 [fireRoomStateChanged](fireRoomStateChanged:) 回调,返回发生 ApplianceClickerClicker 和 ApplianceClickerPencil 教具切换。
+ 
+ 该参数仅在 iPad 设备上生效
+ 建议跟随`UIPencilInteraction.prefersPencilOnlyDrawing`设置
+ 
+ 该参数默认为`NO`
+ */
+@property (nonatomic, assign) BOOL drawOnlyApplePencil;
+
 @end
 
 NS_ASSUME_NONNULL_END
+
+#if __has_include("WhiteRoomConfig+FPA.h")
+#import "WhiteRoomConfig+FPA.h"
+#endif

+ 12 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteRoomConfig.m

@@ -41,6 +41,8 @@
         _isWritable = true;
         _uid = uid;
         _disableNewPencil = true;
+        _enableWritableAssert = false;
+        _drawOnlyApplePencil = false;
         if (_userPayload) {
             NSDictionary *dict = @{@"key": _userPayload};
             if (![NSJSONSerialization isValidJSONObject:dict]) {
@@ -64,4 +66,14 @@
     _disableCameraTransform = disableOperations;
 }
 
+#if __has_include("WhiteRoomConfig+FPA.h")
+- (void)setNativeWebSocket:(BOOL)nativeWebSocket {
+    if (@available(iOS 13.0, *)) {
+        _nativeWebSocket = nativeWebSocket;
+    } else {
+        _nativeWebSocket = NO;
+    }
+}
+#endif
+
 @end

+ 36 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Room/WhiteSDK+Room.m

@@ -12,6 +12,17 @@
 #import "WhiteRoom+Private.h"
 #import "WhiteRoomCallbacks+Private.h"
 #import "WhiteRoom.h"
+#import "WhiteSocket.h"
+#import "WhiteSocket+Private.h"
+#if __has_include ("WhiteRoomConfig+FPA.h")
+#import "WhiteFPA.h"
+#import "WhiteRoomConfig+FPA.h"
+#endif
+
+#if DEBUG
+#import "WritableDetectRoom.h"
+#endif
+
 
 @implementation WhiteSDK (Room)
 
@@ -26,7 +37,18 @@
         WhiteRoomCallbacks *roomCallbacks = [[WhiteRoomCallbacks alloc] init];
         self.bridge.roomCallbacks = roomCallbacks;
         [self.bridge addJavascriptObject:roomCallbacks namespace:@"room"];
+        
+#if __has_include ("WhiteRoomConfig+FPA.h")
+        if (@available(iOS 13.0, *)) {
+            if (config.nativeWebSocket) {
+                [WhiteFPA setupFpa:[WhiteFPA defaultFpaConfig] chain:[WhiteFPA defaultChain]];
+                WhiteSocket *socket = [[WhiteSocket alloc] initWithBridge:self.bridge];
+                [self.bridge addJavascriptObject:socket namespace:@"ws"];
+            }
+        }
+#endif
     }
+
     
     if (callbacks) {
         self.bridge.roomCallbacks.delegate = callbacks;
@@ -34,6 +56,15 @@
     __weak typeof(self.bridge)weakBridge = self.bridge;
     WhiteRoom *room = [[WhiteRoom alloc] initWithUuid:config.uuid bridge:weakBridge];
     self.bridge.roomCallbacks.room = room;
+#if DEBUG
+    if (config.enableWritableAssert) {
+        [WritableDetectRoom startObserveRoom:room];
+    }
+    
+    room.shouldCheckingRepeatSetWritable = config.enableWritableAssert;
+#else
+    room.shouldCheckingRepeatSetWritable = false;
+#endif
     
     [self.bridge callHandler:@"sdk.joinRoom" arguments:@[config] completionHandler:^(id _Nullable value) {
        
@@ -52,6 +83,11 @@
                 [room updateRoomState:[WhiteRoomState modelWithJSON:dict[@"state"]]];
                 weakBridge.room = room;
                 weakBridge.roomCallbacks.room = room;
+                
+                if (config.drawOnlyApplePencil && UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
+                    [room prepareForApplePencilDrawOnly];
+                }
+                
                 completionHandler(YES, room, nil);
             }
         }

+ 9 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSDK.h

@@ -11,6 +11,7 @@
 #import "WhiteSdkConfiguration.h"
 #import "WhiteAudioMixerBridge.h"
 #import "WhiteFontFace.h"
+#import "WhiteRegisterAppParams.h"
 NS_ASSUME_NONNULL_BEGIN
 
 /** 白板 SDK 相关方法。 */
@@ -126,6 +127,14 @@ NS_ASSUME_NONNULL_BEGIN
  */
 - (void)setCommonCallbackDelegate:(nullable id<WhiteCommonCallbackDelegate>)callbackDelegate;
 
+#pragma mark - CustomApp
+
+/**
+ 注册自定义App
+ 
+ @param params 注册参数,详见 [WhiteRegisterAppParams](WhiteRegisterAppParams)
+ */
+- (void)registerAppWithParams:(WhiteRegisterAppParams *)params completionHandler:(void (^)(NSError * _Nullable error))completionHandler;
 
 @end
 NS_ASSUME_NONNULL_END

+ 26 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSDK.m

@@ -23,7 +23,7 @@
 
 + (NSString *)version
 {
-    return @"2.16.0";
+    return @"2.16.27";
 }
 
 - (instancetype)initWithWhiteBoardView:(WhiteBoardView *)boardView config:(WhiteSdkConfiguration *)config commonCallbackDelegate:(nullable id<WhiteCommonCallbackDelegate>)callback audioMixerBridgeDelegate:( id<WhiteAudioMixerBridgeDelegate>)mixer
@@ -83,6 +83,31 @@
     [self.bridge callHandler:@"sdk.updateNativeTextareaFont" arguments:@[fonts]];
 }
 
+#pragma mark - 自定义App
+
+- (void)registerAppWithParams:(WhiteRegisterAppParams *)params completionHandler:(void (^)(NSError * _Nullable))completionHandler
+{
+    [self.bridge callHandler:@"sdk.registerApp" arguments:@[params] completionHandler:^(id  _Nullable value) {
+        if (completionHandler) {
+            if (!value) {
+                completionHandler(nil);
+                return;
+            }
+            NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
+            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+            NSDictionary *error = dict[@"__error"];
+            if (error) {
+                NSString *desc = error[@"message"] ? : @"";
+                NSString *description = error[@"jsStack"] ? : @"";
+                NSDictionary *userInfo = @{NSLocalizedDescriptionKey: desc, NSDebugDescriptionErrorKey: description};
+                completionHandler([NSError errorWithDomain:WhiteConstErrorDomain code:-101 userInfo:userInfo]);
+            } else {
+                completionHandler(nil);
+            }
+        }
+    }];
+}
+
 #pragma mark - Private
 - (void)setupWebSdk
 {

+ 1 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSdkConfiguration+Private.h

@@ -12,6 +12,7 @@ NS_ASSUME_NONNULL_BEGIN
 @interface WhiteSdkConfiguration ()
 
 @property (nonatomic, assign) BOOL enableRtcIntercept;
+@property (nonatomic, copy) NSArray<NSString *> *netlessUA;
 
 @end
 

+ 5 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSdkConfiguration.h

@@ -191,6 +191,11 @@ FOUNDATION_EXPORT WhiteSDKLoggerReportModeKey const WhiteSDKLoggerReportBan;
 
 @property (nonatomic, assign) BOOL disableDeviceInputs;
 
+/**
+ * 是否禁止新铅笔工具展示笔锋,默认是 `NO`。
+ */
+@property (nonatomic, assign) BOOL disableNewPencilStroke;
+
 /** 独立的 SyncedStore 状态,与 globalState 类似,但是没有任何 SDK 内部的状态 */
 @property (nonatomic, assign) BOOL enableSyncedStore;
 

+ 4 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/SDK/WhiteSdkConfiguration.m

@@ -73,12 +73,15 @@ static NSString *const kJSDeviceType = @"deviceType";
     _nativeTags = @{@"nativeVersion": [WhiteSDK version], @"platform": [NSString stringWithFormat:@"%@ %@ %@", _platform, deviceModel, currentDevice.systemVersion]};
     _appIdentifier = appIdentifier;
     _pptParams = [[WhitePptParams alloc] init];
+    _disableNewPencilStroke = NO;
     return self;
 }
 
 + (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper
 {
-    return @{@"nativeTags": @"__nativeTags", @"platform": @"__platform"};
+    return @{@"nativeTags": @"__nativeTags",
+             @"platform": @"__platform",
+             @"netlessUA": @"__netlessUA"};
 }
 
 - (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic {

+ 3 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Classes/Whiteboard.h

@@ -18,5 +18,8 @@
 #import "WhitePlayer.h"
 #import "WhiteConverter.h"
 #import "WhiteCombinePlayer.h"
+#import "WhiteConverterV5.h"
+#import "WhiteProjectorPolling.h"
+#import "WhiteAdvanceConvertProgressPolling.h"
 
 #endif /* Whiteboard_h */

+ 0 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/f17ecb7


+ 1 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/index.html

@@ -1 +1 @@
-<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0" name="viewport"/><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>white-sdk-bridge Application</title><script defer="defer" src="runtime.42cce1dd.js"></script><script defer="defer" src="web-sdk.47b8d54d.js"></script><script defer="defer" src="netless.3d40c396.js"></script><script defer="defer" src="video.b3db6331.js"></script><script defer="defer" src="vendor.7dc7ced9.js"></script><script defer="defer" src="main.419dbe84.js"></script><link href="vendor.css" rel="stylesheet"><link href="main.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
+<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0" name="viewport"/><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>white-sdk-bridge Application</title><script defer="defer" src="runtime.42cce1dd.js"></script><script defer="defer" src="web-sdk.33a13aff.js"></script><script defer="defer" src="netless.20e5e81a.js"></script><script defer="defer" src="video.b3db6331.js"></script><script defer="defer" src="vendor.ff6a3f24.js"></script><script defer="defer" src="main.76ae1298.js"></script><link href="netless.css" rel="stylesheet"><link href="main.css" rel="stylesheet"></head><body><div id="root"></div></body></html>

File diff suppressed because it is too large
+ 0 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/main.419dbe84.js


File diff suppressed because it is too large
+ 0 - 1
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/main.css


File diff suppressed because it is too large
+ 0 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/netless.3d40c396.js


File diff suppressed because it is too large
+ 0 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/vendor.7dc7ced9.js


File diff suppressed because it is too large
+ 0 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/vendor.css


File diff suppressed because it is too large
+ 0 - 0
KulexiuForTeacher/Pods/Whiteboard/Whiteboard/Resource/web-sdk.47b8d54d.js


+ 0 - 8
KulexiuForTeacher/Pods/dsBridge/dsbridge/DSCallInfo.h

@@ -1,8 +0,0 @@
-
-#import <Foundation/Foundation.h>
-
-@interface DSCallInfo : NSObject
-@property (nullable, nonatomic) NSString* method;
-@property (nullable, nonatomic) NSNumber* id;
-@property (nullable,nonatomic) NSArray * args;
-@end

+ 0 - 13
KulexiuForTeacher/Pods/dsBridge/dsbridge/DSCallInfo.m

@@ -1,13 +0,0 @@
-//
-//  DSCallInfo.m
-//  dsbridge
-//
-//  Created by du on 2018/1/30.
-//  Copyright © 2018年 杜文. All rights reserved.
-//
-
-#import "DSCallInfo.h"
-
-@implementation DSCallInfo
-
-@end

+ 0 - 54
KulexiuForTeacher/Pods/dsBridge/dsbridge/DWKWebView.h

@@ -1,54 +0,0 @@
-//
-//  DSWKwebview.h
-//  dspider
-//
-//  Created by 杜文 on 16/12/28.
-//  Copyright © 2016年 杜文. All rights reserved.
-//
-
-#import <WebKit/WebKit.h>
-
-typedef void (^JSCallback)(NSString * _Nullable result,BOOL complete);
-
-@interface DWKWebView : WKWebView <WKUIDelegate>
-
-@property (nullable, nonatomic, weak) id <WKUIDelegate> DSUIDelegate;
-
-- (void)loadUrl: (NSString * _Nonnull) url;
-
-// Call javascript handler
--(void) callHandler:(NSString * _Nonnull) methodName  arguments:(NSArray * _Nullable) args;
--(void) callHandler:(NSString * _Nonnull) methodName  completionHandler:(void (^ _Nullable)(id _Nullable value))completionHandler;
--(void) callHandler:(NSString * _Nonnull) methodName  arguments:(NSArray * _Nullable) args completionHandler:(void (^ _Nullable)(id _Nullable value))completionHandler;
-
-// set a listener for javascript closing the current page.
-- (void)setJavascriptCloseWindowListener:(void(^_Nullable)(void))callback;
-
-/**
- * Add a Javascript Object to dsBridge with namespace.
- * @param object
- * which implemented the javascript interfaces
- * @param namespace  
- * if empty, the object have no namespace.
- **/
-- (void)addJavascriptObject:(id _Nullable ) object namespace:(NSString *  _Nullable) namespace;
-
-// Remove the Javascript Object with the supplied namespace
-- (void)removeJavascriptObject:(NSString *  _Nullable) namespace;
-
-// Test whether the handler exist in javascript
-- (void) hasJavascriptMethod:(NSString * _Nonnull) handlerName methodExistCallback:(void(^ _Nullable)(bool exist))callback;
-
-// Set debug mode. if in debug mode, some errors will be prompted by a dialog
-// and the exception caused by the native handlers will not be captured.
-- (void) setDebugMode:(bool) debug;
-
-- (void) disableJavascriptDialogBlock:(bool) disable;
-
-// custom the  label text of  javascript dialog that includes alert/confirm/prompt
-- (void) customJavascriptDialogLabelTitles:(NSDictionary*_Nullable) dic;
-
-// private method, the developer shoudn't call this method
-- (id _Nullable ) onMessage:(NSDictionary *_Nonnull) msg type:(int) type;
-
-@end

+ 0 - 488
KulexiuForTeacher/Pods/dsBridge/dsbridge/DWKWebView.m

@@ -1,488 +0,0 @@
-#import "DWKWebView.h"
-#import "JSBUtil.h"
-#import "DSCallInfo.h"
-#import "InternalApis.h"
-#import <objc/message.h>
-
-@implementation DWKWebView
-{
-    void (^alertHandler)(void);
-    void (^confirmHandler)(BOOL);
-    void (^promptHandler)(NSString *);
-    void(^javascriptCloseWindowListener)(void);
-    int dialogType;
-    int callId;
-    bool jsDialogBlock;
-    NSMutableDictionary<NSString *,id> *javaScriptNamespaceInterfaces;
-    NSMutableDictionary *handerMap;
-    NSMutableArray<DSCallInfo *> * callInfoList;
-    NSDictionary<NSString*,NSString*> *dialogTextDic;
-    UITextField *txtName;
-    UInt64 lastCallTime ;
-    NSString *jsCache;
-    bool isPending;
-    bool isDebug;
-}
-
-
--(instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
-{
-    txtName=nil;
-    dialogType=0;
-    callId=0;
-    alertHandler=nil;
-    confirmHandler=nil;
-    promptHandler=nil;
-    jsDialogBlock=true;
-    callInfoList=[NSMutableArray array];
-    javaScriptNamespaceInterfaces=[NSMutableDictionary dictionary];
-    handerMap=[NSMutableDictionary dictionary];
-    lastCallTime = 0;
-    jsCache=@"";
-    isPending=false;
-    isDebug=false;
-    dialogTextDic=@{};
-    
-    WKUserScript *script = [[WKUserScript alloc] initWithSource:@"window._dswk=true;"
-                                                  injectionTime:WKUserScriptInjectionTimeAtDocumentStart
-                                               forMainFrameOnly:YES];
-    [configuration.userContentController addUserScript:script];
-    self = [super initWithFrame:frame configuration: configuration];
-    if (self) {
-        super.UIDelegate=self;
-    }
-    // add internal Javascript Object
-    InternalApis *  interalApis= [[InternalApis alloc] init];
-    interalApis.webview=self;
-    [self addJavascriptObject:interalApis namespace:@"_dsb"];
-    return self;
-}
-
-- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt
-    defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame
-completionHandler:(void (^)(NSString * _Nullable result))completionHandler
-{
-    NSString * prefix=@"_dsbridge=";
-    if ([prompt hasPrefix:prefix])
-    {
-        NSString *method= [prompt substringFromIndex:[prefix length]];
-        NSString *result=nil;
-        if(isDebug){
-            result =[self call:method :defaultText ];
-        }else{
-            @try {
-                result =[self call:method :defaultText ];
-            }@catch(NSException *exception){
-                NSLog(@"%@", exception);
-            }
-        }
-        completionHandler(result);
-        
-    }else {
-        if(!jsDialogBlock){
-            completionHandler(nil);
-        }
-        if(self.DSUIDelegate && [self.DSUIDelegate respondsToSelector:
-                                 @selector(webView:runJavaScriptTextInputPanelWithPrompt
-                                           :defaultText:initiatedByFrame
-                                           :completionHandler:)])
-        {
-            return [self.DSUIDelegate webView:webView runJavaScriptTextInputPanelWithPrompt:prompt
-                                  defaultText:defaultText
-                             initiatedByFrame:frame
-                            completionHandler:completionHandler];
-        }else{
-            dialogType=3;
-            if(jsDialogBlock){
-                promptHandler=completionHandler;
-            }
-            UIAlertView *alert = [[UIAlertView alloc]
-                                  initWithTitle:prompt
-                                  message:@""
-                                  delegate:self
-                                  cancelButtonTitle:dialogTextDic[@"promptCancelBtn"]?dialogTextDic[@"promptCancelBtn"]:@"取消"
-                                  otherButtonTitles:dialogTextDic[@"promptOkBtn"]?dialogTextDic[@"promptOkBtn"]:@"确定",
-                                  nil];
-            [alert setAlertViewStyle:UIAlertViewStylePlainTextInput];
-            txtName = [alert textFieldAtIndex:0];
-            txtName.text=defaultText;
-            [alert show];
-        }
-    }
-}
-
-- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message
-initiatedByFrame:(WKFrameInfo *)frame
-completionHandler:(void (^)(void))completionHandler
-{
-    if(!jsDialogBlock){
-        completionHandler();
-    }
-    if( self.DSUIDelegate &&  [self.DSUIDelegate respondsToSelector:
-                               @selector(webView:runJavaScriptAlertPanelWithMessage
-                                         :initiatedByFrame:completionHandler:)])
-    {
-        return [self.DSUIDelegate webView:webView runJavaScriptAlertPanelWithMessage:message
-                         initiatedByFrame:frame
-                        completionHandler:completionHandler];
-    }else{
-        dialogType=1;
-        if(jsDialogBlock){
-            alertHandler=completionHandler;
-        }
-        UIAlertView *alertView =
-        [[UIAlertView alloc] initWithTitle:dialogTextDic[@"alertTitle"]?dialogTextDic[@"alertTitle"]:@"提示"
-                                   message:message
-                                  delegate:self
-                         cancelButtonTitle:dialogTextDic[@"alertBtn"]?dialogTextDic[@"alertBtn"]:@"确定"
-                         otherButtonTitles:nil,nil];
-        [alertView show];
-    }
-}
-
--(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message
-initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler
-{
-    if(!jsDialogBlock){
-        completionHandler(YES);
-    }
-    if( self.DSUIDelegate&& [self.DSUIDelegate respondsToSelector:
-                            @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)])
-    {
-        return[self.DSUIDelegate webView:webView runJavaScriptConfirmPanelWithMessage:message
-                        initiatedByFrame:frame
-                       completionHandler:completionHandler];
-    }else{
-        dialogType=2;
-        if(jsDialogBlock){
-            confirmHandler=completionHandler;
-        }
-        UIAlertView *alertView =
-        [[UIAlertView alloc] initWithTitle:dialogTextDic[@"confirmTitle"]?dialogTextDic[@"confirmTitle"]:@"提示"
-                                   message:message
-                                  delegate:self
-                         cancelButtonTitle:dialogTextDic[@"confirmCancelBtn"]?dialogTextDic[@"confirmCancelBtn"]:@"取消"
-                         otherButtonTitles:dialogTextDic[@"confirmOkBtn"]?dialogTextDic[@"confirmOkBtn"]:@"确定", nil];
-        [alertView show];
-    }
-}
-
-- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
-    if( self.DSUIDelegate && [self.DSUIDelegate respondsToSelector:
-                              @selector(webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)]){
-        return [self.DSUIDelegate webView:webView createWebViewWithConfiguration:configuration forNavigationAction:navigationAction windowFeatures:windowFeatures];
-    }
-    return  nil;
-}
-
-- (void)webViewDidClose:(WKWebView *)webView{
-    if( self.DSUIDelegate && [self.DSUIDelegate respondsToSelector:
-                              @selector(webViewDidClose:)]){
-        [self.DSUIDelegate webViewDidClose:webView];
-    }
-}
-
-- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo{
-    if( self.DSUIDelegate
-       && [self.DSUIDelegate respondsToSelector:
-           @selector(webView:shouldPreviewElement:)]){
-           return [self.DSUIDelegate webView:webView shouldPreviewElement:elementInfo];
-       }
-    return NO;
-}
-
-- (UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id<WKPreviewActionItem>> *)previewActions{
-    if( self.DSUIDelegate &&
-       [self.DSUIDelegate respondsToSelector:@selector(webView:previewingViewControllerForElement:defaultActions:)]){
-        return [self.DSUIDelegate
-                webView:webView
-                previewingViewControllerForElement:elementInfo
-                defaultActions:previewActions
-                ];
-    }
-    return  nil;
-}
-
-
-- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController{
-    if( self.DSUIDelegate
-       && [self.DSUIDelegate respondsToSelector:@selector(webView:commitPreviewingViewController:)]){
-        return [self.DSUIDelegate webView:webView commitPreviewingViewController:previewingViewController];
-    }
-}
-
-- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
-{
-    if(dialogType==1 && alertHandler){
-        alertHandler();
-        alertHandler=nil;
-    }else if(dialogType==2 && confirmHandler){
-        confirmHandler(buttonIndex==1?YES:NO);
-        confirmHandler=nil;
-    }else if(dialogType==3 && promptHandler && txtName) {
-        if(buttonIndex==1){
-            promptHandler([txtName text]);
-        }else{
-            promptHandler(@"");
-        }
-        promptHandler=nil;
-        txtName=nil;
-    }
-}
-
-- (void) evalJavascript:(int) delay{
-    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
-        @synchronized(self){
-            if([jsCache length]!=0){
-                [self evaluateJavaScript :jsCache completionHandler:nil];
-                isPending=false;
-                jsCache=@"";
-                lastCallTime=[[NSDate date] timeIntervalSince1970]*1000;
-            }
-        }
-    });
-}
-
--(NSString *)call:(NSString*) method :(NSString*) argStr
-{
-    NSArray *nameStr=[JSBUtil parseNamespace:[method stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
-
-    id JavascriptInterfaceObject=javaScriptNamespaceInterfaces[nameStr[0]];
-    NSString *error=[NSString stringWithFormat:@"Error! \n Method %@ is not invoked, since there is not a implementation for it",method];
-    NSMutableDictionary*result =[NSMutableDictionary dictionaryWithDictionary:@{@"code":@-1,@"data":@""}];
-    if(!JavascriptInterfaceObject){
-        NSLog(@"Js bridge  called, but can't find a corresponded JavascriptObject , please check your code!");
-    }else{
-        method=nameStr[1];
-        NSString *methodOne = [JSBUtil methodByNameArg:1 selName:method class:[JavascriptInterfaceObject class]];
-        NSString *methodTwo = [JSBUtil methodByNameArg:2 selName:method class:[JavascriptInterfaceObject class]];
-        SEL sel=NSSelectorFromString(methodOne);
-        SEL selasyn=NSSelectorFromString(methodTwo);
-        NSDictionary * args=[JSBUtil jsonStringToObject:argStr];
-        id arg=args[@"data"];
-        if(arg==[NSNull null]){
-            arg=nil;
-        }
-        NSString * cb;
-        do{
-            if(args && (cb= args[@"_dscbstub"])){
-                if([JavascriptInterfaceObject respondsToSelector:selasyn]){
-                    __weak typeof(self) weakSelf = self;
-                    void (^completionHandler)(id,BOOL) = ^(id value,BOOL complete){
-                        NSString *del=@"";
-                        result[@"code"]=@0;
-                        if(value!=nil){
-                            result[@"data"]=value;
-                        }
-                        value=[JSBUtil objToJsonString:result];
-                        value=[value stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
-                        
-                        if(complete){
-                            del=[@"delete window." stringByAppendingString:cb];
-                        }
-                        NSString*js=[NSString stringWithFormat:@"try {%@(JSON.parse(decodeURIComponent(\"%@\")).data);%@; } catch(e){};",cb,(value == nil) ? @"" : value,del];
-                        __strong typeof(self) strongSelf = weakSelf;
-                        @synchronized(self)
-                        {
-                            UInt64  t=[[NSDate date] timeIntervalSince1970]*1000;
-                            jsCache=[jsCache stringByAppendingString:js];
-                            if(t-lastCallTime<50){
-                                if(!isPending){
-                                    [strongSelf evalJavascript:50];
-                                    isPending=true;
-                                }
-                            }else{
-                                [strongSelf evalJavascript:0];
-                            }
-                        }
-                        
-                    };
-                    
-                    void(*action)(id,SEL,id,id) = (void(*)(id,SEL,id,id))objc_msgSend;
-                    action(JavascriptInterfaceObject,selasyn,arg,completionHandler);
-                    break;
-                }
-            }else if([JavascriptInterfaceObject respondsToSelector:sel]){
-                id ret;
-                id(*action)(id,SEL,id) = (id(*)(id,SEL,id))objc_msgSend;
-                ret=action(JavascriptInterfaceObject,sel,arg);
-                [result setValue:@0 forKey:@"code"];
-                if(ret!=nil){
-                    [result setValue:ret forKey:@"data"];
-                }
-                break;
-            }
-            NSString*js=[error stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
-            if(isDebug){
-                js=[NSString stringWithFormat:@"window.alert(decodeURIComponent(\"%@\"));",js];
-                [self evaluateJavaScript :js completionHandler:nil];
-            }
-            NSLog(@"%@",error);
-        }while (0);
-    }
-    return [JSBUtil objToJsonString:result];
-}
-
-- (void)setJavascriptCloseWindowListener:(void (^)(void))callback
-{
-    javascriptCloseWindowListener=callback;
-}
-
-- (void)setDebugMode:(bool)debug{
-    isDebug=debug;
-}
-
-- (void)loadUrl: (NSString *)url
-{
-    NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
-    [self loadRequest:request];
-}
-
-
-- (void)callHandler:(NSString *)methodName arguments:(NSArray *)args{
-    [self callHandler:methodName arguments:args completionHandler:nil];
-}
-
-- (void)callHandler:(NSString *)methodName completionHandler:(void (^)(id _Nullable))completionHandler{
-    [self callHandler:methodName arguments:nil completionHandler:completionHandler];
-}
-
--(void)callHandler:(NSString *)methodName arguments:(NSArray *)args completionHandler:(void (^)(id  _Nullable value))completionHandler
-{
-    DSCallInfo *callInfo=[[DSCallInfo alloc] init];
-    callInfo.id=[NSNumber numberWithInt: callId++];
-    callInfo.args=args==nil?@[]:args;
-    callInfo.method=methodName;
-    if(completionHandler){
-        [handerMap setObject:completionHandler forKey:callInfo.id];
-    }
-    if(callInfoList!=nil){
-        [callInfoList addObject:callInfo];
-    }else{
-        [self dispatchJavascriptCall:callInfo];
-    }
-}
-
-- (void)dispatchStartupQueue{
-    if(callInfoList==nil) return;
-    for (DSCallInfo * callInfo in callInfoList) {
-        [self dispatchJavascriptCall:callInfo];
-    }
-    callInfoList=nil;
-}
-
-- (void) dispatchJavascriptCall:(DSCallInfo*) info{
-    NSString * json=[JSBUtil objToJsonString:@{@"method":info.method,@"callbackId":info.id,
-                                               @"data":[JSBUtil objToJsonString: info.args]}];
-    [self evaluateJavaScript:[NSString stringWithFormat:@"window._handleMessageFromNative(%@)",json]
-           completionHandler:nil];
-}
-
-- (void) addJavascriptObject:(id)object namespace:(NSString *)namespace{
-    if(namespace==nil){
-        namespace=@"";
-    }
-    if(object!=NULL){
-        [javaScriptNamespaceInterfaces setObject:object forKey:namespace];
-    }
-}
-
-- (void) removeJavascriptObject:(NSString *)namespace {
-    if(namespace==nil){
-        namespace=@"";
-    }
-    [javaScriptNamespaceInterfaces removeObjectForKey:namespace];
-}
-
-- (void)customJavascriptDialogLabelTitles:(NSDictionary *)dic{
-    if(dic){
-        dialogTextDic=dic;
-    }
-}
-
-- (id)onMessage:(NSDictionary *)msg type:(int)type{
-    id ret=nil;
-    switch (type) {
-        case DSB_API_HASNATIVEMETHOD:
-            ret= [self hasNativeMethod:msg]?@1:@0;
-            break;
-        case DSB_API_CLOSEPAGE:
-            [self closePage:msg];
-            break;
-        case DSB_API_RETURNVALUE:
-            ret=[self returnValue:msg];
-            break;
-        case DSB_API_DSINIT:
-            ret=[self dsinit:msg];
-            break;
-        case DSB_API_DISABLESAFETYALERTBOX:
-            [self disableJavascriptDialogBlock:[msg[@"disable"] boolValue]];
-            break;
-        default:
-            break;
-    }
-    return ret;
-}
-
-- (bool) hasNativeMethod:(NSDictionary *) args
-{
-    NSArray *nameStr=[JSBUtil parseNamespace:[args[@"name"]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
-    NSString * type= [args[@"type"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
-    id JavascriptInterfaceObject= [javaScriptNamespaceInterfaces objectForKey:nameStr[0]];
-    if(JavascriptInterfaceObject){
-        bool syn=[JSBUtil methodByNameArg:1 selName:nameStr[1] class:[JavascriptInterfaceObject class]]!=nil;
-        bool asyn=[JSBUtil methodByNameArg:2 selName:nameStr[1] class:[JavascriptInterfaceObject class]]!=nil;
-        if(([@"all" isEqualToString:type]&&(syn||asyn))
-           ||([@"asyn" isEqualToString:type]&&asyn)
-           ||([@"syn" isEqualToString:type]&&syn)
-           ){
-            return true;
-        }
-    }
-    return false;
-}
-
-- (id) closePage:(NSDictionary *) args{
-    if(javascriptCloseWindowListener){
-        javascriptCloseWindowListener();
-    }
-    return nil;
-}
-
-- (id) returnValue:(NSDictionary *) args{
-    void (^ completionHandler)(NSString *  _Nullable)= handerMap[args[@"id"]];
-    if(completionHandler){
-        if(isDebug){
-            completionHandler(args[@"data"]);
-        }else{
-            @try{
-                completionHandler(args[@"data"]);
-            }@catch (NSException *e){
-                NSLog(@"%@",e);
-            }
-        }
-        if([args[@"complete"] boolValue]){
-            [handerMap removeObjectForKey:args[@"id"]];
-        }
-    }
-    return nil;
-}
-
-- (id) dsinit:(NSDictionary *) args{
-    [self dispatchStartupQueue];
-    return nil;
-}
-
-- (void) disableJavascriptDialogBlock:(bool) disable{
-    jsDialogBlock=!disable;
-}
-
-- (void)hasJavascriptMethod:(NSString *)handlerName methodExistCallback:(void (^)(bool exist))callback{
-    [self callHandler:@"_hasJavascriptMethod" arguments:@[handlerName] completionHandler:^(NSNumber* _Nullable value) {
-        callback([value boolValue]);
-    }];
-}
-
-@end
-
-

+ 0 - 8
KulexiuForTeacher/Pods/dsBridge/dsbridge/InternalApis.h

@@ -1,8 +0,0 @@
-#import <Foundation/Foundation.h>
-#import "DWKWebView.h"
-
-@interface InternalApis : NSObject
-@property (nullable, nonatomic, weak) DWKWebView* webview;
-@end
-
-

+ 0 - 25
KulexiuForTeacher/Pods/dsBridge/dsbridge/InternalApis.m

@@ -1,25 +0,0 @@
-#import "InternalApis.h"
-#import "JSBUtil.h"
-
-@implementation InternalApis
-- (id) hasNativeMethod:(id) args
-{
-    return [self.webview onMessage:args type: DSB_API_HASNATIVEMETHOD];
-}
-
-- (id) closePage:(id) args{
-    return [self.webview onMessage:args type:DSB_API_CLOSEPAGE];
-}
-
-- (id) returnValue:(NSDictionary *) args{
-    return [self.webview onMessage:args type:DSB_API_RETURNVALUE];
-}
-
-- (id) dsinit:(id) args{
-    return [self.webview onMessage:args type:DSB_API_DSINIT];
-}
-
-- (id) disableJavascriptDialogBlock:(id) args{
-    return [self.webview onMessage:args type:DSB_API_DISABLESAFETYALERTBOX];
-}
-@end

+ 0 - 17
KulexiuForTeacher/Pods/dsBridge/dsbridge/JSBUtil.h

@@ -1,17 +0,0 @@
-#import <Foundation/Foundation.h>
-
-enum{
- DSB_API_HASNATIVEMETHOD,
- DSB_API_CLOSEPAGE,
- DSB_API_RETURNVALUE,
- DSB_API_DSINIT,
- DSB_API_DISABLESAFETYALERTBOX
-};
-
-@interface JSBUtil : NSObject
-+ (NSString * _Nullable)objToJsonString:(id  _Nonnull)dict;
-+ (id  _Nullable)jsonStringToObject:(NSString * _Nonnull)jsonString;
-+(NSString *_Nullable)methodByNameArg:(NSInteger)argNum
-                              selName:( NSString * _Nullable)selName class:(Class _Nonnull )class;
-+ (NSArray *_Nonnull)parseNamespace: (NSString *_Nonnull) method;
-@end

+ 0 - 105
KulexiuForTeacher/Pods/dsBridge/dsbridge/JSBUtil.m

@@ -1,105 +0,0 @@
-//
-//  Util.m
-//  Created by 杜文 on 16/12/27.
-//  Copyright © 2016年 杜文. All rights reserved.
-//
-
-#import "JSBUtil.h"
-#import <objc/runtime.h>
-#import "DWKWebView.h"
-
-
-@implementation JSBUtil
-+ (NSString *)objToJsonString:(id)dict
-{
-    NSString *jsonString = nil;
-    NSError *error;
-    
-    if (![NSJSONSerialization isValidJSONObject:dict]) {
-        return @"{}";
-    }
-    
-    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
-    if (! jsonData) {
-        return @"{}";
-    } else {
-        jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
-    }
-    return jsonString;
-}
-
-//get this class all method
-+ (NSArray *)allMethodFromClass:(Class)class {
-    NSMutableArray *methods = [NSMutableArray array];
-    while (class) {
-        unsigned int count = 0;
-        Method *method = class_copyMethodList(class, &count);
-        for (unsigned int i = 0; i < count; i++) {
-            SEL name1 = method_getName(method[i]);
-            const char *selName= sel_getName(name1);
-            NSString *strName = [NSString stringWithCString:selName encoding:NSUTF8StringEncoding];
-            [methods addObject:strName];
-        }
-        free(method);
-        
-        Class cls = class_getSuperclass(class);
-        class = [NSStringFromClass(cls) isEqualToString:NSStringFromClass([NSObject class])] ? nil : cls;
-    }
-    
-    return [NSArray arrayWithArray:methods];
-}
-
-//return method name for xxx: or xxx:handle:
-+(NSString *)methodByNameArg:(NSInteger)argNum selName:(NSString *)selName class:(Class)class
-{
-    NSString *result = nil;
-    if(class){
-        NSArray *arr = [JSBUtil allMethodFromClass:class];
-        for (int i=0; i<arr.count; i++) {
-            NSString *method = arr[i];
-            NSArray *tmpArr = [method componentsSeparatedByString:@":"];
-            NSRange range = [method rangeOfString:@":"];
-            if (range.length > 0) {
-                NSString *methodName = [method substringWithRange:NSMakeRange(0, range.location)];
-                if ([methodName isEqualToString:selName] && tmpArr.count == (argNum + 1)) {
-                    result = method;
-                    return result;
-                }
-            }
-        }
-    }
-    return result;
-}
-
-+ (NSArray *)parseNamespace: (NSString *) method{
-    NSRange range=[method rangeOfString:@"." options:NSBackwardsSearch];
-    NSString *namespace=@"";
-    if(range.location!=NSNotFound){
-        namespace=[method substringToIndex:range.location];
-        method=[method substringFromIndex:range.location+1];
-    }
-    return @[namespace,method];
-    
-}
-
-
-+ (id )jsonStringToObject:(NSString *)jsonString
-{
-    if (jsonString == nil) {
-        return nil;
-    }
-    
-    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
-    NSError *err;
-    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
-                                                        options:NSJSONReadingMutableContainers
-                                                          error:&err];
-    if(err)
-    {
-        NSLog(@"json解析失败:%@",err);
-        return nil;
-    }
-    return dic;
-}
-
-@end

+ 0 - 4
KulexiuForTeacher/Pods/dsBridge/dsbridge/dsbridge.h

@@ -1,4 +0,0 @@
-#import <Foundation/Foundation.h>
-#import "JSBUtil.h"
-#import "DWKWebView.h"
-

+ 0 - 515
KulexiuForTeacher/Pods/dsBridge/readme-chs.md

@@ -1,515 +0,0 @@
-# DSBridge  for  IOS
-
-![dsBridge](https://github.com/wendux/DSBridge-IOS/raw/master/img/dsbridge.png)
-
-
-[![cocoapods](https://img.shields.io/cocoapods/v/dsBridge.svg?style=flat)](https://github.com/wendux/DSBridge-IOS)  ![](https://img.shields.io/badge/language-object--c-yellow.svg) [![](https://travis-ci.org/wendux/DSBridge-IOS.svg?branch=master)](https://travis-ci.org/wendux/DSBridge-IOS) [![MIT Licence](https://img.shields.io/packagist/l/doctrine/orm.svg)](https://opensource.org/licenses/mit-license.php)  ![support](https://img.shields.io/badge/support-IOS%208%2B-green.svg) ![platform](https://img.shields.io/badge/platform-ios|osx-ff69b4.svg) [![GitHub last commit](https://img.shields.io/github/last-commit/wendux/DSBridge-IOS.svg?color=blue)](https://github.com/wendux/DSBridge-IOS/) 
-> 三端易用的现代跨平台 Javascript bridge, 通过它,你可以在Javascript和原生之间同步或异步的调用彼此的函数.
-
-### 注意
-
-DSBridge v3.0 是一个里程碑版本,和v2.0相比,有许多变化,需要注意的是v3.0**不兼容**之前版本,但是我们也会继续维护v2.0分支,所以,如果你是v2.0的使用者,请放心继续使用v2.0,如果你是新用户,请使用>=v3.0.
-
-[DSBridge v3.0.0 更新列表](https://github.com/wendux/DSBridge-IOS/issues/25) 
-
-[DSBridge-Android](https://github.com/wendux/DSBridge-Android) 
-
-## 特性
-
-1. Android、IOS、Javascript 三端易用,轻量且强大、安全且健壮。
-2. 同时支持同步调用和异步调用
-3. 支持以类的方式集中统一管理API
-4. 支持API命名空间
-5. 支持调试模式
-6. 支持API存在性检测
-7. 支持进度回调:一次调用,多次返回
-8. 支持Javascript关闭页面事件回调
-9. 支持Javascript 模态/非模态对话框
-10. Android端支持腾讯X5内核
-
-## 安装
-
-```shell
-pod "dsBridge"
-```
-
-## 示例
-
-请参考工程目录下的 `dsbridgedemo/` 文件夹. 运行并查看示例交互.
-
-如果要在你自己的项目中使用 dsBridge :
-
-## 使用
-
-1. 新建一个类,实现API 
-
-   ```objective-c
-   #import "dsbridge.h" 
-   ...
-   @implementation JsApiTest
-   //同步API 
-   - (NSString *) testSyn:(NSString *) msg
-   {
-       return [msg stringByAppendingString:@"[ syn call]"];
-   }
-   //异步API
-   - (void) testAsyn:(NSString *) msg :(JSCallback)completionHandler
-   {
-       completionHandler([msg stringByAppendingString:@" [ asyn call]"],YES);
-   }
-   @end 
-   ```
-   可以看到,DSBridge正式通过API类的方式集中、统一地管理API。
-
-2. 添加API类实例到 DWKWebView 
-
-   ```objective-c
-   DWKWebView * dwebview=[[DWKWebView alloc] initWithFrame:bounds];
-   // register api object without namespace
-   [dwebview addJavascriptObject:[[JsApiTest alloc] init] namespace:nil];
-   ```
-
-3. 在Javascript中调用原生 (Java/Object-c/swift) API ,并注册一个 javascript API供原生调用.
-
-   - 初始化 dsBridge
-
-     ```javascript
-     //cdn方式引入初始化代码(中国地区慢,建议下载到本地工程)
-     //<script src="https://cdn.jsdelivr.net/npm/dsbridge@3.1.4/dist/dsbridge.js"> //</script>
-     //npm方式安装初始化代码
-     //npm install dsbridge@3.1.4
-     var dsBridge=require("dsbridge")
-     ```
-
-   - 调用原生API ,并注册一个 javascript API供原生调用.
-
-     ```javascript
-
-     //同步调用
-     var str=dsBridge.call("testSyn","testSyn");
-
-     //异步调用
-     dsBridge.call("testAsyn","testAsyn", function (v) {
-       alert(v);
-     })
-
-     //注册 javascript API 
-      dsBridge.register('addValue',function(l,r){
-          return l+r;
-      })
-     ```
-
-4. 在Object-c中调用Javascript API 
-
-    ```objective-c
-       [dwebview callHandler:@"addValue" arguments:@[@3,@4] completionHandler:^(NSNumber* value){
-              NSLog(@"%@",value);
-       }];
-    ```
-
-
-## Object-C API 签名
-
- OC API 必须符合如下签名:
-
-1. 同步API.
-
-   **`(id) handler:(id) msg`**
-
-   参数可以是任何类型, 但是返回值类型不能为 **void。** **如果不需要参数,也必须声明**,声明后不使用就行。
-   > 如果同步API返回值类型为void,调用时则会导致Crash,请务必遵守签名规范。
-
-2. 异步 API.
-
-   **` (void) handler:(id)arg :(void (^)( id result,BOOL complete))completionHandler)`**
-
-   `JSCallback` 是一个block类型:
-
-   ```objective-c
-   typedef void (^JSCallback)(NSString * _Nullable result,BOOL complete); 
-   ```
-
-> 注意:API名字**不能**以"init"开始,因为oc的类中是被预留的, 如果以"init"开始,执行结果将无法预期(很多时候会crash)。
->
-
-   
-
-## 在Swift中使用
-
-在 Swift中,你应该按照如下方式声明APIs:
-
-```swift
-//必须给第一个参数前添加下划线"_"来显式忽略参数名。
-@objc func testSyn( _ arg:String) -> String {
-	return String(format:"%@[Swift sync call:%@]", arg, "test")
-}
-
-@objc func testAsyn( _ arg:String, handler: (String, Bool)->Void) {
-	handler(String(format:"%@[Swift async call:%@]", arg, "test"), true)
-}
-```
-
-有两点必须注意:
-
-- 必须给Swift API添加 "@objc" 标注。
-- 必须给第一个参数前添加下划线"_"来显式忽略参数名
-
-完整的示例在 [这里](https://github.com/wendux/DSBridge-IOS/blob/master/dsbridgedemo/JsApiTestSwift.swift) .
-
-## 命名空间
-
-命名空间可以帮助你更好的管理API,这在API数量多的时候非常实用,比如在混合应用中。DSBridge (>= v3.0.0) 支持你通过命名空间将API分类管理,并且命名空间支持多级的,不同级之间只需用'.' 分隔即可。
-
-
-
-## 调试模式
-
-在调试模式时,发生一些错误时,将会以弹窗形式提示,并且原生API如果触发异常将不会被自动捕获,因为在调试阶段应该将问题暴露出来。如果调试模式关闭,错误将不会弹窗,并且会自动捕获API触发的异常,防止crash。强烈建议在开发阶段开启调试模式,可以通过如下代码开启调试模式:
-
-```objective-c
-// open debug mode
-[dwebview setDebugMode:true];
-```
-
-
-
-## 进度回调
-
-通常情况下,调用一个方法结束后会返回一个结果,是一一对应的。但是有时会遇到一次调用需要多次返回的场景,比如在javascript钟调用端上的一个下载文件功能,端上在下载过程中会多次通知javascript进度, 然后javascript将进度信息展示在h5页面上,这是一个典型的一次调用,多次返回的场景,如果使用其它Javascript bridge,  你将会发现要实现这个功能会比较麻烦,而DSBridge本省支持进度回调,你可以非常简单方便的实现一次调用需要多次返回的场景,下面我们实现一个倒计时的例子:
-
-In Object-c
-
-```objective-c
-- ( void )callProgress:(NSDictionary *) args :(JSCallback)completionHandler
-{
-    value=10;
-    hanlder=completionHandler;
-    timer =  [NSTimer scheduledTimerWithTimeInterval:1.0
-                                              target:self
-                                            selector:@selector(onTimer:)
-                                            userInfo:nil
-                                             repeats:YES];
-}
--(void)onTimer:t{
-    if(value!=-1){
-        hanlder([NSNumber numberWithInt:value--],NO);
-    }else{
-        hanlder(@"",YES);
-        [timer invalidate];
-    }
-}
-```
-
-In javascript
-
-```javascript
-dsBridge.call("callProgress", function (value) {
-	document.getElementById("progress").innerText = value
-})
-```
-
-完整的示例代码请参考demo工程。
-
-
-
-## Javascript 弹出框
-
-DSBridge已经实现了 Javascript的弹出框函数(alert/confirm/prompt),这些对话框按钮、标签文字默认都是中文的,如果你想自定义这些文本可以参考 `customJavascriptDialogLabelTitles` API,如果你不想使用DSBridge实现的对话框,你可以通过设置`DSUIDelegate` 属性(是WKUIDelegate的代理属性)完全自定义。
-
-另外注意,DSBridge实现的弹出框都是模态的,这会阻塞UI线程,如果你需要非模态的对话框,请参考`disableJavascriptDialogBlock` API.
-
-
-
-# WKUIDelegate
-
-在 `DWKWebView ` 中,请使用` DSUIDelegate` 代替 `UIDelegate` , 因为在`DWKWebView ` 内部 `UIDelegate`已经设置过了,而 `DSUIDelegate` 正是  `UIDelegate` 的一个代理。
-
-
-
-## API 列表
-
-### Object-C API
-
-在Object-c中我们把实现了供 javascript调用的 API类的实例 成为 **Object-c API object**.
-
-##### `addJavascriptObject:(id) object namespace:(NSString *) namespace`
-
-添加一个 Object-c API object 到DWKWebView,并为它指定一个命名空间. 然后,在 javascript 中就可以通过`bridge.call("namespace.api",...)`来调用Object-c API object中的原生API了。
-
-如果命名空间是空(nil或空字符串), 那么这个添加的  Object-c API object就没有命名空间。在 javascript 通过 `bridge.call("api",...)`调用。
-
-示例:
-
-**In Object-c**
-
-```objective-c
-@implementation JsEchoApi
-- (id) syn:(id) arg
-{
-    return arg;
-}
-- (void) asyn: (id) arg :(JSCallback)completionHandler
-{
-    completionHandler(arg,YES);
-}
-@end
-// register api object with namespace "echo"
-[dwebview addJavascriptObject:[[JsEchoApi alloc] init] namespace:@"echo"];
-```
-
-**In Javascript**
-
-```javascript
-// call echo.syn
-var ret=dsBridge.call("echo.syn",{msg:" I am echoSyn call", tag:1})
-alert(JSON.stringify(ret))  
-// call echo.asyn
-dsBridge.call("echo.asyn",{msg:" I am echoAsyn call",tag:2},function (ret) {
-      alert(JSON.stringify(ret));
-})
-```
-
-
-
-##### `removeJavascriptObject:(NSString *) namespace`
-
-通过命名空间名称移除相应的  Object-c API object.
-
-
-
-##### `callHandler:(NSString *) methodName  arguments:(NSArray *) args`
-
-##### `callHandler:(NSString *) methodName  completionHandler:(void (^)(id value))completionHandler`
-
-##### `callHandler:(NSString *) methodName  arguments:(NSArray *) args completionHandler:(void (^ )(id value))completionHandler`
-
-调用 javascript API.`methodName`  为javascript API 的名称,可以包含命名空间;参数以数组传递,`argumentss`数组中的元素依次对应javascript API的形参;  `completionHandler` 用于接收javascript API的返回值,**注意: `completionHandler`将在主线程中被执行**。
-
-示例:
-
-```objective-c
-[dwebview callHandler:@"append" arguments:@[@"I",@"love",@"you"]
-  completionHandler:^(NSString * _Nullable value) {
-       NSLog(@"call succeed, append string is: %@",value);
-}];
-// call with namespace 'syn', More details to see the Demo project                    
-[dwebview callHandler:@"syn.getInfo" completionHandler:^(NSDictionary * _Nullable value) {
-        NSLog(@"Namespace syn.getInfo: %@",value);
-}];
-```
-
-
-
-##### `disableJavascriptDialogBlock:(bool) disable`
-
-**小心使用**. 如果你再javascript中调用弹窗函数(`alert`,` confirm`, 或 `prompt`), 那么APP将会挂起,因为这些弹窗都是**模态**的,会阻塞APP主线程,此时javascript执行流也会阻塞。如果你想避免阻塞,可以通过此API禁止,禁止后,一旦 javascript中调用了这些弹窗函数,APP将弹出**非模态**对话框,并立即返回,(  `confirm` 会返回 `true`,  `prompt` 返回空字符串)。
-
-如:
-
-```objective-c
-[dwebview disableJavascriptDialogBlock: true]
-```
-
-如果你想恢复**模态**对话框,传 `false` 调用即可.
-
-
-
-##### `setJavascriptCloseWindowListener:(void(^_Nullable)(void))callback`
-
-当 Javascript中调用`window.close`时,DWKWebView会触发此监听器:
-
-Example:
-
-```objective-c
-[dwebview setJavascriptCloseWindowListener:^{
-        NSLog(@"window.close called");
-}];
-```
-
-
-
-##### `hasJavascriptMethod:(NSString*) handlerName methodExistCallback:(void(^)(bool exist))callback`
-
-检测是否存在指定的 javascript API,`handlerName`可以包含命名空间.
-
-Example:
-
-```objective-c
-// test if javascript method exists.
-[dwebview hasJavascriptMethod:@"addValue" methodExistCallback:^(bool exist) {
-      NSLog(@"method 'addValue' exist : %d",exist);
-}];
-```
-
-
-
-##### `setDebugMode:(bool) debug`
-
-设置调试模式。在调试模式时,发生一些错误时,将会以弹窗形式提示,并且原生API如果触发异常将不会被自动捕获,因为在调试阶段应该将问题暴露出来。如果调试模式关闭,错误将不会弹窗,并且会自动捕获API触发的异常,防止crash。强烈建议在开发阶段开启调试模式。
-
-
-
-##### `customJavascriptDialogLabelTitles:(NSDictionary*) dic`
-
-custom the  label text of  javascript dialog that includes alert/confirm/prompt, the default text language is Chinese.
-
-自定义 javascript对话框上按钮、标签的文本,默认的文本语言是中文,你可以自定义英文,如:
-
-```objective-c
-[dwebview customJavascriptDialogLabelTitles:@{
- @"alertTitle":@"Notification",
- @"alertBtn":@"OK",
- @"confirmTitle":@"",
- @"confirmCancelBtn":@"CANCEL",
- @"confirmOkBtn":@"OK",
- @"promptCancelBtn":@"CANCEL",
- @"promptOkBtn":@"OK"
-}];
-```
-
-
-
-### Javascript API
-
-##### dsBridge 
-
-"dsBridge" 在初始化之后可用 .
-
-##### `dsBridge.call(method,[arg,callback])`
-
-同步或异步的调用Java API。
-
-`method`: Java API 名称, 可以包含命名空间。
-
-`arg`:传递给Java API 的参数。只能传一个,如果需要多个参数时,可以合并成一个json对象参数。
-
-`callback(String returnValue)`: 处理Java API的返回结果. 可选参数,**只有异步调用时才需要提供**.
-
-
-
-##### `dsBridge.register(methodName|namespace,function|synApiObject)`
-
-##### `dsBridge.registerAsyn(methodName|namespace,function|asyApiObject)`
-
-注册同步/异步的Javascript API. 这两个方法都有两种调用形式:
-
-1. 注册一个普通的方法,如:
-
-   **In Javascript**
-
-   ```javascript
-   dsBridge.register('addValue',function(l,r){
-        return l+r;
-   })
-   dsBridge.registerAsyn('append',function(arg1,arg2,arg3,responseCallback){
-        responseCallback(arg1+" "+arg2+" "+arg3);
-   })
-   ```
-
-   **In Object-c**
-
-   ```objective-c
-   // call javascript method
-   [dwebview callHandler:@"addValue" arguments:@[@3,@4] completionHandler:^(NSNumber * value){
-         NSLog(@"%@",value);
-   }];
-
-   [dwebview callHandler:@"append" arguments:@[@"I",@"love",@"you"] completionHandler:^(NSString * _Nullable value) {
-        NSLog(@"call succeed, append string is: %@",value);
-   }];
-   ```
-
-   ​
-
-2. 注册一个对象,指定一个命名空间:
-
-   **In Javascript**
-
-   ```java
-   //namespace test for synchronous
-   dsBridge.register("test",{
-     tag:"test",
-     test1:function(){
-   	return this.tag+"1"
-     },
-     test2:function(){
-   	return this.tag+"2"
-     }
-   })
-     
-   //namespace test1 for asynchronous calls  
-   dsBridge.registerAsyn("test1",{
-     tag:"test1",
-     test1:function(responseCallback){
-   	return responseCallback(this.tag+"1")
-     },
-     test2:function(responseCallback){
-   	return responseCallback(this.tag+"2")
-     }
-   })
-   ```
-
-   > 因为Javascript并不支持函数重载,所以不能在同一个Javascript对象中定义同名的同步函数和异步函数
-
-   **In Object-c**
-
-   ```objective-c
-   [dwebview callHandler:@"test.test1" completionHandler:^(NSString * _Nullable value) {
-           NSLog(@"Namespace test.test1: %@",value);
-   }];
-
-   [dwebview callHandler:@"test1.test1" completionHandler:^(NSString * _Nullable value) {
-           NSLog(@"Namespace test1.test1: %@",value);
-   }];
-   ```
-
-
-
-
-##### `dsBridge.hasNativeMethod(handlerName,[type])`
-
-检测Java中是否存在名为`handlerName`的API, `handlerName` 可以包含命名空间. 
-
-`type`: 可选参数,`["all"|"syn"|"asyn" ]`, 默认是 "all".
-
-```javascript
-//检测是否存在一个名为'testAsyn'的API(无论同步还是异步)
-dsBridge.hasNativeMethod('testAsyn') 
-//检测test命名空间下是否存在一个’testAsyn’的API
-dsBridge.hasNativeMethod('test.testAsyn')
-// 检测是否存在一个名为"testSyn"的异步API
-dsBridge.hasNativeMethod('testSyn','asyn') //false
-```
-
-
-##### `dsBridge.disableJavascriptDialogBlock(disable)`
-
-调用 `dsBridge.disableJavascriptDialogBlock(...)` 和在Java中调用 `dwebview.disableJavascriptDialogBlock(...)` 作用一样.
-
-示例:
-
-```javascript
-//disable
-dsBridge.disableJavascriptDialogBlock()
-//enable
-dsBridge.disableJavascriptDialogBlock(false)
-```
-
-
-## 和 fly.js一起使用
-
-当dsBridge遇见  [Fly.js](https://github.com/wendux/fly)  时,将会打开一个新的世界。[fly.js传送门](https://github.com/wendux/fly)
-
-正如我们所知,在浏览器中,ajax请求受同源策略限制,不能跨域请求资源。然而,  [Fly.js](https://github.com/wendux/fly) 有一个强大的功能就是支持请求重定向:将ajax请求通过任何Javascript bridge重定向到端上,并且 [Fly.js](https://github.com/wendux/fly) 官方已经提供的 dsBridge 的 adapter, 可以非常方便的协同dsBridge一起使用。由于端上没有同源策略的限制,所以 fly.js可以请求任何域的资源。
-
-另一个典型的使用场景是在混合APP中,由于[Fly.js](https://github.com/wendux/fly) 可以将所有ajax请求转发到端上,所以,开发者就可以在端上进行统一的请求管理、证书校验、cookie管理、访问控制等。
-
-详情请参考 https://github.com/wendux/fly.  (DSBridge Android版 demo中包含fly.js的示例)
-
-
-
-## 最后
-
-如果你喜欢 DSBridge, 欢迎star,以便更多的人知道它, 谢谢 !
-
-

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