chemin 3 週間 前
コミット
76ea16330f
43 ファイル変更2233 行追加414 行削除
  1. 22 246
      MSYOUPAI.xcodeproj/project.pbxproj
  2. 1 1
      MSYOUPAI.xcodeproj/xcshareddata/xcschemes/MSYOUPAI.xcscheme
  3. BIN
      MSYOUPAI.xcworkspace/xcuserdata/macmini.xcuserdatad/UserInterfaceState.xcuserstate
  4. BIN
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/Info.plist
  5. 488 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/ct4.js
  6. BIN
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/en.lproj/AlicomCaptcha4.strings
  7. 375 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/gt4-index-alicom.html
  8. BIN
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/gt4-loading.gif
  9. BIN
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/zh-CN.lproj/AlicomCaptcha4.strings
  10. BIN
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/AlicomCaptcha4
  11. 66 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Headers/AlicomC4Error.h
  12. 21 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Headers/AlicomCaptcha4.h
  13. 103 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Headers/AlicomCaptcha4Session.h
  14. 83 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Headers/AlicomCaptcha4SessionConfiguration.h
  15. 51 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Info.plist
  16. 6 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Modules/module.modulemap
  17. 22 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/PrivacyInfo.xcprivacy
  18. BIN
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeDirectory
  19. BIN
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeRequirements
  20. BIN
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeRequirements-1
  21. 177 0
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeResources
  22. BIN
      MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeSignature
  23. 20 0
      MSYOUPAI/AlicomCaptcha/CaptchaCenter.h
  24. 99 0
      MSYOUPAI/AlicomCaptcha/CaptchaCenter.m
  25. 47 34
      MSYOUPAI/Class/YQProfile/青少年模式/YOUPAILPYoungForgetPWD.m
  26. 31 0
      MSYOUPAI/NewCode/CustomPopupView/YMCaptchaPopupView.h
  27. 271 0
      MSYOUPAI/NewCode/CustomPopupView/YMCaptchaPopupView.m
  28. 54 20
      MSYOUPAI/NewCode/Module/Register/View/YMRegisterView.m
  29. 2 1
      MSYOUPAI/NewCode/Module/Register/ViewModel/YMRegisterViewModel.h
  30. 12 5
      MSYOUPAI/NewCode/Module/Register/ViewModel/YMRegisterViewModel.m
  31. 54 19
      MSYOUPAI/NewCode/Module/RetrievePassword/View/YMRetrievePasswordView.m
  32. 1 1
      MSYOUPAI/NewCode/Module/RetrievePassword/ViewModel/YMRetrievePasswordViewModel.h
  33. 12 5
      MSYOUPAI/NewCode/Module/RetrievePassword/ViewModel/YMRetrievePasswordViewModel.m
  34. 54 20
      MSYOUPAI/NewCode/Module/VerifyCodeLogin/View/YMVerifyCodeLoginView.m
  35. 1 1
      MSYOUPAI/NewCode/Module/VerifyCodeLogin/ViewModel/YMVerifyCodeLoginViewModel.h
  36. 12 5
      MSYOUPAI/NewCode/Module/VerifyCodeLogin/ViewModel/YMVerifyCodeLoginViewModel.m
  37. 4 4
      MSYOUPAI/Others/Utils/Helper/LCHttpHelper.m
  38. 5 6
      MSYOUPAI/Others/Utils/LPSecureData.m
  39. 20 0
      MSYOUPAI/VQBase/config/MSYOUPAI.pch
  40. 4 2
      MSYOUPAI/VQBase/config/ServerURL.h
  41. 0 22
      MSYOUPAITests/Info.plist
  42. 0 22
      MSYOUPAIUITests/Info.plist
  43. 115 0
      Pods/Pods.xcodeproj/xcuserdata/macmini.xcuserdatad/xcschemes/xcschememanagement.plist

+ 22 - 246
MSYOUPAI.xcodeproj/project.pbxproj

@@ -546,13 +546,12 @@
 		89BF487A2BD0C6610080DAD7 /* YMHomeChildController.m in Sources */ = {isa = PBXBuildFile; fileRef = 89BF48792BD0C6610080DAD7 /* YMHomeChildController.m */; };
 		89BF487D2BD2395B0080DAD7 /* YMHomeChildCollectCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 89BF487C2BD2395B0080DAD7 /* YMHomeChildCollectCell.m */; };
 		89BF48802BD662300080DAD7 /* YMRankTopView.m in Sources */ = {isa = PBXBuildFile; fileRef = 89BF487F2BD662300080DAD7 /* YMRankTopView.m */; };
+		9A6E5CBA2E0F7F6B003BAC9C /* YMCaptchaPopupView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A6E5CB92E0F7F6B003BAC9C /* YMCaptchaPopupView.m */; };
 		9AD658342C39396A006C41CE /* YMPersonalPageAboutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD658332C39396A006C41CE /* YMPersonalPageAboutView.m */; };
 		B39F7B3C244E92A3006127E3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B39F7B3B244E92A3006127E3 /* AppDelegate.m */; };
 		B39F7B42244E92A3006127E3 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B39F7B41244E92A3006127E3 /* ViewController.m */; };
 		B39F7B45244E92A3006127E3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B39F7B43244E92A3006127E3 /* Main.storyboard */; };
 		B39F7B4A244E92A4006127E3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B39F7B48244E92A4006127E3 /* LaunchScreen.storyboard */; };
-		B39F7B57244E92A4006127E3 /* MSYOUPAITests.m in Sources */ = {isa = PBXBuildFile; fileRef = B39F7B56244E92A4006127E3 /* MSYOUPAITests.m */; };
-		B39F7B62244E92A4006127E3 /* MSYOUPAIUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = B39F7B61244E92A4006127E3 /* MSYOUPAIUITests.m */; };
 		B39F7B73244EA2DA006127E3 /* YOUPAISYBaseCollectionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = B39F7B72244EA2DA006127E3 /* YOUPAISYBaseCollectionCell.m */; };
 		B39F7B77244EA3DC006127E3 /* YOUPAISYBaseTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = B39F7B76244EA3DC006127E3 /* YOUPAISYBaseTableCell.m */; };
 		B39F8323244ECD21006127E3 /* YOUPAILCDynamicModel.m in Sources */ = {isa = PBXBuildFile; fileRef = B39F7B7A244ECD1D006127E3 /* YOUPAILCDynamicModel.m */; };
@@ -1742,23 +1741,6 @@
 		EDEE56252B83158500C5F446 /* NSObject+Swizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = EDEE56232B83158500C5F446 /* NSObject+Swizzle.m */; };
 /* End PBXBuildFile section */
 
-/* Begin PBXContainerItemProxy section */
-		B39F7B53244E92A4006127E3 /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = B39F7B2F244E92A3006127E3 /* Project object */;
-			proxyType = 1;
-			remoteGlobalIDString = B39F7B36244E92A3006127E3;
-			remoteInfo = SIYE;
-		};
-		B39F7B5E244E92A4006127E3 /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = B39F7B2F244E92A3006127E3 /* Project object */;
-			proxyType = 1;
-			remoteGlobalIDString = B39F7B36244E92A3006127E3;
-			remoteInfo = SIYE;
-		};
-/* End PBXContainerItemProxy section */
-
 /* Begin PBXCopyFilesBuildPhase section */
 		B39F86A2244EDFA2006127E3 /* CopyFiles */ = {
 			isa = PBXCopyFilesBuildPhase;
@@ -2841,6 +2823,8 @@
 		89BF487F2BD662300080DAD7 /* YMRankTopView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YMRankTopView.m; sourceTree = "<group>"; };
 		8AC988D2D0AE53622E4887A2 /* Pods-MSYOUPAI.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MSYOUPAI.debug.xcconfig"; path = "Target Support Files/Pods-MSYOUPAI/Pods-MSYOUPAI.debug.xcconfig"; sourceTree = "<group>"; };
 		968A35C61C7077187A06BF31 /* Pods-MSYOUPAI.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MSYOUPAI.release.xcconfig"; path = "Target Support Files/Pods-MSYOUPAI/Pods-MSYOUPAI.release.xcconfig"; sourceTree = "<group>"; };
+		9A6E5CB82E0F7F6B003BAC9C /* YMCaptchaPopupView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YMCaptchaPopupView.h; sourceTree = "<group>"; };
+		9A6E5CB92E0F7F6B003BAC9C /* YMCaptchaPopupView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YMCaptchaPopupView.m; sourceTree = "<group>"; };
 		9AD658322C39396A006C41CE /* YMPersonalPageAboutView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YMPersonalPageAboutView.h; sourceTree = "<group>"; };
 		9AD658332C39396A006C41CE /* YMPersonalPageAboutView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YMPersonalPageAboutView.m; sourceTree = "<group>"; };
 		B39F7B37244E92A3006127E3 /* MSYOUPAI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MSYOUPAI.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -2851,12 +2835,6 @@
 		B39F7B44244E92A3006127E3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
 		B39F7B49244E92A4006127E3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 		B39F7B4B244E92A4006127E3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		B39F7B52244E92A4006127E3 /* MSYOUPAITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MSYOUPAITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-		B39F7B56244E92A4006127E3 /* MSYOUPAITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSYOUPAITests.m; sourceTree = "<group>"; };
-		B39F7B58244E92A4006127E3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		B39F7B5D244E92A4006127E3 /* MSYOUPAIUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MSYOUPAIUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-		B39F7B61244E92A4006127E3 /* MSYOUPAIUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSYOUPAIUITests.m; sourceTree = "<group>"; };
-		B39F7B63244E92A4006127E3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		B39F7B71244EA2DA006127E3 /* YOUPAISYBaseCollectionCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YOUPAISYBaseCollectionCell.h; sourceTree = "<group>"; };
 		B39F7B72244EA2DA006127E3 /* YOUPAISYBaseCollectionCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YOUPAISYBaseCollectionCell.m; sourceTree = "<group>"; };
 		B39F7B75244EA3DC006127E3 /* YOUPAISYBaseTableCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YOUPAISYBaseTableCell.h; sourceTree = "<group>"; };
@@ -5250,6 +5228,14 @@
 		EDEE56242B83158500C5F446 /* NSObject+Swizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+Swizzle.h"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
+/* Begin PBXFileSystemSynchronizedRootGroup section */
+		9A6E5CB32E0ECD8E003BAC9C /* AlicomCaptcha */ = {
+			isa = PBXFileSystemSynchronizedRootGroup;
+			path = AlicomCaptcha;
+			sourceTree = "<group>";
+		};
+/* End PBXFileSystemSynchronizedRootGroup section */
+
 /* Begin PBXFrameworksBuildPhase section */
 		B39F7B34244E92A3006127E3 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
@@ -5295,20 +5281,6 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
-		B39F7B4F244E92A4006127E3 /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-		B39F7B5A244E92A4006127E3 /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
@@ -6720,8 +6692,6 @@
 			isa = PBXGroup;
 			children = (
 				B39F7B39244E92A3006127E3 /* MSYOUPAI */,
-				B39F7B55244E92A4006127E3 /* MSYOUPAITests */,
-				B39F7B60244E92A4006127E3 /* MSYOUPAIUITests */,
 				B39F7B38244E92A3006127E3 /* Products */,
 				B39F8679244EDB5E006127E3 /* Frameworks */,
 				FA49D0E8A58FBEBD14D1FB4B /* Pods */,
@@ -6732,8 +6702,6 @@
 			isa = PBXGroup;
 			children = (
 				B39F7B37244E92A3006127E3 /* MSYOUPAI.app */,
-				B39F7B52244E92A4006127E3 /* MSYOUPAITests.xctest */,
-				B39F7B5D244E92A4006127E3 /* MSYOUPAIUITests.xctest */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -6741,6 +6709,7 @@
 		B39F7B39244E92A3006127E3 /* MSYOUPAI */ = {
 			isa = PBXGroup;
 			children = (
+				9A6E5CB32E0ECD8E003BAC9C /* AlicomCaptcha */,
 				440D3CB52DF15F7100249B04 /* 澜极美颜 */,
 				EDEE53EA2B83121700C5F446 /* NewCode */,
 				CB2D5474275F601E0010BF80 /* Others */,
@@ -6770,24 +6739,6 @@
 			path = MSYOUPAI;
 			sourceTree = "<group>";
 		};
-		B39F7B55244E92A4006127E3 /* MSYOUPAITests */ = {
-			isa = PBXGroup;
-			children = (
-				B39F7B56244E92A4006127E3 /* MSYOUPAITests.m */,
-				B39F7B58244E92A4006127E3 /* Info.plist */,
-			);
-			path = MSYOUPAITests;
-			sourceTree = "<group>";
-		};
-		B39F7B60244E92A4006127E3 /* MSYOUPAIUITests */ = {
-			isa = PBXGroup;
-			children = (
-				B39F7B61244E92A4006127E3 /* MSYOUPAIUITests.m */,
-				B39F7B63244E92A4006127E3 /* Info.plist */,
-			);
-			path = MSYOUPAIUITests;
-			sourceTree = "<group>";
-		};
 		B39F7B6F244EA264006127E3 /* SYBaceCell */ = {
 			isa = PBXGroup;
 			children = (
@@ -12532,6 +12483,8 @@
 			children = (
 				EDEE55312B83121700C5F446 /* YMServicePolicyPopupView.h */,
 				EDEE55352B83121700C5F446 /* YMServicePolicyPopupView.m */,
+				9A6E5CB82E0F7F6B003BAC9C /* YMCaptchaPopupView.h */,
+				9A6E5CB92E0F7F6B003BAC9C /* YMCaptchaPopupView.m */,
 				EDEE55342B83121700C5F446 /* YMLoginRegistrAgreementPopupView.h */,
 				EDEE55302B83121700C5F446 /* YMLoginRegistrAgreementPopupView.m */,
 				EDCBCD492B87451E00A65CA6 /* YMOpenAdolescentModelPopupView.h */,
@@ -12730,47 +12683,14 @@
 			);
 			dependencies = (
 			);
+			fileSystemSynchronizedGroups = (
+				9A6E5CB32E0ECD8E003BAC9C /* AlicomCaptcha */,
+			);
 			name = MSYOUPAI;
 			productName = SIYE;
 			productReference = B39F7B37244E92A3006127E3 /* MSYOUPAI.app */;
 			productType = "com.apple.product-type.application";
 		};
-		B39F7B51244E92A4006127E3 /* MSYOUPAITests */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = B39F7B69244E92A4006127E3 /* Build configuration list for PBXNativeTarget "MSYOUPAITests" */;
-			buildPhases = (
-				B39F7B4E244E92A4006127E3 /* Sources */,
-				B39F7B4F244E92A4006127E3 /* Frameworks */,
-				B39F7B50244E92A4006127E3 /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-				B39F7B54244E92A4006127E3 /* PBXTargetDependency */,
-			);
-			name = MSYOUPAITests;
-			productName = SIYETests;
-			productReference = B39F7B52244E92A4006127E3 /* MSYOUPAITests.xctest */;
-			productType = "com.apple.product-type.bundle.unit-test";
-		};
-		B39F7B5C244E92A4006127E3 /* MSYOUPAIUITests */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = B39F7B6C244E92A4006127E3 /* Build configuration list for PBXNativeTarget "MSYOUPAIUITests" */;
-			buildPhases = (
-				B39F7B59244E92A4006127E3 /* Sources */,
-				B39F7B5A244E92A4006127E3 /* Frameworks */,
-				B39F7B5B244E92A4006127E3 /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-				B39F7B5F244E92A4006127E3 /* PBXTargetDependency */,
-			);
-			name = MSYOUPAIUITests;
-			productName = SIYEUITests;
-			productReference = B39F7B5D244E92A4006127E3 /* MSYOUPAIUITests.xctest */;
-			productType = "com.apple.product-type.bundle.ui-testing";
-		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
@@ -12786,14 +12706,6 @@
 						CreatedOnToolsVersion = 11.4.1;
 						LastSwiftMigration = 1330;
 					};
-					B39F7B51244E92A4006127E3 = {
-						CreatedOnToolsVersion = 11.4.1;
-						TestTargetID = B39F7B36244E92A3006127E3;
-					};
-					B39F7B5C244E92A4006127E3 = {
-						CreatedOnToolsVersion = 11.4.1;
-						TestTargetID = B39F7B36244E92A3006127E3;
-					};
 				};
 			};
 			buildConfigurationList = B39F7B32244E92A3006127E3 /* Build configuration list for PBXProject "MSYOUPAI" */;
@@ -12811,8 +12723,6 @@
 			projectRoot = "";
 			targets = (
 				B39F7B36244E92A3006127E3 /* MSYOUPAI */,
-				B39F7B51244E92A4006127E3 /* MSYOUPAITests */,
-				B39F7B5C244E92A4006127E3 /* MSYOUPAIUITests */,
 			);
 		};
 /* End PBXProject section */
@@ -12892,20 +12802,6 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
-		B39F7B50244E92A4006127E3 /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-		B39F7B5B244E92A4006127E3 /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
@@ -13626,6 +13522,7 @@
 				B39F8427244ECD22006127E3 /* NIMTeamMemberCardHeaderCell.m in Sources */,
 				B39F85B3244ECD23006127E3 /* YOUPAILCGiftModel.m in Sources */,
 				23287ADA2BAAFA62003CCFAA /* UIViewController+TZImagePickerController.m in Sources */,
+				9A6E5CBA2E0F7F6B003BAC9C /* YMCaptchaPopupView.m in Sources */,
 				01AB617927367F73006B803F /* YOUPAILZChatRoomUpSeatApplyWindow.m in Sources */,
 				019BB5FA27609F1200C0E5D9 /* NSURLRequest+SRWebSocket.m in Sources */,
 				CB53B61927435A5A00CC3BF8 /* YOUPAIHRSearchResultVC.m in Sources */,
@@ -14641,37 +14538,8 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
-		B39F7B4E244E92A4006127E3 /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				B39F7B57244E92A4006127E3 /* MSYOUPAITests.m in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-		B39F7B59244E92A4006127E3 /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				B39F7B62244E92A4006127E3 /* MSYOUPAIUITests.m in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
 /* End PBXSourcesBuildPhase section */
 
-/* Begin PBXTargetDependency section */
-		B39F7B54244E92A4006127E3 /* PBXTargetDependency */ = {
-			isa = PBXTargetDependency;
-			target = B39F7B36244E92A3006127E3 /* MSYOUPAI */;
-			targetProxy = B39F7B53244E92A4006127E3 /* PBXContainerItemProxy */;
-		};
-		B39F7B5F244E92A4006127E3 /* PBXTargetDependency */ = {
-			isa = PBXTargetDependency;
-			target = B39F7B36244E92A3006127E3 /* MSYOUPAI */;
-			targetProxy = B39F7B5E244E92A4006127E3 /* PBXContainerItemProxy */;
-		};
-/* End PBXTargetDependency section */
-
 /* Begin PBXVariantGroup section */
 		440D3D782DF1769000249B04 /* PFAPIDemoBar.xib */ = {
 			isa = PBXVariantGroup;
@@ -14880,6 +14748,7 @@
 					"$(PROJECT_DIR)/MSYOUPAI/NewCode/SDPay",
 					"$(PROJECT_DIR)/MSYOUPAI/澜极美颜",
 					"$(PROJECT_DIR)/MSYOUPAI/澜极美颜/res",
+					"$(PROJECT_DIR)/MSYOUPAI/AlicomCaptcha",
 				);
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_PREFIX_HEADER = "$(SRCROOT)/MSYOUPAI/VQBase/config/MSYOUPAI.pch";
@@ -14899,7 +14768,7 @@
 					"$(PROJECT_DIR)/MSYOUPAI/3rd/TalkingData",
 					"$(PROJECT_DIR)/MSYOUPAI/3rd/Talkingdata",
 				);
-				MARKETING_VERSION = 2.0.1;
+				MARKETING_VERSION = 1.0.0;
 				ONLY_ACTIVE_ARCH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.tianshangrenjian.sheng;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -14937,6 +14806,7 @@
 					"$(PROJECT_DIR)/MSYOUPAI/NewCode/SDPay",
 					"$(PROJECT_DIR)/MSYOUPAI/澜极美颜",
 					"$(PROJECT_DIR)/MSYOUPAI/澜极美颜/res",
+					"$(PROJECT_DIR)/MSYOUPAI/AlicomCaptcha",
 				);
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_PREFIX_HEADER = "$(SRCROOT)/MSYOUPAI/VQBase/config/MSYOUPAI.pch";
@@ -14956,7 +14826,7 @@
 					"$(PROJECT_DIR)/MSYOUPAI/3rd/TalkingData",
 					"$(PROJECT_DIR)/MSYOUPAI/3rd/Talkingdata",
 				);
-				MARKETING_VERSION = 2.0.1;
+				MARKETING_VERSION = 1.0.0;
 				PRODUCT_BUNDLE_IDENTIFIER = com.tianshangrenjian.sheng;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -14968,82 +14838,6 @@
 			};
 			name = Release;
 		};
-		B39F7B6A244E92A4006127E3 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				BUNDLE_LOADER = "$(TEST_HOST)";
-				CODE_SIGN_STYLE = Automatic;
-				DEVELOPMENT_TEAM = A28977DMGP;
-				INFOPLIST_FILE = MSYOUPAITests/Info.plist;
-				IPHONEOS_DEPLOYMENT_TARGET = 13.4;
-				LD_RUNPATH_SEARCH_PATHS = (
-					"$(inherited)",
-					"@executable_path/Frameworks",
-					"@loader_path/Frameworks",
-				);
-				PRODUCT_BUNDLE_IDENTIFIER = leo.MSYOUPAITests;
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				TARGETED_DEVICE_FAMILY = "1,2";
-				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MSYOUPAI.app/MSYOUPAI";
-			};
-			name = Debug;
-		};
-		B39F7B6B244E92A4006127E3 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				BUNDLE_LOADER = "$(TEST_HOST)";
-				CODE_SIGN_STYLE = Automatic;
-				DEVELOPMENT_TEAM = A28977DMGP;
-				INFOPLIST_FILE = MSYOUPAITests/Info.plist;
-				IPHONEOS_DEPLOYMENT_TARGET = 13.4;
-				LD_RUNPATH_SEARCH_PATHS = (
-					"$(inherited)",
-					"@executable_path/Frameworks",
-					"@loader_path/Frameworks",
-				);
-				PRODUCT_BUNDLE_IDENTIFIER = leo.MSYOUPAITests;
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				TARGETED_DEVICE_FAMILY = "1,2";
-				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MSYOUPAI.app/MSYOUPAI";
-			};
-			name = Release;
-		};
-		B39F7B6D244E92A4006127E3 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				CODE_SIGN_STYLE = Automatic;
-				DEVELOPMENT_TEAM = A28977DMGP;
-				INFOPLIST_FILE = MSYOUPAIUITests/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = (
-					"$(inherited)",
-					"@executable_path/Frameworks",
-					"@loader_path/Frameworks",
-				);
-				PRODUCT_BUNDLE_IDENTIFIER = leo.MSYOUPAIUITests;
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				TARGETED_DEVICE_FAMILY = "1,2";
-				TEST_TARGET_NAME = MSYOUPAI;
-			};
-			name = Debug;
-		};
-		B39F7B6E244E92A4006127E3 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				CODE_SIGN_STYLE = Automatic;
-				DEVELOPMENT_TEAM = A28977DMGP;
-				INFOPLIST_FILE = MSYOUPAIUITests/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = (
-					"$(inherited)",
-					"@executable_path/Frameworks",
-					"@loader_path/Frameworks",
-				);
-				PRODUCT_BUNDLE_IDENTIFIER = leo.MSYOUPAIUITests;
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				TARGETED_DEVICE_FAMILY = "1,2";
-				TEST_TARGET_NAME = MSYOUPAI;
-			};
-			name = Release;
-		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
@@ -15065,24 +14859,6 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		B39F7B69244E92A4006127E3 /* Build configuration list for PBXNativeTarget "MSYOUPAITests" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				B39F7B6A244E92A4006127E3 /* Debug */,
-				B39F7B6B244E92A4006127E3 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		B39F7B6C244E92A4006127E3 /* Build configuration list for PBXNativeTarget "MSYOUPAIUITests" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				B39F7B6D244E92A4006127E3 /* Debug */,
-				B39F7B6E244E92A4006127E3 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
 /* End XCConfigurationList section */
 	};
 	rootObject = B39F7B2F244E92A3006127E3 /* Project object */;

+ 1 - 1
MSYOUPAI.xcodeproj/xcshareddata/xcschemes/MSYOUPAI.xcscheme

@@ -72,7 +72,7 @@
       buildConfiguration = "Debug">
    </AnalyzeAction>
    <ArchiveAction
-      buildConfiguration = "Release"
+      buildConfiguration = "Debug"
       revealArchiveInOrganizer = "YES">
    </ArchiveAction>
 </Scheme>

BIN
MSYOUPAI.xcworkspace/xcuserdata/macmini.xcuserdatad/UserInterfaceState.xcuserstate


BIN
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/Info.plist


+ 488 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/ct4.js

@@ -0,0 +1,488 @@
+"v1.0.0 Captcha4 Inc.";
+
+(function (window) {
+    "use strict";
+    if (typeof window === 'undefined') {
+        throw new Error('Captcha4 requires browser environment');
+    }
+
+var document = window.document;
+var Math = window.Math;
+var head = document.getElementsByTagName("head")[0];
+var TIMEOUT = 10000;
+
+function _Object(obj) {
+    this._obj = obj;
+}
+
+_Object.prototype = {
+    _each: function (process) {
+        var _obj = this._obj;
+        for (var k in _obj) {
+            if (_obj.hasOwnProperty(k)) {
+                process(k, _obj[k]);
+            }
+        }
+        return this;
+    },
+    _extend: function (obj){
+        var self = this;
+        new _Object(obj)._each(function (key, value){
+            self._obj[key] = value;
+        })
+    }
+};
+
+var uuid = function () {
+        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+            var r = Math.random() * 16 | 0;
+            var v = c === 'x' ? r : (r & 0x3 | 0x8);
+            return v.toString(16);
+        });
+    };
+
+function Config(config) {
+    var self = this;
+    new _Object(config)._each(function (key, value) {
+        self[key] = value;
+    });
+}
+
+Config.prototype = {
+    apiServers: ['captcha.alicaptcha.com'],
+    staticServers: ["static.alicaptcha.com"],
+    protocol: 'http://',
+    typePath: '/load',
+    fallback_config: {
+        bypass: {
+            staticServers: ["static.alicaptcha.com"],
+            type: 'bypass',
+            bypass: '/v4/alibypass.js'
+        }
+    },
+    _get_fallback_config: function () {
+        var self = this;
+        if (isString(self.type)) {
+            return self.fallback_config[self.type];
+        } else {
+            return self.fallback_config.bypass;
+        }
+    },
+    _extend: function (obj) {
+        var self = this;
+        new _Object(obj)._each(function (key, value) {
+            self[key] = value;
+        })
+    }
+};
+var isNumber = function (value) {
+    return (typeof value === 'number');
+};
+var isString = function (value) {
+    return (typeof value === 'string');
+};
+var isBoolean = function (value) {
+    return (typeof value === 'boolean');
+};
+var isObject = function (value) {
+    return (typeof value === 'object' && value !== null);
+};
+var isFunction = function (value) {
+    return (typeof value === 'function');
+};
+var MOBILE = /Mobi/i.test(navigator.userAgent);
+
+var callbacks = {};
+var status = {};
+
+var random = function () {
+    return parseInt(Math.random() * 10000) + (new Date()).valueOf();
+};
+
+// bind 函数polify, 不带new功能的bind
+
+var bind = function(target,context){
+    if(typeof target !== 'function'){
+        return;
+    }
+    var args = Array.prototype.slice.call(arguments,2);
+
+    if(Function.prototype.bind){
+        return target.bind(context, args);
+    }else {
+        return function(){
+            var _args = Array.prototype.slice.call(arguments);
+            return target.apply(context,args.concat(_args));
+        }
+    }
+}
+
+
+
+var toString = Object.prototype.toString;
+
+var _isFunction = function(obj) {
+  return typeof(obj) === 'function';
+};
+var _isObject = function(obj) {
+  return obj === Object(obj);
+};
+var _isArray = function(obj) {
+  return toString.call(obj) == '[object Array]';
+};
+var _isDate = function(obj) {
+  return toString.call(obj) == '[object Date]';
+};
+var _isRegExp = function(obj) {
+  return toString.call(obj) == '[object RegExp]';
+};
+var _isBoolean = function(obj) {
+  return toString.call(obj) == '[object Boolean]';
+};
+
+
+function resolveKey(input){
+  return  input.replace(/(\S)(_([a-zA-Z]))/g, function(match, $1, $2, $3){
+          return $1 + $3.toUpperCase() || "";
+  })
+}
+
+function camelizeKeys(input, convert){
+  if(!_isObject(input) || _isDate(input) || _isRegExp(input) || _isBoolean(input) || _isFunction(input)){
+      return convert ? resolveKey(input) : input;
+  }
+
+  if(_isArray(input)){
+      var temp = [];
+      for(var i = 0; i < input.length; i++){
+          temp.push(camelizeKeys(input[i]));
+      }
+
+  }else {
+      var temp = {};
+      for(var prop in input){
+          if(input.hasOwnProperty(prop)){
+              temp[camelizeKeys(prop, true)] = camelizeKeys(input[prop]);
+          }
+      }
+  }
+  return temp;
+}
+
+var loadScript = function (url, cb, timeout) {
+    var script = document.createElement("script");
+    script.charset = "UTF-8";
+    script.async = true;
+
+    // 对geetest的静态资源添加 crossOrigin
+    if ( /static\.geetest\.com/g.test(url)) {
+        script.crossOrigin = "anonymous";
+    }
+
+    script.onerror = function () {
+        cb(true);
+        // 错误触发了,超时逻辑就不用了
+        loaded = true;
+    };
+    var loaded = false;
+    script.onload = script.onreadystatechange = function () {
+        if (!loaded &&
+            (!script.readyState ||
+            "loaded" === script.readyState ||
+            "complete" === script.readyState)) {
+
+            loaded = true;
+            setTimeout(function () {
+                cb(false);
+            }, 0);
+        }
+    };
+    script.src = url;
+    head.appendChild(script);
+
+    setTimeout(function () {
+        if (!loaded) {
+            script.onerror = script.onload = null;
+            script.remove && script.remove();
+            cb(true);
+        }
+    }, timeout || TIMEOUT);
+};
+
+var normalizeDomain = function (domain) {
+    // special domain: uems.sysu.edu.cn/jwxt/geetest/
+    // return domain.replace(/^https?:\/\/|\/.*$/g, ''); uems.sysu.edu.cn
+    return domain.replace(/^https?:\/\/|\/$/g, ''); // uems.sysu.edu.cn/jwxt/geetest
+};
+var normalizePath = function (path) {
+    path = path && path.replace(/\/+/g, '/');
+    if (path.indexOf('/') !== 0) {
+        path = '/' + path;
+    }
+    return path;
+};
+var normalizeQuery = function (query) {
+    if (!query) {
+        return '';
+    }
+    var q = '?';
+    new _Object(query)._each(function (key, value) {
+        if (isString(value) || isNumber(value) || isBoolean(value)) {
+            q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
+        }
+    });
+    if (q === '?') {
+        q = '';
+    }
+    return q.replace(/&$/, '');
+};
+var makeURL = function (protocol, domain, path, query) {
+    domain = normalizeDomain(domain);
+
+    var url = normalizePath(path) + normalizeQuery(query);
+    if (domain) {
+        url = protocol + domain + url;
+    }
+
+    return url;
+};
+
+var load = function (config, protocol, domains, path, query, cb, handleCb) {
+    var tryRequest = function (at) {
+        // 处理jsonp回调,这里为了保证每个不同jsonp都有唯一的回调函数
+        if(handleCb){
+            var cbName = "captcha4_" + random();
+            // 需要与预先定义好cbname参数,删除对象
+            window[cbName] = bind(handleCb, null, cbName);
+            query.callback = cbName;
+        }
+        var url = makeURL(protocol, domains[at], path, query);
+        loadScript(url, function (err) {
+            if (err) {
+                // 超时或者出错的时候 移除回调
+                if(cbName){
+                  try {
+                     window[cbName] = function(){
+                       window[cbName] = null;
+                      }
+                    } catch (e) {}
+                }
+
+                if (at >= domains.length - 1) {
+                    cb(true);
+                    // report gettype error
+                } else {
+                    tryRequest(at + 1);
+                }
+            } else {
+                cb(false);
+            }
+        }, config.timeout);
+    };
+    tryRequest(0);
+};
+
+
+var jsonp = function (domains, path, config, callback) {
+
+    var handleCb = function (cbName, data) {
+
+        // 保证只执行一次,全部超时的情况下不会再触发;
+
+        if (data.status == 'success') {
+            callback(data.data);
+        } else if (!data.status) {
+            callback(data);
+        } else {
+            //接口有返回,但是返回了错误状态,进入报错逻辑
+            callback(data);
+        }
+        window[cbName] = undefined;
+        try {
+            delete window[cbName];
+        } catch (e) {
+        }
+    };
+    load(config, config.protocol, domains, path, {
+        callback: '',
+        captcha_id: config.captchaId,
+        challenge: config.challenge || uuid(),
+        client_type: MOBILE? 'h5':'web',
+        risk_type: config.riskType,
+        user_info: config.userInfo,
+        call_type: config.callType,
+        lang: config.language? config.language : navigator.appName === 'Netscape' ? navigator.language.toLowerCase() : navigator.userLanguage.toLowerCase()
+    }, function (err) {
+        // 网络问题接口没有返回,直接使用本地验证码,走宕机模式
+        // 这里可以添加用户的逻辑
+            if(err && typeof config.offlineCb === 'function'){
+                // 执行自己的宕机
+                config.offlineCb();
+                return;
+            }
+           if(err){
+            callback(config._get_fallback_config());
+           }
+    }, handleCb);
+};
+
+var reportError = function (config, url) {
+    load(config, config.protocol, ['monitor.geetest.com'], '/monitor/send', {
+        time: Date.now().getTime(),
+        captcha_id: config.gt,
+        challenge: config.challenge,
+        exception_url: url,
+        error_code: config.error_code
+    }, function (err) {})
+}
+
+var throwError = function (errorType, config, errObj) {
+    var errors = {
+        networkError: '网络错误',
+        gtTypeError: 'gt字段不是字符串类型'
+    };
+    if (typeof config.onError === 'function') {
+        config.onError({
+            desc: errObj.desc,
+            msg: errObj.msg,
+            code: errObj.code
+        });
+    } else {
+        throw new Error(errors[errorType]);
+    }
+};
+
+var detect = function () {
+    return window.Captcha4 || document.getElementById("gt_lib");
+};
+
+if (detect()) {
+    status.slide = "loaded";
+}
+var Captcha4IsLoad = function (fname) {
+  var Captcha4IsLoad = false;
+  var tags = { js: 'script', css: 'link' };
+  var tagname = fname && tags[fname.split('.').pop()];
+  if (tagname !== undefined) {
+    var elts = document.getElementsByTagName(tagname);
+    for (var i in elts) {
+      if ((elts[i].href && elts[i].href.toString().indexOf(fname) > 0)
+              || (elts[i].src && elts[i].src.toString().indexOf(fname) > 0)) {
+        Captcha4IsLoad = true;
+      }
+    }
+  }
+  return Captcha4IsLoad;
+};
+window.initAlicom4 = function (userConfig,callback) {
+
+    var config = new Config(userConfig);
+    if (userConfig.https) {
+        config.protocol = 'https://';
+    } else if (!userConfig.protocol) {
+        config.protocol = window.location.protocol + '//';
+    }
+
+
+    if (isObject(userConfig.getType)) {
+        config._extend(userConfig.getType);
+    }
+
+    jsonp(config.apiServers , config.typePath, config, function (newConfig) {
+            
+            //错误捕获,第一个load请求可能直接报错
+            var newConfig = camelizeKeys(newConfig);
+
+            if(newConfig.status === 'error'){
+               return throwError('networkError', config, newConfig);
+            }
+
+            var type = newConfig.type;
+            
+            if(config.debug){
+                new _Object(newConfig)._extend(config.debug)
+            }
+            var init = function () {
+                config._extend(newConfig);
+                callback(new window.Captcha4(config));
+            };
+
+            callbacks[type] = callbacks[type] || [];
+
+            var s = status[type] || 'init';
+            if (s === 'init') {
+                status[type] = 'loading';
+
+                callbacks[type].push(init);
+
+                if(newConfig.gctPath){
+                    load(config, config.protocol, Object.hasOwnProperty.call(config, 'staticServers') ? config.staticServers  : newConfig.staticServers || config.staticServers , newConfig.gctPath, null, function (err){
+                        if(err){
+                            throwError('networkError', config, {
+                                code: '60205',
+                                msg: 'Network failure',
+                                desc: {
+                                    detail: 'gct resource load timeout'
+                                }
+                            });
+                        }
+                    })
+                }
+
+                load(config,  config.protocol, Object.hasOwnProperty.call(config, 'staticServers') ? config.staticServers  : newConfig.staticServers || config.staticServers, newConfig.bypass || (newConfig.staticPath + newConfig.js), null, function (err) {
+                    if (err) {
+                        status[type] = 'fail';
+                        throwError('networkError', config, {
+                            code: '60204',
+                            msg: 'Network failure',
+                            desc: {
+                                detail: 'js resource load timeout'
+                            }
+                        });
+                    } else {
+                        status[type] = 'loaded';
+                        var cbs = callbacks[type];
+                        for (var i = 0, len = cbs.length; i < len; i = i + 1) {
+                            var cb = cbs[i];
+                            if (isFunction(cb)) {
+                                cb();
+                            }
+                        }
+                        callbacks[type] = [];
+                    }
+                });
+            } else if (s === "loaded") {
+                // 判断gct是否需要重新加载
+                if(newConfig.gctPath && !Captcha4IsLoad(newConfig.gctPath)){
+
+                // if(!Captcha4IsLoad(newConfig.gctPath)){
+                  load(config, config.protocol, Object.hasOwnProperty.call(config, 'staticServers') ? config.staticServers  : newConfig.staticServers || config.staticServers , newConfig.gctPath, null, function (err){
+                      if(err){
+                          throwError('networkError', config, {
+                              code: '60205',
+                              msg: 'Network failure',
+                              desc: {
+                                  detail: 'gct resource load timeout'
+                              }
+                          });
+                      }
+                  })
+                }
+                return  init();
+            } else if (s === "fail") {
+              throwError('networkError', config, {
+                code: '60204',
+                msg: 'Network failure',
+                desc: {
+                    detail: 'js resource load timeout'
+                }
+              });
+            } else if (s === "loading") {
+                callbacks[type].push(init);
+            }
+        });
+
+};
+
+
+})(window);

BIN
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/en.lproj/AlicomCaptcha4.strings


+ 375 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/gt4-index-alicom.html

@@ -0,0 +1,375 @@
+<!doctype html>
+<html>
+
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="renderer" content="webkit">
+    <meta name="viewport" id="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
+    <title>请通过以下验证</title>
+    <style>
+        body {
+            margin: 0;
+        }
+
+        .title {
+            height: 18px;
+            margin: 15px;
+            font-size: 18px;
+            line-height: 18px;
+        }
+
+        #log {
+            display: none;
+            margin: 0;
+            word-break: break-all;
+        }
+
+        #log.log {
+            display: block;
+        }
+
+        #captcha_index_loading {
+            position: fixed;
+            top: 50%;
+            left: 50%;
+            overflow: hidden;
+            transform: translate(-50%, -50%);
+        }
+
+        #captcha {
+            position: absolute;
+            top: 50%;
+            left: 50%;
+            width: 260px;
+            height: 50px;
+            transform: translate(-50%, -50%);
+        }
+
+        /* loading */
+        .loader {
+            width: 40px;
+            height: 40px;
+        }
+
+        svg path,
+        svg rect {
+            fill: #3973ff;
+        }
+    </style>
+</head>
+
+<body>
+    <div id="log"></div>
+    <div id="captcha"></div>
+
+    <div id="captcha_index_loading">
+        <img class="captcha_index_img loader" id="captcha_img_loading" alt="加载中" style="display: none;">
+    </div>
+    <script>
+        var debug = false;
+        var logEle = document.getElementById('log');
+        var isOffline = false;
+        var indexVersion = '1.3.4'; // 中间页版本号,每次修改文件要进行版本号升级
+        function log(str) {
+            if (!debug) {
+                return;
+            }
+            var p = document.createElement('p');
+            p.appendChild(document.createTextNode(str));
+            logEle.insertBefore(p, logEle.firstChild);
+            // 同时将错误输出到控制台
+            console.log(str);
+        }
+        (function () {
+            // 错误构造函数
+            function newError(msg, code, detail) {
+                return {
+                    desc: {
+                        indexVersion: indexVersion,
+                        detail: detail
+                    },
+                    msg: msg,
+                    code: code
+                }
+            }
+            function uploadExtraData(type, extraData) {
+                var self = window;
+                // 参数应该存在length属性,并且参数长度不可超过限制
+                if (!extraData || (!extraData.length) || (extraData.length >= 1024 * 4)) {
+                    return;
+                }
+                if (!self.extraData) {
+                    self.extraData = {};
+                }
+                // 设计成可拓展的结构,防止以后有类似的字段增加需求
+                self.extraData[type] = extraData;
+            }
+            var jsBridge = (function () {
+
+                var callbacks = {
+                    showBox: function () {
+                        captchaObj.showBox &&  captchaObj.showBox();
+                    },
+                    postNativeMessage: function (data) {
+                        log('getCore time: ' + ((new Date()).getTime()));
+                        uploadExtraData('GeeToken', data);
+                    }
+                };
+                var call = function (data) {
+                    //调用原生方法
+                    try {
+                        nativeCall(JSON.stringify(data))
+                    } catch (e) {
+                        log('调用navtive接口异常');
+                    }
+                };
+                // 适配鸿蒙
+                var harmonys = JSON.parse(decodeURIComponent(location.href.split('?')[1].split('=')[1]));
+                var nativeCall = harmonys.harmony?  function (data) {
+                    if (window.webkit && window.webkit.messageHandlers) {
+                        return window.webkit.messageHandlers.gt4Notify.postMessage.bind(window.webkit.messageHandlers.gt4Notify)
+                    } else if (window.JSInterface) {
+                        // return JSInterface.gt4Notify.bind(JSInterface)
+                        JSInterface.call(data)
+                    } else {
+                        log('请在移动端环境运行')
+                    }
+                }: (function () {
+                    if (window.webkit && window.webkit.messageHandlers) {
+                        return window.webkit.messageHandlers.gt4Notify.postMessage.bind(window.webkit.messageHandlers.gt4Notify)
+                    } else if (window.JSInterface) {
+                        return JSInterface.gt4Notify.bind(JSInterface)
+                    } else {
+                        log('请在移动端环境运行')
+                    }
+                })();
+
+                return {
+                    callback: function (type, data) {
+                        return callbacks[type](data);
+                    },
+                    callNative: call
+                }
+            })();
+            // 暴露 jsBridge
+            window.jsBridge = jsBridge;
+            // jsBridge 与 全局错误捕获要尽可能早的加载,防止gt4中的错误捕获不到;
+            if (window.addEventListener) {
+                window.addEventListener('error', function (e) {
+                    jsBridge.callNative({
+                        type: 'error',
+                        data: newError("gt4-index error", 60302, e.message)
+                    });
+                })
+            } else {
+                window.onerror = function (e) {
+                    jsBridge.callNative({
+                        type: 'error',
+                        data: newError("gt4-index error", 60302, e.message)
+                    });
+                }
+            }
+        })();
+    </script>
+
+    <!-- 此链接位置不要改变,防止上面页面错误catch 不到gt4的错误-->
+    <script src="./ct4.js"></script>
+
+    <script>
+        (function () {
+            //geeToken兼容ai下无token
+            if (!isOffline) {
+                // 非宕机模式下获取移动端coreSDK数据
+                jsBridge.callNative({
+                    type: 'get'
+                })
+            }
+            var startTime = 0;
+            var clearID = 0;
+            var captcha = document.getElementById('captcha');
+            var loadingEle = document.getElementById('captcha_index_loading');
+            var img = document.getElementById('captcha_img_loading');
+
+            var query = location.href.split('?')[1];
+            // 兼容安卓4.3版本样式问题
+            var ua = navigator.userAgent.toLowerCase();
+            if(/Android/.test(window.navigator.userAgent) && /android\s([\w.]+)/.exec(ua)[1] <= 4.3) {
+                loadingEle.style.left = '45%';
+            }
+            
+            // 兼容低版本Object.assign
+            if (typeof Object.assign != 'function') {
+                // Must be writable: true, enumerable: false, configurable: true
+                Object.defineProperty(Object, "assign", {
+                    value: function assign(target, varArgs) { // .length of function is 2
+                    if (target == null) { // TypeError if undefined or null
+                        throw new TypeError('Cannot convert undefined or null to object');
+                    }
+
+                    var to = Object(target);
+
+                    for (var index = 1; index < arguments.length; index++) {
+                        var nextSource = arguments[index];
+
+                        if (nextSource != null) { // Skip over if undefined or null
+                        for (var nextKey in nextSource) {
+                            // Avoid bugs when hasOwnProperty is shadowed
+                            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
+                            to[nextKey] = nextSource[nextKey];
+                            }
+                        }
+                        }
+                    }
+                    return to;
+                    },
+                    writable: true,
+                    configurable: true
+                });
+            }
+            // 默认配置
+            var config = {
+                product: 'bind',
+                onError: function (e) {
+                    // 错误信息中插入版本号
+                    e.desc = Object.assign({}, e.desc, { indexVersion: indexVersion });
+                    jsBridge.callNative({
+                        type: 'error',
+                        data: e
+                    });
+                }
+            };
+            function setDebug() {
+                debug = true;
+                logEle.className = 'log';
+            }
+            
+            function paseURI() {
+                return JSON.parse(decodeURIComponent(query.split('=')[1]));
+            }
+
+            function checkArgs(args) {
+                //设置loading
+                if(args['loading']){
+                  img.src = args['loading'];
+                  clearID = setTimeout(function () {
+                    img.style.display = 'inline-block';
+                  }, 200);
+                }
+                // 是否开启debug
+                if (args['debug']) {
+                    setDebug(true);
+                    startTime = (new Date()).getTime();
+                    log(JSON.stringify(args))
+                }
+
+                // 设置title
+                if (args['title'] && args['title'] != "") {
+                    var h3 = document.createElement('h3');
+                    h3.className = 'title';
+                    h3.appendChild(document.createTextNode(decodeURIComponent(args['title'])));
+                    captcha.appendChild(h3);
+                }
+
+                // 检查必要参数
+                if (!args['captchaId']) {
+                    log('args error: ' + query);
+                }
+
+                // 通过useLocalOffline判断是否会加入宕机效验
+                if (args['useLocalOffline']) {
+                    //宕机启用自己的方法
+                    config.offlineCb = function () {
+
+                        isOffline = true;
+
+                        jsBridge.callNative({
+                            type: 'result',
+                            data: {
+                                captcha_id: args['captchaId'],
+                                challenge: args['challenge'],
+                                offline: true
+                            }
+                        });
+                    }
+                }
+            }
+
+            function mergeOptions(args) {
+                for (var k in args) {
+                    if (args.hasOwnProperty(k) &&
+                        ['debug', 'title',  args['type']].indexOf(k) === -1) {
+                        config[k] = args[k];
+                    }
+                }
+            }
+
+            if (!query) {
+                setDebug();
+                log('no query: ' + location.href);
+                return false;
+            }
+
+            // 解析参数
+            var args = paseURI(query);
+
+            // 检查参数
+            checkArgs(args);
+
+            // 合并配置项
+            mergeOptions(args);
+
+            // 初始化验证码
+            var handler = function (captchaObj) {
+                window.captchaObj = captchaObj;
+                captchaObj
+                    .appendTo(captcha)
+                    .onSuccess(function () {
+                        var result = captchaObj.getValidate();
+                        log('Success validate: ' + result);
+                        jsBridge.callNative({
+                            type: 'result',
+                            data: result
+                        });
+
+                    })
+                    .onReady(function () {
+                        log('load time: ' + ((new Date()).getTime() - (startTime || 0)));
+
+                        jsBridge.callNative({
+                            type: 'ready',
+                            data: {
+                                ready: 0
+                            }
+                        })
+
+                        clearTimeout(clearID);
+                        loadingEle.style.display = 'none';
+                    })
+                    .onClose(function () {
+                        jsBridge.callNative({
+                            type: 'close'
+                        });
+                    })
+                    .onError(function (e) {
+                        e.desc && (e.desc.indexVersion = indexVersion);
+                        jsBridge.callNative({
+                            type: 'error',
+                            data: e
+                        });
+                    })
+                    .onFail(function (e) {
+                        jsBridge.callNative({
+                            type: 'fail',
+                            data: e
+                        });
+                    })
+            };
+            window.initAlicom4(config, handler);
+
+        })();
+
+    </script>
+</body>
+
+</html>

BIN
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/gt4-loading.gif


BIN
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.bundle/zh-CN.lproj/AlicomCaptcha4.strings


BIN
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/AlicomCaptcha4


+ 66 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Headers/AlicomC4Error.h

@@ -0,0 +1,66 @@
+//
+//  AlicomC4Error.h
+//  AlicomCaptcha4
+//
+//  Created by NikoXu on 2020/9/30.
+//  Copyright © 2020 GT. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// 不合法的参数。请检查输入的参数。
+/// Illegal parameter. Please check the parameters you entered.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeInvalidParameter;
+/// 操作失败。详细查看描述。
+/// Operation failed. Check the description in detail.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeOperationFail;
+/// 资源缺失。请检查 AlicomCaptcha4.bundle 文件是否完整。
+/// Lack of resources. Please check if the `AlicomCaptcha4.bundle` file is imported correctly.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeMissedResource;
+
+/// 用户取消了验证。
+/// Verification is canceled by the user.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeUserDidCancel;
+
+/// 加载文件失败。请检查是否导入了完整的 AlicomCaptcha4.bundle 文件或者配置的远程静态资源是否可访问。
+/// Failed to load file. Please check if the `AlicomCaptcha4.bundle` file
+/// is complete or if the configured remote static resource is accessible.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeLoadFileFailure;
+/// 加载超时。
+/// Request timeout.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeTimeout;
+/// 执行 Javascript 脚本失败。
+/// Evaluating javascript script fail.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeEvaluatingJavascriptFail;
+/// Javascript 返回错误。
+/// Javascript returns an error.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeJavascriptError;
+/// WebView 内存警告。
+/// WebView memory warning.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeWebViewMemoryWarning;
+
+/// 未知错误。
+/// Unknown error.
+FOUNDATION_EXPORT NSString * const AlicomC4ErrorCodeUnknown;
+
+/// 错误描述对象
+/// Error description object
+@interface AlicomC4Error : NSObject
+
+/// 错误码, 可用于匹配并进行相应处理
+/// Error code, and can be used for matching processing.
+@property (readonly, nonatomic, strong) NSString *code;
+/// 错误信息,可用于用户界面展示。
+/// Error message. can be used for user interface display.
+@property (readonly, nonatomic, strong) NSString *msg;
+/// 错误详细描述,用于详细排查问题。
+/// 建议可以记录为排查日志。
+/// Detailed description of the error,
+/// which is used to troubleshoot problems in detail.
+@property (readonly, nonatomic, strong) NSDictionary *desc;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 21 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Headers/AlicomCaptcha4.h

@@ -0,0 +1,21 @@
+//
+//  AlicomCaptcha4.h
+//  AlicomCaptcha4
+//
+//  Created by NikoXu on 2020/9/18.
+//  Copyright © 2020 geetest. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+//! Project version number for AlicomCaptcha4.
+FOUNDATION_EXPORT double AlicomCaptcha4VersionNumber;
+
+//! Project version string for AlicomCaptcha4.
+FOUNDATION_EXPORT const unsigned char AlicomCaptcha4VersionString[];
+
+#import <AlicomCaptcha4/AlicomCaptcha4Session.h>
+#import <AlicomCaptcha4/AlicomCaptcha4SessionConfiguration.h>
+#import <AlicomCaptcha4/AlicomC4Error.h>
+
+

+ 103 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Headers/AlicomCaptcha4Session.h

@@ -0,0 +1,103 @@
+//
+//  AlicomCaptcha4Session.h
+//  AlicomCaptcha4.h
+//
+//  Created by NikoXu on 2020/9/29.
+//  Copyright © 2020 GT. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class AlicomCaptcha4SessionConfiguration, AlicomC4Error;
+
+@protocol AlicomCaptcha4SessionTaskDelegate;
+
+/// 验证会话(Captcha session)
+@interface AlicomCaptcha4Session : NSObject
+
+/// 验证会话任务的代理(Captcha session task delegate)
+@property (nullable, nonatomic, weak) id<AlicomCaptcha4SessionTaskDelegate> delegate;
+
+/// 当前验证会话的验证ID(The captcha ID of the current captcha session)
+@property (nonnull, readonly, nonatomic, strong) NSString *captchaID;
+/// 当前验证会话的流水号(The serial number of the current captcha session)
+@property (nullable, readonly, nonatomic, strong) NSString *challenge;
+/// 当前验证会话的配置(The configuration of the current captcha session)
+@property (nonnull, readonly, nonatomic, strong) AlicomCaptcha4SessionConfiguration *configuration;
+
+/// 创建一个新的验证会话实例(Create a new captcha session instance)
+/// @param captchaID 验证ID(The captcha ID)
++ (instancetype)sessionWithCaptchaID:(NSString *)captchaID;
+
+/// 创建一个新的验证会话实例(Create a new captcha session instance.)
+/// @param captchaID 验证ID(The captcha ID)
+/// @param configuration 会话配置(The configuration of session)
++ (instancetype)sessionWithCaptchaID:(NSString *)captchaID
+                       configuration:(nullable AlicomCaptcha4SessionConfiguration *)configuration;
+
+/// 初始化一个新的验证会话实例(Create a new captcha session instance)
+/// @param captchaID 验证ID(The captcha ID)
+- (instancetype)initWithCaptchaID:(NSString *)captchaID;
+
+/// 初始化一个新的验证会话实例(Create a new captcha session instance)
+/// @param captchaID 验证ID(The captcha ID)
+/// @param configuration 会话配置(The configuration of session)
+- (instancetype)initWithCaptchaID:(NSString *)captchaID
+                    configuration:(nullable AlicomCaptcha4SessionConfiguration *)configuration;
+
+/// 开始验证(Start verification)
+- (void)verify;
+
+/// 取消验证(Cancel verification)
+- (void)cancel;
+
+/// SDK 版本号(Obtain the SDK version)
++ (NSString *)sdkVersion;
+
+@end
+
+/// 验证会话任务代理协议(Captcha Session Task Delegate)
+@protocol AlicomCaptcha4SessionTaskDelegate <NSObject>
+
+@required
+
+/// 回调验证会话的结果参数(Callback result parameters of captcha session)
+/// @discussion 拿到验证结果的参数后,需要提交到业务服务端,
+///             完成参数的校验
+///             After getting the parameters of verification results,
+///             they need to be submitted to the business server to
+///             complete the verification of parameters.
+/// @param captchaSession 验证会话(Captcha session)
+/// @param status 状态码。@"0"/@"1": 未完成/完成。当 status 为 @"1"
+///                     时,则为成功,需要对结果进行二次校验。
+///               Status code. @ “0”/@ “1”: Not finished/finished.
+///               When status is @ “1”, it is successful, and the
+///               result needs to be secondary validated.
+/// @param result 结果校验参数(Result verification parameters.)。示例(Example):
+///               ```
+///               {
+///                 challenge = "19080ae5-fe79-4431-9c78-4ee8e0dec798";
+///                 captcha_id = "c62d0f270240799b3113b0a5787ead55";
+///               }
+///               ```
+- (void)alicomCaptchaSession:(AlicomCaptcha4Session *)captchaSession
+              didReceive:(NSString *)status
+                  result:(nullable NSDictionary *)result;
+
+/// 回调验证会话中发生的错误(Callback errors that occurred in the captcha session)
+/// @param captchaSession 验证会话(Captcha session)
+/// @param error 错误描述对象(Error description object)
+- (void)alicomCaptchaSession:(AlicomCaptcha4Session *)captchaSession
+         didReceiveError:(AlicomC4Error *)error;
+
+@optional
+
+/// 通知验证界面将要展现
+/// @param captchaSession 验证会话
+- (void)alicomCaptchaSessionWillShow:(AlicomCaptcha4Session *)captchaSession;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 83 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Headers/AlicomCaptcha4SessionConfiguration.h

@@ -0,0 +1,83 @@
+//
+//  AlicomCaptcha4SessionConfiguration.h
+//  AlicomCaptcha4
+//
+//  Created by NikoXu on 2020/9/30.
+//  Copyright © 2020 GT. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// 验证界面样式(User interface style)
+typedef NS_ENUM(NSInteger, AlicomC4UserInterfaceStyle) {
+    /** 跟随系统样式(Follow system) */
+    AlicomC4UserInterfaceStyleSystem = 0,
+    /** 普通样式(Light) */
+    AlicomC4UserInterfaceStyleLight,
+    /** 暗黑样式(Dark) */
+    AlicomC4UserInterfaceStyleDark,
+    /** 默认样式(Default) */
+    AlicomC4UserInterfaceStyleDefault = AlicomC4UserInterfaceStyleLight
+};
+
+/// 验证会话配置(Captcha session configuration)
+@interface AlicomCaptcha4SessionConfiguration : NSObject <NSCoding>
+
+/// 静态资源文件的路径, 默认为空。
+/// 如果为远程文件,则应为完成路径。
+/// 如果为本地文件,则应为文件所在路径(不包含文件)。
+/// The path of static resources, which is empty by default.
+@property (nullable, nonatomic, strong) NSString *resourcePath;
+/// 远程访问静态资源时的协议,默认 @“https”。
+/// Protocol for remote access to static resources, default is @ “https”.
+@property (nullable, nonatomic, strong) NSString *protocol;
+/// 静态服务地址,默认为空。
+@property (nullable, nonatomic, strong) NSArray<NSString *> *staticServers;
+/// 接口服务地址,默认为空。
+@property (nullable, nonatomic, strong) NSArray<NSString *> *apiServers;
+
+/// 界面和状态栏样式,默认 `AlicomC4UserInterfaceStyleLight`。
+/// User interface and statusBar style, which is white by default.
+@property (nonatomic, assign) AlicomC4UserInterfaceStyle userInterfaceStyle;
+
+/// 背景颜色,默认透明
+/// Defines color for captcha background. Default is transparent.
+@property (nonatomic, strong) UIColor *backgroundColor;
+
+/// 调试模式开关,默认关闭。
+/// Determines whether the debug information is shown on background,
+/// which is disable by default.
+@property (nonatomic, assign) BOOL debugEnable;
+/// 点击背景的交互,默认开启。
+/// Determines whether the background is able to interact,
+/// which is disable by default.
+@property (nonatomic, assign) BOOL backgroundUserInteractionEnable;
+/// 请求超时时长,默认 8 秒。
+/// The timeout of each request. Default is 8.0s.
+@property (nonatomic, assign) NSTimeInterval timeout;
+/// 语言,默认跟随系统。
+/// 如果系统为不支持的语言,则为中文简体。
+/// 指定语言请参考文档中的语言短码清单(ISO 639-2 标准)。
+/// Defines Language for captcha, which is same as system language by default.
+/// Display in English, if not supported.
+/// Please refer to the language short code(ISO 639-2 standard) for setting the language.
+@property (nonatomic, strong) NSString *language;
+
+/// 支持的横竖屏方向。
+/// The supported interface orientations.
+@property (assign, nonatomic) UIInterfaceOrientationMask supportedInterfaceOrientations;
+
+/// 额外的参数, 默认为空。参数将被组装后提交到验证服务。
+/// Additional parameter, which is empty by default.
+/// Parameters will be assembled and submitted to the captcha server.
+@property (nullable, nonatomic, strong) NSMutableDictionary *additionalParameter;
+
+/// 获得一个默认配置
+/// Get a default configuration.
++ (AlicomCaptcha4SessionConfiguration *)defaultConfiguration;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 51 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Info.plist

@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>BuildMachineOSBuild</key>
+	<string>22G91</string>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>AlicomCaptcha4</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.alicom.gtcaptcha4</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>AlicomCaptcha4</string>
+	<key>CFBundlePackageType</key>
+	<string>FMWK</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.8.3.2</string>
+	<key>CFBundleSupportedPlatforms</key>
+	<array>
+		<string>iPhoneOS</string>
+	</array>
+	<key>CFBundleVersion</key>
+	<string>2401081433</string>
+	<key>DTCompiler</key>
+	<string>com.apple.compilers.llvm.clang.1_0</string>
+	<key>DTPlatformBuild</key>
+	<string>19F64</string>
+	<key>DTPlatformName</key>
+	<string>iphoneos</string>
+	<key>DTPlatformVersion</key>
+	<string>15.5</string>
+	<key>DTSDKBuild</key>
+	<string>19F64</string>
+	<key>DTSDKName</key>
+	<string>iphoneos15.5</string>
+	<key>DTXcode</key>
+	<string>1341</string>
+	<key>DTXcodeBuild</key>
+	<string>13F100</string>
+	<key>MinimumOSVersion</key>
+	<string>8.0</string>
+	<key>UIDeviceFamily</key>
+	<array>
+		<integer>1</integer>
+		<integer>2</integer>
+	</array>
+</dict>
+</plist>

+ 6 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/Modules/module.modulemap

@@ -0,0 +1,6 @@
+framework module AlicomCaptcha4 {
+  umbrella header "AlicomCaptcha4.h"
+
+  export *
+  module * { export * }
+}

+ 22 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/PrivacyInfo.xcprivacy

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>NSPrivacyCollectedDataTypes</key>
+	<array>
+		<dict>
+			<key>NSPrivacyCollectedDataType</key>
+			<string>NSPrivacyCollectedDataTypeProductInteraction</string>
+			<key>NSPrivacyCollectedDataTypeLinked</key>
+			<false/>
+			<key>NSPrivacyCollectedDataTypeTracking</key>
+			<false/>
+			<key>NSPrivacyCollectedDataTypePurposes</key>
+			<array>
+				<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
+				<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
+			</array>
+		</dict>
+	</array>
+</dict>
+</plist>

BIN
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeDirectory


BIN
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeRequirements


BIN
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeRequirements-1


+ 177 - 0
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeResources

@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>files</key>
+	<dict>
+		<key>Headers/AlicomC4Error.h</key>
+		<data>
+		Ado5ZDjT1YOpzS2JOym18V1b6SI=
+		</data>
+		<key>Headers/AlicomCaptcha4.h</key>
+		<data>
+		jKkAbFMdxn6SoFwmBicKhTQL+tg=
+		</data>
+		<key>Headers/AlicomCaptcha4Session.h</key>
+		<data>
+		lAlT53AFxRDFz0566AUsKiSWDlA=
+		</data>
+		<key>Headers/AlicomCaptcha4SessionConfiguration.h</key>
+		<data>
+		JpYjgFhHBMfJbA4iDpxc6P6W3iU=
+		</data>
+		<key>Info.plist</key>
+		<data>
+		f9D1JuCQdyae3w7LQoTaLC/oemY=
+		</data>
+		<key>Modules/module.modulemap</key>
+		<data>
+		61LVSDcvfGyffJvdHViPje8Hr2o=
+		</data>
+	</dict>
+	<key>files2</key>
+	<dict>
+		<key>Headers/AlicomC4Error.h</key>
+		<dict>
+			<key>hash</key>
+			<data>
+			Ado5ZDjT1YOpzS2JOym18V1b6SI=
+			</data>
+			<key>hash2</key>
+			<data>
+			oc30PgajfuyrgHb2YdguedVQet/P/nQreKxSUkucGZ8=
+			</data>
+		</dict>
+		<key>Headers/AlicomCaptcha4.h</key>
+		<dict>
+			<key>hash</key>
+			<data>
+			jKkAbFMdxn6SoFwmBicKhTQL+tg=
+			</data>
+			<key>hash2</key>
+			<data>
+			dHLO9QowizxWuSIsUhXpCoPR0pdQfjdcYo2XBNI9B6A=
+			</data>
+		</dict>
+		<key>Headers/AlicomCaptcha4Session.h</key>
+		<dict>
+			<key>hash</key>
+			<data>
+			lAlT53AFxRDFz0566AUsKiSWDlA=
+			</data>
+			<key>hash2</key>
+			<data>
+			z6BeoUKk+KIFpuJJ0nKA8VvPQ3+8ejBsv70vsv0BBLo=
+			</data>
+		</dict>
+		<key>Headers/AlicomCaptcha4SessionConfiguration.h</key>
+		<dict>
+			<key>hash</key>
+			<data>
+			JpYjgFhHBMfJbA4iDpxc6P6W3iU=
+			</data>
+			<key>hash2</key>
+			<data>
+			KzompxE7K2ThBfQhoD+BQ+JfwpZeAT86XMBozgJ3Pdc=
+			</data>
+		</dict>
+		<key>Modules/module.modulemap</key>
+		<dict>
+			<key>hash</key>
+			<data>
+			61LVSDcvfGyffJvdHViPje8Hr2o=
+			</data>
+			<key>hash2</key>
+			<data>
+			F/lmxPgp5pqm8HIELtn/UF29GI9CCceohFuDJUb8GQM=
+			</data>
+		</dict>
+	</dict>
+	<key>rules</key>
+	<dict>
+		<key>^.*</key>
+		<true/>
+		<key>^.*\.lproj/</key>
+		<dict>
+			<key>optional</key>
+			<true/>
+			<key>weight</key>
+			<real>1000</real>
+		</dict>
+		<key>^.*\.lproj/locversion.plist$</key>
+		<dict>
+			<key>omit</key>
+			<true/>
+			<key>weight</key>
+			<real>1100</real>
+		</dict>
+		<key>^Base\.lproj/</key>
+		<dict>
+			<key>weight</key>
+			<real>1010</real>
+		</dict>
+		<key>^version.plist$</key>
+		<true/>
+	</dict>
+	<key>rules2</key>
+	<dict>
+		<key>.*\.dSYM($|/)</key>
+		<dict>
+			<key>weight</key>
+			<real>11</real>
+		</dict>
+		<key>^(.*/)?\.DS_Store$</key>
+		<dict>
+			<key>omit</key>
+			<true/>
+			<key>weight</key>
+			<real>2000</real>
+		</dict>
+		<key>^.*</key>
+		<true/>
+		<key>^.*\.lproj/</key>
+		<dict>
+			<key>optional</key>
+			<true/>
+			<key>weight</key>
+			<real>1000</real>
+		</dict>
+		<key>^.*\.lproj/locversion.plist$</key>
+		<dict>
+			<key>omit</key>
+			<true/>
+			<key>weight</key>
+			<real>1100</real>
+		</dict>
+		<key>^Base\.lproj/</key>
+		<dict>
+			<key>weight</key>
+			<real>1010</real>
+		</dict>
+		<key>^Info\.plist$</key>
+		<dict>
+			<key>omit</key>
+			<true/>
+			<key>weight</key>
+			<real>20</real>
+		</dict>
+		<key>^PkgInfo$</key>
+		<dict>
+			<key>omit</key>
+			<true/>
+			<key>weight</key>
+			<real>20</real>
+		</dict>
+		<key>^embedded\.provisionprofile$</key>
+		<dict>
+			<key>weight</key>
+			<real>20</real>
+		</dict>
+		<key>^version\.plist$</key>
+		<dict>
+			<key>weight</key>
+			<real>20</real>
+		</dict>
+	</dict>
+</dict>
+</plist>

BIN
MSYOUPAI/AlicomCaptcha/AlicomCaptcha4.framework/_CodeSignature/CodeSignature


+ 20 - 0
MSYOUPAI/AlicomCaptcha/CaptchaCenter.h

@@ -0,0 +1,20 @@
+
+
+#import <Foundation/Foundation.h>
+#import <AlicomCaptcha4/AlicomCaptcha4.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CaptchaCenter : NSObject
+
++ (instancetype)defaultCenter;
+
+/// 获取验证码类型,返回1是原生验证码, 2是阿里验证码
+- (void)getCaptchaType:(void(^)(NSNumber * _Nullable type, NSError * _Nullable error))completion;
+
+/// 阿里验证码返回结果
+- (void)verifyCompletion:(void(^)(NSString *status, NSDictionary *result))completion;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 99 - 0
MSYOUPAI/AlicomCaptcha/CaptchaCenter.m

@@ -0,0 +1,99 @@
+
+
+#import "CaptchaCenter.h"
+
+
+#define captchaID @"629e4f9060c50e8ec0c0ba2db0580db0"
+
+@interface CaptchaCenter ()<AlicomCaptcha4SessionTaskDelegate>
+
+@property (nonatomic, strong) AlicomCaptcha4Session *captchaSession;
+@property (nonatomic, copy) void (^verifyBlock)(NSString *status, NSDictionary *result);
+
+@end
+
+
+@implementation CaptchaCenter
+
+static id _instance;
+
++ (instancetype)defaultCenter {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        _instance = [[self alloc] init];
+    });
+    return _instance;
+}
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        [self captchaSession];
+    }
+    return self;
+}
+
+// 防止通过拷贝创建新实例
+- (id)copyWithZone:(NSZone *)zone {
+    return _instance;
+}
+
+// 防止通过归档创建新实例
+- (id)mutableCopyWithZone:(NSZone *)zone {
+    return _instance;
+}
+
+
+/// 获取验证码
+- (void)getCaptchaType:(void(^)(NSNumber * _Nullable type, NSError * _Nullable error))completion {
+    [LCHttpHelper requestWithURLString:GetCaptchaType parameters:@{} needToken:NO type:HttpRequestTypePost success:^(id responseObject) {
+        NSDictionary* dict = (NSDictionary*)responseObject;
+        NSInteger code = [[dict objectForKey:@"code"] integerValue];
+        if (code == 0) {
+            NSDictionary *dataDict = [dict objectForKey:@"data"];
+            NSNumber *type = [dataDict objectForKey:@"type"];
+            completion(type, nil);
+        } else {
+            NSError *error = [[NSError alloc] initWithDomain:NSCocoaErrorDomain code:123 userInfo:@{@"msg": @"服务端返回失败"}];
+            completion(nil, error);
+        }
+    } failure:^(NSError *error) {
+        completion(nil, error);
+    }];
+}
+
+
+- (AlicomCaptcha4Session *)captchaSession {
+    if (!_captchaSession) {
+        _captchaSession = [AlicomCaptcha4Session sessionWithCaptchaID:captchaID];
+        /// 如需修改默认配置
+        /// 可选择下⾯注释的⽅式创建实例
+        // AlicomCaptcha4SessionConfiguration *config = [AlicomCaptcha4SessionConfiguration defaultConfiguration];
+        // config.timeout = 8.0f;
+        // ...
+        // _captchaSession = [AlicomCaptcha4Session sessionWithCaptchaID:captchaID configuration:config];
+        _captchaSession.delegate = self;
+    }
+    return _captchaSession;
+}
+
+- (void)verifyCompletion:(void(^)(NSString *status, NSDictionary *result))completion {
+    [self.captchaSession verify];
+    self.verifyBlock = completion;
+}
+
+
+- (void)alicomCaptchaSession:(AlicomCaptcha4Session *)captchaSession didReceive:(NSString *)status result:(nullable NSDictionary *)result {
+    NSLog(@"status: %@" , status);
+    NSLog(@"result: %@" , result);
+    // status 为 @"1"则为用户完成了验证,为@"0"则为用户验证失败
+    self.verifyBlock(status, result);
+}
+
+
+- (void)alicomCaptchaSession:(AlicomCaptcha4Session *)captchaSession didReceiveError:(AlicomC4Error *)error {
+    NSLog(@"error: %@", error.description);
+}
+
+
+@end

+ 47 - 34
MSYOUPAI/Class/YQProfile/青少年模式/YOUPAILPYoungForgetPWD.m

@@ -7,6 +7,7 @@
 //
 
 #import "YOUPAILPYoungForgetPWD.h"
+#import "YMCaptchaPopupView.h"
 
 @interface YOUPAILPYoungForgetPWD ()<UIScrollViewDelegate,UITextViewDelegate>
 @property(nonatomic,strong)UITextField* youpaipphoneTextField,*youpaippwdTextField;
@@ -173,40 +174,52 @@
     NSString *phoneText = [self.youpaipphoneTextField.text stringByReplacingOccurrencesOfString:@" " withString:@""];
     if ([ZCRegularHelper regularPhoneNumber:phoneText]) {//首先手机格式保证正确
         
-        [LCHttpHelper requestWithURLString:PhoneCode parameters:@{@"mobile":phoneText,@"type":@"findadpwd"} needToken:YES type:(HttpRequestTypePost) success:^(id responseObject) {
-            NSDictionary* dict = (NSDictionary*)responseObject;
-            NSInteger code = [[dict objectForKey:@"code"] integerValue];
-            if (code==0) {//成功
-                [ZCHUDHelper showTitle:@"验证码已发送"];
-                __block int timeout=120;
-                dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
-                dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
-                dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
-                dispatch_source_set_event_handler(_timer, ^{
-                    if(timeout<=0){
-                        dispatch_source_cancel(_timer);
-                        
-                        dispatch_async(dispatch_get_main_queue(), ^{
-                            [self.youpaipverifyBtn setTitle:@"获取验证码" forState:UIControlStateNormal];
-                            self.youpaipverifyBtn.userInteractionEnabled = YES;
-                        });
-                    }else{
-                        
-                        NSString *strTime = [NSString stringWithFormat:@"%.2dS",timeout];
-                        dispatch_async(dispatch_get_main_queue(), ^{
-                            //设置界面的按钮显示 根据自己需求设置
-                            [self.youpaipverifyBtn setTitle:strTime forState:UIControlStateNormal];
-                            self.youpaipverifyBtn.userInteractionEnabled = NO;
-                        });
-                        timeout--;
-                        
-                    }
-                });
-                dispatch_resume(_timer);
-            }
-        } failure:^(NSError *error) {
-            
-        }];
+        YMCaptchaPopupView *view = [[YMCaptchaPopupView alloc] init];
+        view.cancelButtonTappedBlock = ^{};
+        @weakify(self)
+        view.confirmButtonTappedBlock = ^(NSString * _Nonnull input) {
+            @strongify(self)
+            @weakify(self)
+            [LCHttpHelper requestWithURLString:PhoneCode parameters:@{@"captcha":input, @"mobile":phoneText,@"type":@"forget"} needToken:YES type:(HttpRequestTypePost) success:^(id responseObject) {
+                @strongify(self)
+                NSDictionary* dict = (NSDictionary*)responseObject;
+                NSInteger code = [[dict objectForKey:@"code"] integerValue];
+                if (code==0) {//成功
+                    [ZCHUDHelper showTitle:@"验证码已发送"];
+                    __block int timeout=120;
+                    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+                    dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
+                    dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
+                    dispatch_source_set_event_handler(_timer, ^{
+                        if(timeout<=0){
+                            dispatch_source_cancel(_timer);
+                            
+                            dispatch_async(dispatch_get_main_queue(), ^{
+                                [self.youpaipverifyBtn setTitle:@"获取验证码" forState:UIControlStateNormal];
+                                self.youpaipverifyBtn.userInteractionEnabled = YES;
+                            });
+                        }else{
+                            
+                            NSString *strTime = [NSString stringWithFormat:@"%.2dS",timeout];
+                            dispatch_async(dispatch_get_main_queue(), ^{
+                                //设置界面的按钮显示 根据自己需求设置
+                                [self.youpaipverifyBtn setTitle:strTime forState:UIControlStateNormal];
+                                self.youpaipverifyBtn.userInteractionEnabled = NO;
+                            });
+                            timeout--;
+                            
+                        }
+                    });
+                    dispatch_resume(_timer);
+                }
+            } failure:^(NSError *error) {
+                
+            }];
+        };
+        UIView *currentVCView = [LCTools getCurrentVC].view;
+        if (currentVCView != nil && ![currentVCView isEqual:NSNull.null]) {
+            [view showInView:currentVCView];
+        }
     }
     
 }

+ 31 - 0
MSYOUPAI/NewCode/CustomPopupView/YMCaptchaPopupView.h

@@ -0,0 +1,31 @@
+//
+//  YMCaptchaPopupView.h
+//  MSYOUPAI
+//
+//  Created by macmini on 2025/6/7.
+//  Copyright © 2025 MS. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+// 定义 Block 类型
+typedef void (^CaptchaCancelBlock)(void);
+typedef void (^CaptchaConfirmBlock)(NSString *input);
+//typedef void (^CaptchaRefreshBlock)(void);
+
+@interface YMCaptchaPopupView : UIView
+
+@property (nonatomic, copy) CaptchaCancelBlock cancelButtonTappedBlock;
+@property (nonatomic, copy) CaptchaConfirmBlock confirmButtonTappedBlock;
+//@property (nonatomic, copy) CaptchaRefreshBlock refreshButtonTappedBlock; // 用于点击验证码图片刷新
+
+- (void)showInView:(UIView *)view;
+- (void)dismiss;
+- (void)setCaptchaImage:(UIImage *)image;
+
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 271 - 0
MSYOUPAI/NewCode/CustomPopupView/YMCaptchaPopupView.m

@@ -0,0 +1,271 @@
+//
+//  YMCaptchaPopupView.m
+//  MSYOUPAI
+//
+//  Created by macmini on 2025/6/7.
+//  Copyright © 2025 MS. All rights reserved.
+//
+
+#import "YMCaptchaPopupView.h"
+
+@interface YMCaptchaPopupView ()<UITextFieldDelegate>
+
+@property (nonatomic, strong) UIView *backgroundMaskView;
+@property (nonatomic, strong) UIView *contentView;
+@property (nonatomic, strong) UILabel *titleLabel;
+@property (nonatomic, strong) UITextField *inputTextField;
+@property (nonatomic, strong) UIImageView *captchaImageView;
+@property (nonatomic, strong) UIButton *cancelButton;
+@property (nonatomic, strong) UIButton *confirmButton;
+
+@end
+
+@implementation YMCaptchaPopupView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self setupUI];
+        [self loadCaptchaImage];
+    }
+    return self;
+}
+
+- (void)setupUI {
+    self.backgroundColor = [UIColor clearColor];
+
+    // Background Mask
+    self.backgroundMaskView = [[UIView alloc] initWithFrame:self.bounds];
+    self.backgroundMaskView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
+    self.backgroundMaskView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    [self addSubview:self.backgroundMaskView];
+    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismiss)];
+    [self.backgroundMaskView addGestureRecognizer:tapGesture];
+
+    // Content View
+    self.contentView = [[UIView alloc] init];
+    self.contentView.backgroundColor = [UIColor whiteColor];
+    self.contentView.layer.cornerRadius = 10.0;
+    self.contentView.clipsToBounds = YES;
+    [self.contentView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithActionBlock:^(id  _Nonnull sender) { }]];
+    [self addSubview:self.contentView];
+
+    // Title Label
+    self.titleLabel = [[UILabel alloc] init];
+    self.titleLabel.text = @"图形验证";
+    self.titleLabel.font = [UIFont boldSystemFontOfSize:18.0];
+    self.titleLabel.textAlignment = NSTextAlignmentCenter;
+    [self.contentView addSubview:self.titleLabel];
+
+    // Input TextField
+    self.inputTextField = [[UITextField alloc] init];
+    self.inputTextField.font = [UIFont systemFontOfSize:14 weight:(UIFontWeightRegular)];
+    self.inputTextField.placeholder = @"请输入验证码(不区分大小写)";
+    self.inputTextField.borderStyle = UITextBorderStyleRoundedRect;
+    self.inputTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
+    self.inputTextField.delegate = self;
+    [self.contentView addSubview:self.inputTextField];
+
+    // Captcha ImageView
+    self.captchaImageView = [[UIImageView alloc] init];
+    self.captchaImageView.backgroundColor = [UIColor lightGrayColor]; // Placeholder color
+    self.captchaImageView.contentMode = UIViewContentModeScaleToFill;
+    self.captchaImageView.userInteractionEnabled = YES;
+    self.captchaImageView.clipsToBounds = YES;
+    self.captchaImageView.layer.cornerRadius = 5; // Approximate from image
+    // You might want to add a tap gesture to refresh the captcha
+    // For example:
+     UITapGestureRecognizer *captchaTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(refreshCaptcha)];
+     [self.captchaImageView addGestureRecognizer:captchaTap];
+    [self.contentView addSubview:self.captchaImageView];
+
+    // Cancel Button
+    self.cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
+    [self.cancelButton setTitle:@"取消" forState:UIControlStateNormal];
+    [self.cancelButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
+    self.cancelButton.titleLabel.font = [UIFont systemFontOfSize:16.0];
+    self.cancelButton.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.0]; // Light gray background
+    self.cancelButton.layer.cornerRadius = 25; // Approximate from image
+    [self.cancelButton addTarget:self action:@selector(cancelButtonTapped) forControlEvents:UIControlEventTouchUpInside];
+    [self.contentView addSubview:self.cancelButton];
+
+    // Confirm Button
+    self.confirmButton = [UIButton buttonWithType:UIButtonTypeSystem];
+    [self.confirmButton setTitle:@"确定" forState:UIControlStateNormal];
+    [self.confirmButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+    self.confirmButton.titleLabel.font = [UIFont systemFontOfSize:16.0];
+    self.confirmButton.backgroundColor = [UIColor colorWithRed:1.0 green:0.4 blue:0.5 alpha:1.0]; // Pinkish color
+    self.confirmButton.layer.cornerRadius = 25; // Approximate from image
+    [self.confirmButton addTarget:self action:@selector(confirmButtonTapped) forControlEvents:UIControlEventTouchUpInside];
+    [self.contentView addSubview:self.confirmButton];
+    
+    [self setupLayoutConstraints];
+}
+
+- (void)setupLayoutConstraints {
+    self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
+    self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+    self.inputTextField.translatesAutoresizingMaskIntoConstraints = NO;
+    self.captchaImageView.translatesAutoresizingMaskIntoConstraints = NO;
+    self.cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
+    self.confirmButton.translatesAutoresizingMaskIntoConstraints = NO;
+
+    CGFloat contentWidth = CGRectGetWidth(UIScreen.mainScreen.bounds) - 60;
+    CGFloat contentHeight = adapt(220); // Adjusted height
+
+    [NSLayoutConstraint activateConstraints:@[
+        [self.contentView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
+        [self.contentView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
+        [self.contentView.widthAnchor constraintEqualToConstant:contentWidth],
+        [self.contentView.heightAnchor constraintEqualToConstant:contentHeight],
+
+        [self.titleLabel.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:20],
+        [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:20],
+        [self.titleLabel.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-20],
+
+        [self.inputTextField.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant:40],
+        [self.inputTextField.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:20],
+        [self.inputTextField.heightAnchor constraintEqualToConstant:50],
+        
+        [self.captchaImageView.leadingAnchor constraintEqualToAnchor:self.inputTextField.trailingAnchor constant:10],
+        [self.captchaImageView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-20],
+        [self.captchaImageView.centerYAnchor constraintEqualToAnchor:self.inputTextField.centerYAnchor],
+        [self.captchaImageView.widthAnchor constraintEqualToConstant:100], // Adjust as needed
+        [self.captchaImageView.heightAnchor constraintEqualToConstant:49],
+        
+        [self.inputTextField.trailingAnchor constraintEqualToAnchor:self.captchaImageView.leadingAnchor constant:-10],
+
+        [self.cancelButton.topAnchor constraintEqualToAnchor:self.inputTextField.bottomAnchor constant:30],
+        [self.cancelButton.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:20],
+        [self.cancelButton.heightAnchor constraintEqualToConstant:50],
+        [self.cancelButton.trailingAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:-10],
+
+        [self.confirmButton.topAnchor constraintEqualToAnchor:self.inputTextField.bottomAnchor constant:30],
+        [self.confirmButton.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-20],
+        [self.confirmButton.heightAnchor constraintEqualToConstant:50],
+        [self.confirmButton.leadingAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:10],
+    ]];
+}
+
+- (void)loadCaptchaImage {
+    [self getCaptchaImageCompletion:^(UIImage *image) {
+        if (image) {
+            self.captchaImageView.image = image;
+        } else {
+            self.captchaImageView.image = ImageByName(@"ym_sound_showcase_refresh_icon");
+        }
+    }];
+}
+
+- (void)inputTextChanged:(UITextField *)textField {
+    NSString *text = textField.text;
+    if (text.length > 4) {
+        textField.text = [text substringToIndex:3];
+    }
+}
+
+
+#pragma mark - UITextFieldDelegate
+- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
+    
+    // 如果是删除操作,允许
+    if (string.length == 0) {
+        return YES;
+    }
+    
+    // 使用正则表达式判断是否只包含字母和数字
+    NSString *pattern = @"^[a-zA-Z0-9]+$";
+    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
+    return [predicate evaluateWithObject:string];
+}
+
+#pragma mark - Actions
+
+- (void)cancelButtonTapped {
+//    if ([self.delegate respondsToSelector:@selector(captchaViewDidCancel)]) {
+//        [self.delegate captchaViewDidCancel];
+//    }
+    
+    if (self.cancelButtonTappedBlock) {
+        self.cancelButtonTappedBlock();
+    }
+    [self dismiss];
+}
+
+- (void)confirmButtonTapped {
+    if (self.confirmButtonTappedBlock) {
+        self.confirmButtonTappedBlock(self.inputTextField.text);
+    }
+    [self dismiss];
+    
+//    if ([self.delegate respondsToSelector:@selector(captchaViewDidConfirmWithInput:)]) {
+//        [self.delegate captchaViewDidConfirmWithInput:self.inputTextField.text];
+//    }
+    
+    
+    // Optionally dismiss after confirm, or let the delegate handle it
+    // [self dismiss];
+}
+
+#pragma mark - Public Methods
+
+- (void)showInView:(UIView *)view {
+    self.frame = view.bounds;
+    [view addSubview:self];
+    self.alpha = 0;
+    self.contentView.transform = CGAffineTransformMakeScale(0.5, 0.5);
+    [UIView animateWithDuration:0.3 animations:^{
+        self.alpha = 1;
+        self.contentView.transform = CGAffineTransformIdentity;
+    }];
+}
+
+- (void)dismiss {
+    [UIView animateWithDuration:0.3 animations:^{
+        self.alpha = 0;
+        self.contentView.transform = CGAffineTransformMakeScale(0.5, 0.5);
+    } completion:^(BOOL finished) {
+        [self removeFromSuperview];
+    }];
+}
+
+- (void)setCaptchaImage:(UIImage *)image {
+    self.captchaImageView.image = image;
+}
+
+
+ - (void)refreshCaptcha {
+     NSLog(@"Refresh captcha tapped");
+     [self loadCaptchaImage];
+ }
+
+- (void)getCaptchaImageCompletion:(void(^)(UIImage *image))completion {
+    NSString * urlstr=[NSString stringWithFormat:@"%@%@",[LCSaveData getBaseURL]?[LCSaveData getBaseURL]:BaseURL,GetCaptcha];
+    NSURL *url = [NSURL URLWithString:urlstr];
+    if (!url) {
+        NSLog(@"Captcha URL is nil");
+        return;
+    }
+    
+    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
+        if (error) {
+            NSLog(@"Error fetching captcha image: %@", error.localizedDescription);
+        } else if (data) {
+            UIImage *image = [UIImage imageWithData:data];
+            if (image) {
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    completion(image);
+                    //self.captchaImageView.image = image;
+                });
+            } else {
+                NSLog(@"Failed to convert data to image");
+            }
+        } else {
+            NSLog(@"No data received for captcha image");
+        }
+    }];
+    [task resume];
+}
+
+
+@end

+ 54 - 20
MSYOUPAI/NewCode/Module/Register/View/YMRegisterView.m

@@ -8,6 +8,9 @@
 
 #import "YMRegisterView.h"
 #import "YMRegisterViewModel.h"
+#import "YMCaptchaPopupView.h"
+#import "CaptchaCenter.h"
+
 @interface YMRegisterView ()
 /// 注册VM
 @property (nonatomic, strong) YMRegisterViewModel *viewModel;
@@ -385,10 +388,12 @@
 - (YMCaptchaCountdownButton *)getVerifyCodeBtn{
     if (!_getVerifyCodeBtn) {
         _getVerifyCodeBtn = [YMCaptchaCountdownButton buttonWithType:UIButtonTypeCustom];
-        _getVerifyCodeBtn.titleLabel.font = LCFont(13);
-        [_getVerifyCodeBtn setTitleColor:MainColor forState:UIControlStateNormal];
+        _getVerifyCodeBtn.titleLabel.font = LCFont(14);
+        [_getVerifyCodeBtn setTitleColor:HexColorFromRGB(0xFF6893) forState:UIControlStateNormal];
         [_getVerifyCodeBtn setTitle:@"获取验证码" forState:UIControlStateNormal];
+        @weakify(self)
         [_getVerifyCodeBtn countDownButtonHandler:^(YMCaptchaCountdownButton *sender, NSInteger tag) {
+            @strongify(self)
             if (OCStringIsEmpty(self.mobileInputBox.text)) {
                 [ZCHUDHelper showTitle:@"请输入手机号"];
                 return;
@@ -398,30 +403,59 @@
             [self.verifyCodeInputBox resignFirstResponder];
             [self.passwordInputBox resignFirstResponder];
             
-            [self.viewModel getVerifyCodeHandler:^(NSDictionary * _Nonnull dic, NSError * _Nullable error) {
-                
-                sender.enabled = NO;
-                
-                [sender startCountDownWithSecond:59];
-
-                [sender countDownChanging:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
-                    NSString *title = [NSString stringWithFormat:@"重新发送(%zds)",second];
-                    return title;
-                }];
-                
-                [sender countDownFinished:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
-                    countDownButton.enabled = YES;
-                    return @"重新发送";
-                    
-                }];
-                
+            
+            [CaptchaCenter.defaultCenter getCaptchaType:^(NSNumber * _Nullable type, NSError * _Nullable error) {
+                if (error) {
+                    [ZCHUDHelper showTitle:@"获取验证码失败"];
+                    return;
+                }
+                if ([type isEqualToNumber:@1]) { // 原生
+                    YMCaptchaPopupView *view = [[YMCaptchaPopupView alloc] init];
+                    view.cancelButtonTappedBlock = ^{};
+                    @weakify(self)
+                    view.confirmButtonTappedBlock = ^(NSString * _Nonnull input) {
+                        @strongify(self)
+                        [self getVerifyCodeWithCaptcha:input sender:sender];
+                    };
+                    UIView *currentVCView = [LCTools getCurrentVC].view;
+                    if (currentVCView != nil && ![currentVCView isEqual:NSNull.null]) {
+                        [view showInView:currentVCView];
+                    }
+                } else { // 阿里
+                    @weakify(self)
+                    [CaptchaCenter.defaultCenter verifyCompletion:^(NSString * _Nonnull status, NSDictionary * _Nonnull result) {
+                        @strongify(self)
+                        [self getVerifyCodeWithCaptcha:result sender:sender];
+                    }];
+                }
             }];
-
+            
         }];
     }
     return _getVerifyCodeBtn;
 }
 
+- (void)getVerifyCodeWithCaptcha:(id)captcha sender:(YMCaptchaCountdownButton *)sender {
+    @weakify(self)
+    [self.viewModel getVerifyCodeWithCaptcha:captcha handler:^(NSDictionary * _Nonnull dic, NSError * _Nullable error) {
+        @strongify(self)
+        sender.enabled = NO;
+        
+        [sender startCountDownWithSecond:59];
+
+        [sender countDownChanging:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
+            NSString *title = [NSString stringWithFormat:@"重新发送(%zds)",second];
+            return title;
+        }];
+        
+        [sender countDownFinished:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
+            countDownButton.enabled = YES;
+            return @"重新发送";
+        }];
+    }];
+}
+
+
 - (UIView *)passwordView{
     if (!_passwordView) {
         _passwordView = [[UIView alloc]init];

+ 2 - 1
MSYOUPAI/NewCode/Module/Register/ViewModel/YMRegisterViewModel.h

@@ -19,8 +19,9 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nonatomic, copy) NSString *verifyCode;
 /// 密码
 @property (nonatomic, copy) NSString *password;
+
 /// 获取验证码
-- (void)getVerifyCodeHandler:(void(^)(NSDictionary *dic,NSError * _Nullable error))handler;
+- (void)getVerifyCodeWithCaptcha:(id)captcha handler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler ;
 /// 注册请求
 - (void)registerRequest;
 @end

+ 12 - 5
MSYOUPAI/NewCode/Module/Register/ViewModel/YMRegisterViewModel.m

@@ -28,13 +28,20 @@
 }
 
 /// 获取验证码
-- (void)getVerifyCodeHandler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler{
+- (void)getVerifyCodeWithCaptcha:(id)captcha handler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler {
+    NSMutableDictionary *dictm = [NSMutableDictionary dictionary];
+    dictm[@"mobile"] = self.mobile;
+    dictm[@"type"] = @"register";
+    if ([captcha isKindOfClass:[NSString class]]) {
+        dictm[@"captcha"] = captcha;
+    }
+    if ([captcha isKindOfClass:[NSDictionary class]]) {
+        [dictm addEntriesFromDictionary:captcha];
+    }
+    
     @weakify(self)
     [ZCHUDHelper showWithStatus:@"获取验证码中"];
-    [LCHttpHelper requestWithURLString:PhoneCode parameters:@{
-        @"mobile":self.mobile,
-        @"type":@"login"
-    } needToken:NO type:HttpRequestTypePost success:^(id responseObject) {
+    [LCHttpHelper requestWithURLString:PhoneCode parameters:dictm needToken:NO type:HttpRequestTypePost success:^(id responseObject) {
         @strongify(self)
         NSDictionary* dict = (NSDictionary*)responseObject;
         NSInteger code =  [[dict objectForKey:@"code"] integerValue];

+ 54 - 19
MSYOUPAI/NewCode/Module/RetrievePassword/View/YMRetrievePasswordView.m

@@ -8,6 +8,9 @@
 
 #import "YMRetrievePasswordView.h"
 #import "YMRetrievePasswordViewModel.h"
+#import "YMCaptchaPopupView.h"
+#import "CaptchaCenter.h"
+
 @interface YMRetrievePasswordView ()
 /// 找回密码VM
 @property (nonatomic, strong) YMRetrievePasswordViewModel *viewModel;
@@ -277,9 +280,12 @@
     if (!_getVerifyCodeBtn) {
         _getVerifyCodeBtn = [YMCaptchaCountdownButton buttonWithType:UIButtonTypeCustom];
         _getVerifyCodeBtn.titleLabel.font = LCFont(14);
-        [_getVerifyCodeBtn setTitleColor:rgba(252, 94, 158, 1) forState:UIControlStateNormal];
+        [_getVerifyCodeBtn setTitleColor:HexColorFromRGB(0x6D82FD) forState:UIControlStateNormal];
         [_getVerifyCodeBtn setTitle:@"获取验证码" forState:UIControlStateNormal];
+        @weakify(self)
         [_getVerifyCodeBtn countDownButtonHandler:^(YMCaptchaCountdownButton *sender, NSInteger tag) {
+            @strongify(self)
+            
             if (OCStringIsEmpty(self.mobileInputBox.text)) {
                 [ZCHUDHelper showTitle:@"请输入手机号"];
                 return;
@@ -289,31 +295,60 @@
             [self.verifyCodeInputBox resignFirstResponder];
             [self.passwordInputBox resignFirstResponder];
             
-            [self.viewModel getVerifyCodeHandler:^(NSDictionary * _Nonnull dic, NSError * _Nullable error) {
-                
-                sender.enabled = NO;
-                
-                [sender startCountDownWithSecond:59];
-
-                [sender countDownChanging:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
-                    NSString *title = [NSString stringWithFormat:@"重新发送(%zds)",second];
-                    return title;
-                }];
-                
-                [sender countDownFinished:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
-                    countDownButton.enabled = YES;
-                    return @"重新发送";
-                    
-                }];
-                
+            [CaptchaCenter.defaultCenter getCaptchaType:^(NSNumber * _Nullable type, NSError * _Nullable error) {
+                if (error) {
+                    [ZCHUDHelper showTitle:@"获取验证码失败"];
+                    return;
+                }
+                if ([type isEqualToNumber:@1]) { // 原生
+                    YMCaptchaPopupView *view = [[YMCaptchaPopupView alloc] init];
+                    view.cancelButtonTappedBlock = ^{};
+                    @weakify(self)
+                    view.confirmButtonTappedBlock = ^(NSString * _Nonnull input) {
+                        @strongify(self)
+                        [self getVerifyCodeWithCapthca:input sender:sender];
+                    };
+                    UIView *currentVCView = [LCTools getCurrentVC].view;
+                    if (currentVCView != nil && ![currentVCView isEqual:NSNull.null]) {
+                        [view showInView:currentVCView];
+                    }
+                } else { // 阿里
+                    @weakify(self)
+                    [CaptchaCenter.defaultCenter verifyCompletion:^(NSString * _Nonnull status, NSDictionary * _Nonnull result) {
+                        @strongify(self)
+                        [self getVerifyCodeWithCapthca:result sender:sender];
+                    }];
+                }
             }];
-            
 
         }];
     }
     return _getVerifyCodeBtn;
 }
 
+- (void)getVerifyCodeWithCapthca:(id)captcha sender:(YMCaptchaCountdownButton *)sender {
+    @weakify(self)
+    [self.viewModel getVerifyCodeWithCapthca:captcha Handler:^(NSDictionary * _Nonnull dic, NSError * _Nullable error) {
+        @strongify(self)
+        sender.enabled = NO;
+        
+        [sender startCountDownWithSecond:59];
+        
+        [sender countDownChanging:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
+            NSString *title = [NSString stringWithFormat:@"重新发送(%zds)",second];
+            return title;
+        }];
+        
+        [sender countDownFinished:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
+            countDownButton.enabled = YES;
+            return @"重新发送";
+            
+        }];
+        
+    }];
+}
+
+
 - (UIView *)passwordView{
     if (!_passwordView) {
         _passwordView = [[UIView alloc]init];

+ 1 - 1
MSYOUPAI/NewCode/Module/RetrievePassword/ViewModel/YMRetrievePasswordViewModel.h

@@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
 /// 密码
 @property (nonatomic, copy) NSString *password;
 /// 获取验证码
-- (void)getVerifyCodeHandler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler;
+- (void)getVerifyCodeWithCapthca:(id)captcha Handler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler;
 /// 找回密码请求
 - (void)retrievePasswordRequest;
 @end

+ 12 - 5
MSYOUPAI/NewCode/Module/RetrievePassword/ViewModel/YMRetrievePasswordViewModel.m

@@ -28,13 +28,20 @@
 }
 
 /// 获取验证码
-- (void)getVerifyCodeHandler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler{
+- (void)getVerifyCodeWithCapthca:(id)captcha Handler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler{
+    NSMutableDictionary *dictm = [NSMutableDictionary dictionary];
+    dictm[@"mobile"] = self.mobile;
+    dictm[@"type"] = @"findadpwd";
+    if ([captcha isKindOfClass:[NSString class]]) {
+        dictm[@"captcha"] = captcha;
+    }
+    if ([captcha isKindOfClass:[NSDictionary class]]) {
+        [dictm addEntriesFromDictionary:captcha];
+    }
+    
     @weakify(self)
     [ZCHUDHelper showWithStatus:@"获取验证码中"];
-    [LCHttpHelper requestWithURLString:PhoneCode parameters:@{
-        @"mobile":self.mobile,
-        @"type":@"findadpwd"
-    } needToken:NO type:HttpRequestTypePost success:^(id responseObject) {
+    [LCHttpHelper requestWithURLString:PhoneCode parameters:dictm needToken:NO type:HttpRequestTypePost success:^(id responseObject) {
         @strongify(self)
         NSDictionary* dict = (NSDictionary*)responseObject;
         NSInteger code =  [[dict objectForKey:@"code"] integerValue];

+ 54 - 20
MSYOUPAI/NewCode/Module/VerifyCodeLogin/View/YMVerifyCodeLoginView.m

@@ -8,6 +8,9 @@
 
 #import "YMVerifyCodeLoginView.h"
 #import "YMVerifyCodeLoginViewModel.h"
+#import "YMCaptchaPopupView.h"
+#import "CaptchaCenter.h"
+
 @interface YMVerifyCodeLoginView ()
 /// 验证码登录VM
 @property (nonatomic, strong) YMVerifyCodeLoginViewModel *viewModel;
@@ -247,9 +250,11 @@
     if (!_getVerifyCodeBtn) {
         _getVerifyCodeBtn = [YMCaptchaCountdownButton buttonWithType:UIButtonTypeCustom];
         _getVerifyCodeBtn.titleLabel.font = LCFont(14);
-        [_getVerifyCodeBtn setTitleColor:MainColor forState:UIControlStateNormal];
+        [_getVerifyCodeBtn setTitleColor:HexColorFromRGB(0xB26AFD) forState:UIControlStateNormal];
         [_getVerifyCodeBtn setTitle:@"获取验证码" forState:UIControlStateNormal];
+        @weakify(self)
         [_getVerifyCodeBtn countDownButtonHandler:^(YMCaptchaCountdownButton *sender, NSInteger tag) {
+            @strongify(self)
             if (OCStringIsEmpty(self.mobileInputBox.text)) {
                 [ZCHUDHelper showTitle:@"请输入手机号"];
                 return;
@@ -259,31 +264,60 @@
             [self.verifyCodeInputBox resignFirstResponder];
             [self.verifyCodeInputBox resignFirstResponder];
             
-            [self.viewModel getVerifyCodeHandler:^(NSDictionary * _Nonnull dic, NSError * _Nullable error) {
-                
-                sender.enabled = NO;
-                
-                [sender startCountDownWithSecond:59];
-
-                [sender countDownChanging:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
-                    NSString *title = [NSString stringWithFormat:@"重新发送(%zds)",second];
-                    return title;
-                }];
-                
-                [sender countDownFinished:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
-                    countDownButton.enabled = YES;
-                    return @"重新发送";
-                    
-                }];
-                
+            [CaptchaCenter.defaultCenter getCaptchaType:^(NSNumber * _Nullable type, NSError * _Nullable error) {
+                if (error) {
+                    [ZCHUDHelper showTitle:@"获取验证码失败"];
+                    return;
+                }
+                if ([type isEqualToNumber:@1]) { // 原生
+                    YMCaptchaPopupView *view = [[YMCaptchaPopupView alloc] init];
+                    view.cancelButtonTappedBlock = ^{};
+                    @weakify(self)
+                    view.confirmButtonTappedBlock = ^(NSString * _Nonnull input) {
+                        @strongify(self)
+                        [self getVerifyCodeWithCapthca:input sender:sender];
+                    };
+                    UIView *currentVCView = [LCTools getCurrentVC].view;
+                    if (currentVCView != nil && ![currentVCView isEqual:NSNull.null]) {
+                        [view showInView:currentVCView];
+                    }
+                } else { // 阿里
+                    @weakify(self)
+                    [CaptchaCenter.defaultCenter verifyCompletion:^(NSString * _Nonnull status, NSDictionary * _Nonnull result) {
+                        @strongify(self)
+                        [self getVerifyCodeWithCapthca:result sender:sender];
+                    }];
+                }
             }];
-            
-
         }];
     }
     return _getVerifyCodeBtn;
 }
 
+- (void)getVerifyCodeWithCapthca:(id)capthca sender:(YMCaptchaCountdownButton *)sender {
+    //@weakify(self)
+    [self.viewModel getVerifyCodeWithCaptcha:capthca Handler:^(NSDictionary * _Nonnull dic, NSError * _Nullable error) {
+        //@strongify(self)
+        
+        sender.enabled = NO;
+        
+        [sender startCountDownWithSecond:59];
+
+        [sender countDownChanging:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
+            NSString *title = [NSString stringWithFormat:@"重新发送(%zds)",second];
+            return title;
+        }];
+        
+        [sender countDownFinished:^NSString *(YMCaptchaCountdownButton *countDownButton, NSUInteger second) {
+            countDownButton.enabled = YES;
+            return @"重新发送";
+            
+        }];
+        
+    }];
+}
+
+
 
 - (UIView *)agreementView{
     if (!_agreementView) {

+ 1 - 1
MSYOUPAI/NewCode/Module/VerifyCodeLogin/ViewModel/YMVerifyCodeLoginViewModel.h

@@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
 /// 验证码
 @property (nonatomic, copy) NSString *verifyCode;
 /// 获取验证码
-- (void)getVerifyCodeHandler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler;
+- (void)getVerifyCodeWithCaptcha:(id)captcha Handler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler;
 /// 登录请求
 - (void)loginRequest;
 /// 前往注册界面

+ 12 - 5
MSYOUPAI/NewCode/Module/VerifyCodeLogin/ViewModel/YMVerifyCodeLoginViewModel.m

@@ -30,13 +30,20 @@
 }
 
 /// 获取验证码
-- (void)getVerifyCodeHandler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler{
+- (void)getVerifyCodeWithCaptcha:(id)captcha Handler:(void(^)(NSDictionary *dic, NSError * _Nullable error))handler{
+    NSMutableDictionary *dictm = [NSMutableDictionary dictionary];
+    dictm[@"mobile"] = self.mobile;
+    dictm[@"type"] = @"login";
+    if ([captcha isKindOfClass:[NSString class]]) {
+        dictm[@"captcha"] = captcha;
+    }
+    if ([captcha isKindOfClass:[NSDictionary class]]) {
+        [dictm addEntriesFromDictionary:captcha];
+    }
+        
     @weakify(self)
     [ZCHUDHelper showWithStatus:@"获取验证码中"];
-    [LCHttpHelper requestWithURLString:PhoneCode parameters:@{
-        @"mobile":self.mobile,
-        @"type":@"login"
-    } needToken:NO type:HttpRequestTypePost success:^(id responseObject) {
+    [LCHttpHelper requestWithURLString:PhoneCode parameters:dictm needToken:NO type:HttpRequestTypePost success:^(id responseObject) {
         @strongify(self)
         NSDictionary* dict = (NSDictionary*)responseObject;
         NSInteger code =  [[dict objectForKey:@"code"] integerValue];

+ 4 - 4
MSYOUPAI/Others/Utils/Helper/LCHttpHelper.m

@@ -104,7 +104,7 @@ static NSString *kChannel = @"22";
             [manager.requestSerializer setValue:tokenStr forHTTPHeaderField:@"token"];
         }else{
             [[NSNotificationCenter defaultCenter] postNotificationName:@"AbnormalLogout" object:nil userInfo:nil];
-            [ZCHUDHelper showTitle:@"登录状态过期,需重新登录" showtime:4];
+            //[ZCHUDHelper showTitle:@"登录状态过期,需重新登录" showtime:4];
             [LCTools changeRootToLogin];
         }
     }
@@ -282,7 +282,7 @@ static NSString *kChannel = @"22";
         
     }else if(code==1001){
         [[NSNotificationCenter defaultCenter] postNotificationName:@"AbnormalLogout" object:nil userInfo:nil];
-        [ZCHUDHelper showTitle:@"登录状态过期,需重新登录"];
+        //[ZCHUDHelper showTitle:@"登录状态过期,需重新登录"];
         [LCTools changeRootToLogin];
     }else if(code==1002){
         [ZCHUDHelper showTitle:@"您的可用余额不足"];
@@ -414,9 +414,9 @@ static NSString *kChannel = @"22";
     
     NSString *signStr;
     if (sortKeys.count == 0) {
-        signStr = [NSString stringWithFormat:@"%@%@%@%@",@"2jot2Ioj31oFT9DI",timeSp,random,[LCTools getUUIDString]];
+        signStr = [NSString stringWithFormat:@"%@%@%@%@",kYanQianKey,timeSp,random,[LCTools getUUIDString]];
     }else{
-        signStr = [NSString stringWithFormat:@"%@%@%@%@%@",string,@"2jot2Ioj31oFT9DI",timeSp,random,[LCTools getUUIDString]];
+        signStr = [NSString stringWithFormat:@"%@%@%@%@%@",string,kYanQianKey,timeSp,random,[LCTools getUUIDString]];
     }
     NSLog(@"str = %@",signStr);
     

+ 5 - 6
MSYOUPAI/Others/Utils/LPSecureData.m

@@ -10,7 +10,6 @@
 #import  <CommonCrypto/CommonCryptor.h>
 
 #define LocalStr_None @""
-#define AESKEYVALUE @"!IQ31NeGcV&*n6w="
 
 static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
@@ -39,7 +38,7 @@ static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq
     NSString* jsonStr = [dict mj_JSONString];
 //    NSString* newStr = [jsonStr stringByAppendingString:[self getRadomStr:4]];
     NSData *data = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
-    NSData* aesdata = [self AES128operation:kCCEncrypt data:data key:AESKEYVALUE iv:AESKEYVALUE];
+    NSData* aesdata = [self AES128operation:kCCEncrypt data:data key:kJiaMiKey iv:kJiaMiKey];
     NSLog(@"加密后的字符串为%@",[self base64EncodedStringFrom:aesdata]);
     return [self base64EncodedStringFrom:aesdata];
 }
@@ -48,8 +47,8 @@ static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq
     NSData *data = [self dataWithBase64EncodedString:str];
     NSData *aesData = [self AES128operation:kCCDecrypt
                                            data:data
-                                            key:AESKEYVALUE
-                                             iv:AESKEYVALUE];
+                                            key:kJiaMiKey
+                                             iv:kJiaMiKey];
     NSDictionary* dict = [aesData mj_JSONObject];
     return dict;
 }
@@ -202,8 +201,8 @@ static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq
     NSData *data = [self dataWithBase64EncodedString:str];
     NSData *aesData = [self AES128operation:kCCDecrypt
                                            data:data
-                                            key:AESKEYVALUE
-                                             iv:AESKEYVALUE];//AES解密
+                                            key:kJiaMiKey
+                                             iv:kJiaMiKey];//AES解密
     NSString *base64 = [[NSString alloc] initWithData:aesData encoding:NSUTF8StringEncoding];
     if (!base64) {
         NSLog(@"AES加密解析失败");

+ 20 - 0
MSYOUPAI/VQBase/config/MSYOUPAI.pch

@@ -67,6 +67,24 @@
 #import <UMPush/UMessage.h>
 #import "UMengRecordTool.h"
 
+#ifdef DEBUG
+#define kJiaMiKey          @"JANp_XpXL^&1c47l" // 接口加密
+#define kYanQianKey        @"O-R0aDC=MEZYP0&%" // 接口验签
+//第三方SDK Key
+//#define TalkingDataID      @"33338A19561C48FDA138E078691A4E93"
+#define BuglyAppId         @"6d2437b479"//Bugly
+#define UMAppKey           @"66a12d93940d5a4c4998b295"//友盟
+#define AgoraID            @"25cac1e50c684f5c91e60327056d2571"//声网
+#define NIMSDKID           @"c25c8fd87f554d2df631a812b9524340"//云信
+#define OpenWXID           @"wxd5de43f2840a3c42"//微信开放平台
+#define WXUniversalLink    @"https://api.yanyanghong.top/"//微信通用链接,比 BaseURL 多一个 "/"
+#define kBaseURL           @"https://api.wuhanyyh.cn" // BaseUrl
+#define kBaseImgURL        @"https://api.wuhanyyh.cn/" // oss
+
+#else
+
+#define kJiaMiKey          @"!IQ31NeGcV&*n6w=" // 接口加密
+#define kYanQianKey        @"2jot2Ioj31oFT9DI" // 接口验签
 //第三方SDK Key
 //#define TalkingDataID      @"33338A19561C48FDA138E078691A4E93"
 #define BuglyAppId         @"6d2437b479"//Bugly
@@ -78,6 +96,8 @@
 #define kBaseURL           @"https://api.yanyanghong.top" // BaseUrl
 #define kBaseImgURL        @"https://oss.yanyanghong.top/" // oss
 
+#endif
+
 
 #define KHistorySearchPath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"PYSearchhistories.plist"]
 #define DocPath            [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]

+ 4 - 2
MSYOUPAI/VQBase/config/ServerURL.h

@@ -41,13 +41,15 @@
 #define AppConfig           @"/api/app/config"  //系统配置信息
 #define LevelInfo           @"/api/common/icon"  //获取等级图标
 #define AllBadge @"/api/dress/getAllBadge" //获取所有徽章 和 贵族图标
-#define SystemIndex        @"/api/system/index"  //打开app最先请求的接口
+#define SystemIndex         @"/api/system/index"  //打开app最先请求的接口
 #define ActiveUpdate        @"/api/user/active_update" //更新活跃时间
 //登录注册
 #define PhoneRegister       @"/api/passport/register"            //手机注册
 #define PhoneLogin          @"/api/passport/login"               //手机登录
 #define PhoneCode           @"/api/passport/send_code"           //发送验证码
-#define Getnickname           @"/api/user/nickname"           //系统头像+昵称
+#define GetCaptcha          @"/api/passport/captcha"           //获取图片验证码
+#define GetCaptchaType      @"/api/passport/captcha_type"      //获取验证码类型,返回1是原生验证码, 2是阿里验证码
+#define Getnickname         @"/api/user/nickname"           //系统头像+昵称
 
 #define PhoneCodeLogin           @"/api/passport/codeLogin"           //手机号验证码登录
 #define OncePhoneLogin       @"/api/passport/oneKeyLogin"            //一键手机号登录

+ 0 - 22
MSYOUPAITests/Info.plist

@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>$(DEVELOPMENT_LANGUAGE)</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-</dict>
-</plist>

+ 0 - 22
MSYOUPAIUITests/Info.plist

@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>$(DEVELOPMENT_LANGUAGE)</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-</dict>
-</plist>

+ 115 - 0
Pods/Pods.xcodeproj/xcuserdata/macmini.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -8,276 +8,391 @@
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>1</integer>
 		</dict>
 		<key>AlipaySDK-iOS.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>2</integer>
 		</dict>
 		<key>AliyunOSSiOS.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>3</integer>
 		</dict>
 		<key>BAGridView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>4</integer>
 		</dict>
 		<key>BATextField.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>5</integer>
 		</dict>
 		<key>BAWKWebView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>6</integer>
 		</dict>
 		<key>CHTCollectionViewWaterfallLayout.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>7</integer>
 		</dict>
 		<key>CocoaAsyncSocket.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>8</integer>
 		</dict>
 		<key>FLAnimatedImage.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>9</integer>
 		</dict>
 		<key>GKNavigationBarViewController.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>10</integer>
 		</dict>
 		<key>IQKeyboardManager-IQKeyboardManager.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>12</integer>
 		</dict>
 		<key>IQKeyboardManager.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>11</integer>
 		</dict>
 		<key>JQCollectionViewAlignLayout.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>14</integer>
 		</dict>
 		<key>JXCategoryView-JXCategoryView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>16</integer>
 		</dict>
 		<key>JXCategoryView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>15</integer>
 		</dict>
 		<key>JXPagingView-JXPagerView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>18</integer>
 		</dict>
 		<key>JXPagingView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>17</integer>
 		</dict>
 		<key>JhtMarquee.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>13</integer>
 		</dict>
 		<key>KTVHTTPCache.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>19</integer>
 		</dict>
 		<key>LYEmptyView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>25</integer>
 		</dict>
 		<key>LookinServer.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>23</integer>
 		</dict>
 		<key>MJExtension-MJExtension.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>28</integer>
 		</dict>
 		<key>MJExtension.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>27</integer>
 		</dict>
 		<key>MJRefresh-MJRefresh.Privacy.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>30</integer>
 		</dict>
 		<key>MJRefresh.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>29</integer>
 		</dict>
 		<key>MSYConfig.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>31</integer>
 		</dict>
 		<key>Masonry.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>26</integer>
 		</dict>
 		<key>Nama-lite.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>32</integer>
 		</dict>
 		<key>PGDatePicker.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>33</integer>
 		</dict>
 		<key>PGPickerView.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>34</integer>
+		</dict>
+		<key>PixelFree.xcscheme_^#shared#^_</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>56</integer>
 		</dict>
 		<key>Pods-MSYOUPAI.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>35</integer>
 		</dict>
 		<key>PrintBeautifulLog.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>36</integer>
 		</dict>
 		<key>Protobuf-Protobuf_Privacy.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>38</integer>
 		</dict>
 		<key>Protobuf.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>37</integer>
 		</dict>
 		<key>ReactiveObjC.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>39</integer>
 		</dict>
 		<key>SDWebImage.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>40</integer>
 		</dict>
 		<key>SDWebImageAPNGCoder.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>41</integer>
 		</dict>
 		<key>SSZipArchive.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>42</integer>
 		</dict>
 		<key>SVGAPlayer.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>43</integer>
 		</dict>
 		<key>TFHpple.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>44</integer>
 		</dict>
 		<key>TZImagePickerController.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>45</integer>
 		</dict>
 		<key>UMAPM.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>46</integer>
 		</dict>
 		<key>UMCCommonLog.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>47</integer>
 		</dict>
 		<key>UMCommon.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>48</integer>
 		</dict>
 		<key>UMDevice.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>49</integer>
 		</dict>
 		<key>UMPush.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>50</integer>
 		</dict>
 		<key>UMShare.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>51</integer>
 		</dict>
 		<key>VODUpload.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>52</integer>
 		</dict>
 		<key>WechatOpenSDK.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>53</integer>
 		</dict>
 		<key>YYModel.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>54</integer>
 		</dict>
 		<key>YYText.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>55</integer>
 		</dict>
 		<key>libOpenInstallSDK-OPPrivacy.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>21</integer>
 		</dict>
 		<key>libOpenInstallSDK.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>20</integer>
 		</dict>
 		<key>libwebp.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>22</integer>
 		</dict>
 		<key>lottie-ios_Oc.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
+			<key>orderHint</key>
+			<integer>24</integer>
 		</dict>
 	</dict>
 	<key>SuppressBuildableAutocreation</key>