迁移仓库
This commit is contained in:
@@ -28,6 +28,13 @@
|
||||
20CC02D32D150A1C0001B529 /* DSAvatarCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 20CC02D12D150A1C0001B529 /* DSAvatarCollectionViewCell.xib */; };
|
||||
20DA04E42CD32AEF003530CA /* DSWebDragView.m in Sources */ = {isa = PBXBuildFile; fileRef = 20DA04E02CD32AEF003530CA /* DSWebDragView.m */; };
|
||||
20DA04E52CD32AEF003530CA /* WMDragView.m in Sources */ = {isa = PBXBuildFile; fileRef = 20DA04E12CD32AEF003530CA /* WMDragView.m */; };
|
||||
891A21472EAF3C4D008F03B3 /* GDWebPageHookService.m in Sources */ = {isa = PBXBuildFile; fileRef = 891A21422EAF3C4D008F03B3 /* GDWebPageHookService.m */; };
|
||||
891A21482EAF3C4D008F03B3 /* GDWebURLSessionDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 891A21462EAF3C4D008F03B3 /* GDWebURLSessionDelegate.m */; };
|
||||
891A21492EAF3C4D008F03B3 /* WKWebView+GDWebURLSchemeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 891A213D2EAF3C4D008F03B3 /* WKWebView+GDWebURLSchemeHandler.m */; };
|
||||
891A214A2EAF3C4D008F03B3 /* GDWebAssetStorageService.m in Sources */ = {isa = PBXBuildFile; fileRef = 891A21402EAF3C4D008F03B3 /* GDWebAssetStorageService.m */; };
|
||||
891A214B2EAF3C4D008F03B3 /* GDWebURLSchemeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 891A213B2EAF3C4D008F03B3 /* GDWebURLSchemeHandler.m */; };
|
||||
891A214C2EAF3C4D008F03B3 /* GDWebURLSessionService.m in Sources */ = {isa = PBXBuildFile; fileRef = 891A21442EAF3C4D008F03B3 /* GDWebURLSessionService.m */; };
|
||||
891A23692EC3178B008F03B3 /* GameWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 891A23682EC3178B008F03B3 /* GameWebViewController.m */; };
|
||||
896EC2172D4081AE00732103 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 896EC2162D4081AE00732103 /* CoreTelephony.framework */; };
|
||||
89A55AD72D4210CF0000FE0F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 89A55AD62D4210CF0000FE0F /* GoogleService-Info.plist */; };
|
||||
9D06CD612B70B72500A5CDF7 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D06CD602B70B72500A5CDF7 /* libc++.tbd */; };
|
||||
@@ -123,6 +130,21 @@
|
||||
20DA04E32CD32AEF003530CA /* WMDragView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMDragView.h; sourceTree = "<group>"; };
|
||||
2770952325ADBC033AEA844E /* Pods_SQNoti.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SQNoti.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
30D1D837206E6AC5F27F4CB4 /* Pods-ShenQi.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShenQi.release.xcconfig"; path = "Target Support Files/Pods-ShenQi/Pods-ShenQi.release.xcconfig"; sourceTree = "<group>"; };
|
||||
891A213A2EAF3C4D008F03B3 /* GDWebURLSchemeHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDWebURLSchemeHandler.h; sourceTree = "<group>"; };
|
||||
891A213B2EAF3C4D008F03B3 /* GDWebURLSchemeHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GDWebURLSchemeHandler.m; sourceTree = "<group>"; };
|
||||
891A213C2EAF3C4D008F03B3 /* WKWebView+GDWebURLSchemeHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WKWebView+GDWebURLSchemeHandler.h"; sourceTree = "<group>"; };
|
||||
891A213D2EAF3C4D008F03B3 /* WKWebView+GDWebURLSchemeHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "WKWebView+GDWebURLSchemeHandler.m"; sourceTree = "<group>"; };
|
||||
891A213E2EAF3C4D008F03B3 /* GDWebCustomURLSchemeProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDWebCustomURLSchemeProtocol.h; sourceTree = "<group>"; };
|
||||
891A213F2EAF3C4D008F03B3 /* GDWebAssetStorageService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDWebAssetStorageService.h; sourceTree = "<group>"; };
|
||||
891A21402EAF3C4D008F03B3 /* GDWebAssetStorageService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GDWebAssetStorageService.m; sourceTree = "<group>"; };
|
||||
891A21412EAF3C4D008F03B3 /* GDWebPageHookService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDWebPageHookService.h; sourceTree = "<group>"; };
|
||||
891A21422EAF3C4D008F03B3 /* GDWebPageHookService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GDWebPageHookService.m; sourceTree = "<group>"; };
|
||||
891A21432EAF3C4D008F03B3 /* GDWebURLSessionService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDWebURLSessionService.h; sourceTree = "<group>"; };
|
||||
891A21442EAF3C4D008F03B3 /* GDWebURLSessionService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GDWebURLSessionService.m; sourceTree = "<group>"; };
|
||||
891A21452EAF3C4D008F03B3 /* GDWebURLSessionDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDWebURLSessionDelegate.h; sourceTree = "<group>"; };
|
||||
891A21462EAF3C4D008F03B3 /* GDWebURLSessionDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GDWebURLSessionDelegate.m; sourceTree = "<group>"; };
|
||||
891A23672EC3178B008F03B3 /* GameWebViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GameWebViewController.h; sourceTree = "<group>"; };
|
||||
891A23682EC3178B008F03B3 /* GameWebViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GameWebViewController.m; sourceTree = "<group>"; };
|
||||
896EC2162D4081AE00732103 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
|
||||
89A55AD62D4210CF0000FE0F /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
9D06CD602B70B72500A5CDF7 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||
@@ -249,6 +271,8 @@
|
||||
20CC02C92D141B650001B529 /* LaunchViewController.xib */,
|
||||
207022AD2CD8C1C10061657B /* MainOldViewController.h */,
|
||||
207022AE2CD8C1C10061657B /* MainOldViewController.m */,
|
||||
891A23672EC3178B008F03B3 /* GameWebViewController.h */,
|
||||
891A23682EC3178B008F03B3 /* GameWebViewController.m */,
|
||||
9D834B862D320969005B7327 /* NotiCenterViewController.h */,
|
||||
9D834B872D320969005B7327 /* NotiCenterViewController.m */,
|
||||
9D834B882D320969005B7327 /* NotiCenterViewController.xib */,
|
||||
@@ -271,6 +295,19 @@
|
||||
9D834BA22D3214C2005B7327 /* PushRecordData.m */,
|
||||
9D834BA42D3214C3005B7327 /* PushRecordList.h */,
|
||||
9D834BA12D3214C2005B7327 /* PushRecordList.m */,
|
||||
891A213A2EAF3C4D008F03B3 /* GDWebURLSchemeHandler.h */,
|
||||
891A213B2EAF3C4D008F03B3 /* GDWebURLSchemeHandler.m */,
|
||||
891A213C2EAF3C4D008F03B3 /* WKWebView+GDWebURLSchemeHandler.h */,
|
||||
891A213D2EAF3C4D008F03B3 /* WKWebView+GDWebURLSchemeHandler.m */,
|
||||
891A213E2EAF3C4D008F03B3 /* GDWebCustomURLSchemeProtocol.h */,
|
||||
891A213F2EAF3C4D008F03B3 /* GDWebAssetStorageService.h */,
|
||||
891A21402EAF3C4D008F03B3 /* GDWebAssetStorageService.m */,
|
||||
891A21412EAF3C4D008F03B3 /* GDWebPageHookService.h */,
|
||||
891A21422EAF3C4D008F03B3 /* GDWebPageHookService.m */,
|
||||
891A21432EAF3C4D008F03B3 /* GDWebURLSessionService.h */,
|
||||
891A21442EAF3C4D008F03B3 /* GDWebURLSessionService.m */,
|
||||
891A21452EAF3C4D008F03B3 /* GDWebURLSessionDelegate.h */,
|
||||
891A21462EAF3C4D008F03B3 /* GDWebURLSessionDelegate.m */,
|
||||
89A55AD62D4210CF0000FE0F /* GoogleService-Info.plist */,
|
||||
20B317F32CD4BA6700B29987 /* YYModel */,
|
||||
20DA04DF2CD32AEF003530CA /* WMDragView */,
|
||||
@@ -355,6 +392,7 @@
|
||||
TargetAttributes = {
|
||||
20B61C7729DC008500CE7946 = {
|
||||
CreatedOnToolsVersion = 14.2;
|
||||
LastSwiftMigration = 1640;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -455,6 +493,12 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9D834BAC2D321722005B7327 /* UIButton+DSButtonBlock.m in Sources */,
|
||||
891A21472EAF3C4D008F03B3 /* GDWebPageHookService.m in Sources */,
|
||||
891A21482EAF3C4D008F03B3 /* GDWebURLSessionDelegate.m in Sources */,
|
||||
891A21492EAF3C4D008F03B3 /* WKWebView+GDWebURLSchemeHandler.m in Sources */,
|
||||
891A214A2EAF3C4D008F03B3 /* GDWebAssetStorageService.m in Sources */,
|
||||
891A214B2EAF3C4D008F03B3 /* GDWebURLSchemeHandler.m in Sources */,
|
||||
891A214C2EAF3C4D008F03B3 /* GDWebURLSessionService.m in Sources */,
|
||||
20CC02D22D150A1C0001B529 /* DSAvatarCollectionViewCell.m in Sources */,
|
||||
20DA04E42CD32AEF003530CA /* DSWebDragView.m in Sources */,
|
||||
9D834B8F2D320BC2005B7327 /* NotiCenterTableViewCell.m in Sources */,
|
||||
@@ -468,6 +512,7 @@
|
||||
20B61C7D29DC008500CE7946 /* AppDelegate.m in Sources */,
|
||||
207022AF2CD8C1C10061657B /* MainOldViewController.m in Sources */,
|
||||
20CC02C52D14183A0001B529 /* ConfigDataModel.m in Sources */,
|
||||
891A23692EC3178B008F03B3 /* GameWebViewController.m in Sources */,
|
||||
20CC02C62D14183A0001B529 /* ConfigData.m in Sources */,
|
||||
20B61C8E29DC008800CE7946 /* main.m in Sources */,
|
||||
20B317F92CD4BA6800B29987 /* YYClassInfo.m in Sources */,
|
||||
@@ -642,18 +687,19 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = ShenQi/ShenQiDebug.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 78T95AT28H;
|
||||
DEVELOPMENT_TEAM = 89Y643YWG7;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/ShenQi",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = ShenQi/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = RAPID97;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Nova9;
|
||||
INFOPLIST_KEY_NSAppleMusicUsageDescription = "需要访问相册权限用于照片上传,应用不会上传和存储您的照片";
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "需要相机权限用于拍照上传,应用不会上传和存储您的照片";
|
||||
INFOPLIST_KEY_NSContactsUsageDescription = "用于匹配您的好友";
|
||||
@@ -665,7 +711,7 @@
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = UIInterfaceOrientationPortrait;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -675,14 +721,16 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/ShenQi",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = noti.RAPID97;
|
||||
MARKETING_VERSION = 1.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = noti.NO1VA9SG4;
|
||||
PRODUCT_NAME = TESTAPP;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 6.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -693,18 +741,19 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = ShenQi/ShenQiRelease.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 78T95AT28H;
|
||||
DEVELOPMENT_TEAM = 89Y643YWG7;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/ShenQi",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = ShenQi/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = RAPID97;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Nova9;
|
||||
INFOPLIST_KEY_NSAppleMusicUsageDescription = "需要访问相册权限用于照片上传,应用不会上传和存储您的照片";
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "需要相机权限用于拍照上传,应用不会上传和存储您的照片";
|
||||
INFOPLIST_KEY_NSContactsUsageDescription = "用于匹配您的好友";
|
||||
@@ -716,7 +765,7 @@
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = UIInterfaceOrientationPortrait;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -726,14 +775,15 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/ShenQi",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = noti.RAPID97;
|
||||
MARKETING_VERSION = 1.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = noti.NO1VA9SG4;
|
||||
PRODUCT_NAME = TESTAPP;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 6.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
Binary file not shown.
@@ -3,4 +3,18 @@
|
||||
uuid = "8C3A038C-0CB6-445A-A27C-084577E8C5CA"
|
||||
type = "0"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "4B613790-7E9F-4906-844F-5F338E1E79E2"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
breakpointStackSelectionBehavior = "1"
|
||||
scope = "1"
|
||||
stopOnStyle = "0">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "微信图片_20250819133612_1137.jpg",
|
||||
"filename" : "app_logo.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
|
||||
BIN
ShenQi/Assets.xcassets/AppIcon.appiconset/app_logo.png
Normal file
BIN
ShenQi/Assets.xcassets/AppIcon.appiconset/app_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 769 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 107 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "微信图片_20250819133612_1137.jpg",
|
||||
"filename" : "app_logo.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
|
||||
BIN
ShenQi/Assets.xcassets/appLogo.imageset/app_logo.png
vendored
Normal file
BIN
ShenQi/Assets.xcassets/appLogo.imageset/app_logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 769 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 107 KiB |
@@ -26,7 +26,7 @@
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" red="0.074509806930000005" green="0.15686275059999999" blue="0.55294120309999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="wWz-RR-gyr" firstAttribute="centerY" secondItem="6Tk-OE-BBY" secondAttribute="centerY" constant="-40" id="CqV-4e-F3I"/>
|
||||
<constraint firstItem="wWz-RR-gyr" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="FHK-Fd-BPL"/>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="CLX-jd-tRb">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="CLX-jd-tRb">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@@ -55,15 +55,15 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jWy-uW-8Li" customClass="DSWebDragView">
|
||||
<rect key="frame" x="0.0" y="408.66666666666669" width="60" height="60"/>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jWy-uW-8Li" customClass="DSWebDragView">
|
||||
<rect key="frame" x="0.0" y="421" width="60" height="60"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="XG1-uZ-BDG"/>
|
||||
<constraint firstAttribute="width" secondItem="jWy-uW-8Li" secondAttribute="height" multiplier="1:1" id="yzH-EX-jDa"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<collectionView hidden="YES" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="rsS-Qz-Fg1" customClass="DSWebMenuCollectionView">
|
||||
<rect key="frame" x="0.0" y="271.66666666666669" width="60" height="334.00000000000006"/>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="rsS-Qz-Fg1" customClass="DSWebMenuCollectionView">
|
||||
<rect key="frame" x="0.0" y="284" width="60" height="334"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="60" id="gU5-UR-beg"/>
|
||||
@@ -105,7 +105,7 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="appLogo" translatesAutoresizingMaskIntoConstraints="NO" id="keb-Jy-qyA">
|
||||
<rect key="frame" x="96.666666666666686" y="298.66666666666669" width="200" height="200"/>
|
||||
<rect key="frame" x="96.666666666666686" y="311" width="200" height="200"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="200" id="B9b-Wy-kPu"/>
|
||||
@@ -114,7 +114,7 @@
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="cX4-SA-T7x"/>
|
||||
<color key="backgroundColor" red="0.078431375319999996" green="0.15294116739999999" blue="0.55294120309999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="keb-Jy-qyA" firstAttribute="centerX" secondItem="cX4-SA-T7x" secondAttribute="centerX" id="PJ3-c1-DbO"/>
|
||||
<constraint firstItem="keb-Jy-qyA" firstAttribute="centerY" secondItem="cX4-SA-T7x" secondAttribute="centerY" constant="-40" id="S3L-dn-yjZ"/>
|
||||
|
||||
23
ShenQi/GDWebAssetStorageService.h
Normal file
23
ShenQi/GDWebAssetStorageService.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// GDWebAssetStorageService.h
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "GDWebCustomURLSchemeProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GDWebAssetStorageService : NSObject <GDWebCustomURLSchemeProtocol>
|
||||
|
||||
/// 存储需要处理的请求任务
|
||||
@property (nonatomic, strong) id<WKURLSchemeTask> schemeTask;
|
||||
/// 处理完成的回调
|
||||
@property (nonatomic, copy) void(^completion)(void);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
83
ShenQi/GDWebAssetStorageService.m
Normal file
83
ShenQi/GDWebAssetStorageService.m
Normal file
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// GDWebAssetStorageService.m
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import "GDWebAssetStorageService.h"
|
||||
|
||||
@implementation GDWebAssetStorageService
|
||||
|
||||
#pragma mark - 初始化
|
||||
- (instancetype)initWithSchemeTask:(id<WKURLSchemeTask>)task {
|
||||
if (self = [super init]) {
|
||||
_schemeTask = task;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - GDWebCustomURLSchemeProtocol
|
||||
+ (BOOL)canService:(id<WKURLSchemeTask>)task {
|
||||
// 只处理 "asset://" 协议的请求
|
||||
NSString *scheme = task.request.URL.scheme.lowercaseString;
|
||||
return [scheme isEqualToString:@"asset"];
|
||||
}
|
||||
|
||||
- (void)startLoading:(void (^)(void))completion {
|
||||
self.completion = completion;
|
||||
NSURLRequest *request = self.schemeTask.request;
|
||||
NSURL *url = request.URL;
|
||||
|
||||
// 1. 解析本地资源路径(如 asset://images/logo.png -> 映射到沙盒中的 images/logo.png)
|
||||
NSString *path = [url.path stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]];
|
||||
NSString *localPath = [[NSBundle mainBundle] pathForResource:path ofType:nil];
|
||||
if (!localPath) {
|
||||
// 若主包中没有,检查 Documents 目录
|
||||
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:path];
|
||||
localPath = docPath;
|
||||
}
|
||||
|
||||
// 2. 读取本地文件并返回给网页
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:localPath]) {
|
||||
NSData *data = [NSData dataWithContentsOfFile:localPath];
|
||||
NSString *mimeType = [self mimeTypeForPath:localPath];
|
||||
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:url
|
||||
MIMEType:mimeType
|
||||
expectedContentLength:data.length
|
||||
textEncodingName:@"UTF-8"];
|
||||
// 发送响应和数据给网页
|
||||
[self.schemeTask didReceiveResponse:response];
|
||||
[self.schemeTask didReceiveData:data];
|
||||
[self.schemeTask didFinish];
|
||||
} else {
|
||||
// 资源不存在,返回 404 错误
|
||||
NSError *error = [NSError errorWithDomain:NSURLErrorDomain
|
||||
code:NSURLErrorFileDoesNotExist
|
||||
userInfo:@{NSLocalizedDescriptionKey: @"本地资源不存在"}];
|
||||
[self.schemeTask didFailWithError:error];
|
||||
}
|
||||
|
||||
// 调用完成回调(从任务列表中移除)
|
||||
if (completion) completion();
|
||||
}
|
||||
|
||||
- (void)stopLoading {
|
||||
// 停止加载时清理资源(如取消文件读取)
|
||||
self.schemeTask = nil;
|
||||
if (self.completion) self.completion();
|
||||
}
|
||||
|
||||
#pragma mark - 辅助方法:根据文件路径获取 MIME 类型
|
||||
- (NSString *)mimeTypeForPath:(NSString *)path {
|
||||
NSString *extension = [path pathExtension].lowercaseString;
|
||||
if ([extension isEqualToString:@"html"]) return @"text/html";
|
||||
if ([extension isEqualToString:@"js"]) return @"application/javascript";
|
||||
if ([extension isEqualToString:@"css"]) return @"text/css";
|
||||
if ([extension isEqualToString:@"png"]) return @"image/png";
|
||||
if ([extension isEqualToString:@"jpg"] || [extension isEqualToString:@"jpeg"]) return @"image/jpeg";
|
||||
return @"application/octet-stream";
|
||||
}
|
||||
|
||||
@end
|
||||
33
ShenQi/GDWebCustomURLSchemeProtocol.h
Normal file
33
ShenQi/GDWebCustomURLSchemeProtocol.h
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// GDWebCustomURLSchemeProtocol.h
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol GDWebCustomURLSchemeProtocol <NSObject>
|
||||
|
||||
/// 初始化方法,传入需要处理的请求任务
|
||||
/// @param task WKURLSchemeTask 对象(包含请求信息和回调方法)
|
||||
- (instancetype)initWithSchemeTask:(id<WKURLSchemeTask>)task;
|
||||
|
||||
/// 开始处理请求
|
||||
/// @param completion 处理完成后的回调(用于移除任务缓存)
|
||||
- (void)startLoading:(void(^)(void))completion;
|
||||
|
||||
/// 停止处理请求(如网页取消加载时调用)
|
||||
- (void)stopLoading;
|
||||
|
||||
/// 类方法:判断当前服务是否能处理该请求
|
||||
/// @param task 待处理的请求任务
|
||||
+ (BOOL)canService:(id<WKURLSchemeTask>)task;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
23
ShenQi/GDWebPageHookService.h
Normal file
23
ShenQi/GDWebPageHookService.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// GDWebPageHookService.h
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "GDWebCustomURLSchemeProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GDWebPageHookService : NSObject <GDWebCustomURLSchemeProtocol>
|
||||
|
||||
@property (nonatomic, strong) id<WKURLSchemeTask> schemeTask;
|
||||
@property (nonatomic, copy) void(^completion)(void);
|
||||
/// 用于网络请求的会话
|
||||
@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
80
ShenQi/GDWebPageHookService.m
Normal file
80
ShenQi/GDWebPageHookService.m
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// GDWebPageHookService.m
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import "GDWebPageHookService.h"
|
||||
|
||||
@implementation GDWebPageHookService
|
||||
|
||||
#pragma mark - 初始化
|
||||
- (instancetype)initWithSchemeTask:(id<WKURLSchemeTask>)task {
|
||||
if (self = [super init]) {
|
||||
_schemeTask = task;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - GDWebCustomURLSchemeProtocol
|
||||
+ (BOOL)canService:(id<WKURLSchemeTask>)task {
|
||||
// 处理需要钩子的请求(如包含 "/api/hook" 的接口)
|
||||
NSString *urlString = task.request.URL.absoluteString;
|
||||
return [urlString containsString:@"/api/hook"];
|
||||
}
|
||||
|
||||
- (void)startLoading:(void (^)(void))completion {
|
||||
self.completion = completion;
|
||||
NSURLRequest *request = self.schemeTask.request;
|
||||
|
||||
// 1. 发起原始网络请求
|
||||
self.dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
// 网络错误,直接返回给网页
|
||||
[self.schemeTask didFailWithError:error];
|
||||
if (completion) completion();
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 钩子逻辑:修改响应数据(示例:给 API 响应添加自定义字段)
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
NSMutableDictionary *headers = [httpResponse.allHeaderFields mutableCopy];
|
||||
// 允许网页接收修改后的数据(处理跨域)
|
||||
headers[@"Access-Control-Allow-Origin"] = @"*";
|
||||
|
||||
// 若为 JSON 响应,修改内容
|
||||
NSData *modifiedData = data;
|
||||
if ([httpResponse.MIMEType containsString:@"application/json"] && data) {
|
||||
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
|
||||
if (json) {
|
||||
json[@"_injected_by_native"] = @"true"; // 注入自定义字段
|
||||
modifiedData = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 构造修改后的响应并返回给网页
|
||||
NSHTTPURLResponse *modifiedResponse = [[NSHTTPURLResponse alloc] initWithURL:httpResponse.URL
|
||||
statusCode:httpResponse.statusCode
|
||||
HTTPVersion:@"HTTP/1.1"
|
||||
headerFields:headers];
|
||||
[self.schemeTask didReceiveResponse:modifiedResponse];
|
||||
[self.schemeTask didReceiveData:modifiedData];
|
||||
[self.schemeTask didFinish];
|
||||
|
||||
// 调用完成回调
|
||||
if (completion) completion();
|
||||
}];
|
||||
[self.dataTask resume];
|
||||
}
|
||||
|
||||
- (void)stopLoading {
|
||||
// 停止网络请求
|
||||
[self.dataTask cancel];
|
||||
self.dataTask = nil;
|
||||
self.schemeTask = nil;
|
||||
if (self.completion) self.completion();
|
||||
}
|
||||
|
||||
@end
|
||||
22
ShenQi/GDWebURLSchemeHandler.h
Normal file
22
ShenQi/GDWebURLSchemeHandler.h
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// GDWebURLSchemeHandler.h
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#import "GDWebCustomURLSchemeProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GDWebURLSchemeHandler : NSObject<WKURLSchemeHandler>
|
||||
|
||||
@property (nonatomic, strong) NSMutableDictionary *tasks;
|
||||
@property (nonatomic, strong) NSMutableDictionary *schemeStatusDic;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
51
ShenQi/GDWebURLSchemeHandler.m
Normal file
51
ShenQi/GDWebURLSchemeHandler.m
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// GDWebURLSchemeHandler.m
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import "GDWebURLSchemeHandler.h"
|
||||
#import "GDWebAssetStorageService.h"
|
||||
#import "GDWebPageHookService.h"
|
||||
#import "GDWebURLSessionService.h"
|
||||
|
||||
@implementation GDWebURLSchemeHandler
|
||||
|
||||
- (instancetype)init {
|
||||
|
||||
_tasks = [NSMutableDictionary dictionary];
|
||||
_schemeStatusDic = [NSMutableDictionary dictionary];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)webView: (WKWebView *)webView startURLSchemeTask: (id<WKURLSchemeTask>)urlSchemeTask {
|
||||
|
||||
id<GDWebCustomURLSchemeProtocol> service;
|
||||
if ([GDWebAssetStorageService canService:urlSchemeTask]) {
|
||||
service = [[GDWebAssetStorageService alloc] initWithSchemeTask:urlSchemeTask];
|
||||
}else if ([GDWebPageHookService canService:urlSchemeTask]) {
|
||||
service = [[GDWebPageHookService alloc] initWithSchemeTask:urlSchemeTask];
|
||||
}else {
|
||||
service = [[GDWebURLSessionService alloc] initWithSchemeTask:urlSchemeTask];
|
||||
GDWebURLSessionService *webService = (GDWebURLSessionService *)service;
|
||||
webService.stopMarkDic = self.schemeStatusDic;
|
||||
}
|
||||
[self.tasks setValue:service forKey:urlSchemeTask.description];
|
||||
[service startLoading:^{
|
||||
// GDStrongify(self);
|
||||
[self.tasks removeObjectForKey:urlSchemeTask.description];
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
- (void)webView: (WKWebView *)webView stopURLSchemeTask: (id<WKURLSchemeTask>)urlSchemeTask {
|
||||
[self.schemeStatusDic setObject:@1 forKey:urlSchemeTask.description];
|
||||
NSURL *URL = urlSchemeTask.request.URL;
|
||||
id<GDWebCustomURLSchemeProtocol> service = self.tasks[URL.absoluteString];
|
||||
[service stopLoading];
|
||||
[self.tasks removeObjectForKey:urlSchemeTask.description];
|
||||
}
|
||||
|
||||
@end
|
||||
28
ShenQi/GDWebURLSessionDelegate.h
Normal file
28
ShenQi/GDWebURLSessionDelegate.h
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// GDWebURLSessionDelegate.h
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GDWebURLSessionDelegate : NSObject <NSURLSessionDataDelegate>
|
||||
|
||||
@property (nonatomic, strong) id<WKURLSchemeTask> schemeTask;
|
||||
@property (nonatomic, copy) void(^completion)(void);
|
||||
@property (nonatomic, weak) NSMutableDictionary *stopMarkDic;
|
||||
@property (nonatomic, strong) NSURLResponse *cachedResponse; // 缓存响应头
|
||||
@property (nonatomic, strong) NSMutableData *cachedData; // 缓存响应体数据
|
||||
|
||||
/// 初始化:关联 schemeTask 和完成回调
|
||||
- (instancetype)initWithSchemeTask:(id<WKURLSchemeTask>)schemeTask
|
||||
completion:(void(^)(void))completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
323
ShenQi/GDWebURLSessionDelegate.m
Normal file
323
ShenQi/GDWebURLSessionDelegate.m
Normal file
@@ -0,0 +1,323 @@
|
||||
//
|
||||
// GDWebURLSessionDelegate.m
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import "GDWebURLSessionDelegate.h"
|
||||
#import "MacroDefine.h"
|
||||
|
||||
@implementation GDWebURLSessionDelegate
|
||||
|
||||
- (instancetype)initWithSchemeTask:(id<WKURLSchemeTask>)schemeTask
|
||||
completion:(void(^)(void))completion {
|
||||
if (self = [super init]) {
|
||||
_schemeTask = schemeTask;
|
||||
_completion = completion;
|
||||
_cachedData = [NSMutableData data]; // 初始化可变数据
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSessionDataDelegate
|
||||
// 1. 处理重定向(核心:解决重定向失效)
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
|
||||
NSURL *url = response.URL;
|
||||
if (url.pathExtension.length == 0 || [url.pathExtension isEqualToString:@"html"]) {
|
||||
//接收到 HTML 文档的重定向时,这里返回 nil, 那么在 dataTaskWithRequest 的回调里就能收到 code = 302 的response, 然后在 webview 里对 302 做特殊处理就行
|
||||
completionHandler(nil);
|
||||
} else {
|
||||
completionHandler(request);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 收到响应(传递给网页)
|
||||
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
|
||||
self.cachedResponse = response; // 保存响应头
|
||||
if (!self.stopMarkDic[_schemeTask.description]) {
|
||||
@try {
|
||||
[self.schemeTask didReceiveResponse:response];
|
||||
} @catch (NSException *exception) {
|
||||
}
|
||||
}
|
||||
completionHandler(NSURLSessionResponseAllow);
|
||||
}
|
||||
|
||||
// 3. 收到数据(传递给网页)
|
||||
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
|
||||
[self.cachedData appendData:data]; // 拼接分片数据
|
||||
if (!self.stopMarkDic[_schemeTask.description]) {
|
||||
@try {
|
||||
[self.schemeTask didReceiveData:data];
|
||||
} @catch (NSException *exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 请求完成(成功/失败)
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
|
||||
@try {
|
||||
if (self.stopMarkDic[_schemeTask.description]) {
|
||||
[self.stopMarkDic removeObjectForKey:_schemeTask.description];
|
||||
} else {
|
||||
if (error) {
|
||||
[_schemeTask didFailWithError:error];
|
||||
} else {
|
||||
[_schemeTask didFinish];
|
||||
[self handleSuccessResult:self.cachedResponse data:self.cachedData];
|
||||
}
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
}
|
||||
|
||||
// 触发完成回调,清理资源
|
||||
if (self.completion) self.completion();
|
||||
}
|
||||
|
||||
// 处理成功结果的工具方法
|
||||
- (void)handleSuccessResult:(NSURLResponse *)response data:(NSData *)data {
|
||||
NSURLRequest *request = self.schemeTask.request;
|
||||
|
||||
NSURL *url = request.URL;
|
||||
NSString *httpMethod = request.HTTPMethod ?: @"GET"; // 默认 GET 方法
|
||||
|
||||
// ===== 1. 提取基础请求信息 =====
|
||||
// NSLog(@"请求 URL:%@", url.absoluteString);
|
||||
// NSLog(@"请求方法:%@", httpMethod);
|
||||
// NSLog(@"请求头:%@", request.allHTTPHeaderFields);
|
||||
|
||||
// ===== 2. 提取 URL 中的查询参数(GET 参数)=====
|
||||
NSString *queryString = url.query;
|
||||
if (queryString.length > 0) {
|
||||
NSDictionary *queryParams = [self parseQueryString:queryString];
|
||||
// NSLog(@"GET 参数:%@", queryParams);
|
||||
}
|
||||
|
||||
NSDictionary *postParams = [NSDictionary dictionary];
|
||||
// ===== 3. 提取 POST 请求体参数 =====
|
||||
if ([httpMethod.uppercaseString isEqualToString:@"POST"] && request.HTTPBody) {
|
||||
// 3.1 解析表单格式(application/x-www-form-urlencoded)
|
||||
NSString *postBodyString = [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
|
||||
if (postBodyString) {
|
||||
// 判断 Content-Type 是否为表单格式
|
||||
NSString *contentType = request.allHTTPHeaderFields[@"Content-Type"];
|
||||
if ([contentType containsString:@"application/x-www-form-urlencoded"]) {
|
||||
postParams = [self parseQueryString:postBodyString];
|
||||
// NSLog(@"POST 表单参数:%@", postParams);
|
||||
}
|
||||
// 3.2 解析 JSON 格式(application/json)
|
||||
else if ([contentType containsString:@"application/json"]) {
|
||||
NSError *jsonError;
|
||||
id jsonObject = [NSJSONSerialization JSONObjectWithData:request.HTTPBody options:0 error:&jsonError];
|
||||
if (jsonObject && !jsonError) {
|
||||
// NSLog(@"POST JSON 参数:%@", jsonObject);
|
||||
} else {
|
||||
// NSLog(@"POST JSON 解析失败:%@,原始数据:%@", jsonError, postBodyString);
|
||||
}
|
||||
}
|
||||
// 3.3 其他格式(如 multipart/form-data 表单上传,这里简化处理)
|
||||
else {
|
||||
NSString *contentTypeStr = request.allHTTPHeaderFields[@"Content-Type"];
|
||||
NSString *boundaryStr = nil;
|
||||
// 1. 按 "boundary=" 分割字符串
|
||||
NSArray *components = [contentType componentsSeparatedByString:@"boundary="];
|
||||
if (components.count >= 2) {
|
||||
// 2. 取分割后的第二个元素(即 boundary 的值),并去除可能的空格
|
||||
boundaryStr = [components[1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
}
|
||||
|
||||
postParams = [self parseFormData:request.HTTPBody boundary:boundaryStr];
|
||||
// NSLog(@"POST 其他格式数据:%@", postBodyString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSDictionary *jsonDic = [NSDictionary dictionary];
|
||||
// 示例:解析 JSON 数据
|
||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
if (httpResponse.statusCode == 200) { // 状态码 200 表示请求成功
|
||||
NSError *jsonError;
|
||||
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
|
||||
if (json && !jsonError) {
|
||||
jsonDic = json;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self uploadDataWithRequest:postParams backDic:jsonDic url:url.absoluteString];
|
||||
}
|
||||
|
||||
- (void)uploadDataWithRequest:(NSDictionary *)parameter backDic:(NSDictionary *)backDic url:(NSString *)url {
|
||||
// /merchants/getPublicInfo accessToken获取有没有登录 merchantId用户ID module接口名
|
||||
// users/login mobile手机号
|
||||
|
||||
if (backDic == nil) {
|
||||
return;
|
||||
}
|
||||
// NSLog(@"-------%@:%@,%@",parameter,backDic,url);
|
||||
if (![backDic isKindOfClass:[NSDictionary class]]) {
|
||||
return;
|
||||
}
|
||||
id status = backDic[@"status"];
|
||||
BOOL isSuccess = NO;
|
||||
if ([status isKindOfClass:[NSString class]]) {
|
||||
if ([backDic[@"status"] isEqualToString:@"SUCCESS"]) {
|
||||
isSuccess = YES;
|
||||
}
|
||||
}else if ([status isKindOfClass:[NSNumber class]]) {
|
||||
isSuccess = [backDic[@"status"] boolValue];
|
||||
}
|
||||
|
||||
if (isSuccess) {
|
||||
BOOL isLoginUrl = NO;
|
||||
if ([url containsString:@"validateUserJs"]) {
|
||||
isLoginUrl = YES;
|
||||
}
|
||||
|
||||
NSString *moduleStr = parameter[@"module"];
|
||||
|
||||
if (!ISNULLSTR(moduleStr)) {
|
||||
if ([moduleStr containsString:@"users/login"]) {
|
||||
isLoginUrl = YES;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLoginUrl) {
|
||||
NSString *mobileStr = parameter[@"mobile"];
|
||||
if (ISNULLSTR(mobileStr)) {
|
||||
mobileStr = parameter[@"login_id"];
|
||||
}
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:updataLoginUser]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"phone":mobileStr,@"appId":NowUserId};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助方法:解析 "key1=value1&key2=value2" 格式的字符串为字典
|
||||
- (NSDictionary *)parseQueryString:(NSString *)queryString {
|
||||
if (!queryString || queryString.length == 0) {
|
||||
return @{};
|
||||
}
|
||||
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
NSArray *pairs = [queryString componentsSeparatedByString:@"&"];
|
||||
|
||||
for (NSString *pair in pairs) {
|
||||
// 分割 key 和 value(处理包含多个 = 的情况,如 key=value=123)
|
||||
NSRange equalRange = [pair rangeOfString:@"="];
|
||||
if (equalRange.location == NSNotFound) {
|
||||
// 没有 =,视为 key 无值
|
||||
NSString *key = [pair stringByRemovingPercentEncoding];
|
||||
params[key] = @"";
|
||||
continue;
|
||||
}
|
||||
|
||||
NSString *key = [pair substringToIndex:equalRange.location];
|
||||
NSString *value = [pair substringFromIndex:equalRange.location + 1];
|
||||
// 解码(处理 URL 编码的字符,如 %20 转为空格)
|
||||
key = [key stringByRemovingPercentEncoding];
|
||||
value = [value stringByRemovingPercentEncoding];
|
||||
|
||||
if (key) {
|
||||
params[key] = value ?: @"";
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, NSString *> *)parseFormData:(NSData *)data boundary:(NSString *)boundary {
|
||||
// 校验参数
|
||||
if (!data || data.length == 0 || !boundary || boundary.length == 0) {
|
||||
NSLog(@"无效的表单数据或边界符");
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 1. 将数据转为字符串(默认 UTF-8 编码,若有特殊编码需调整)
|
||||
NSString *content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
if (!content) {
|
||||
NSLog(@"表单数据编码转换失败(非 UTF-8)");
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 2. 生成完整的边界符(multipart 格式中边界符前需加 "--")
|
||||
NSString *fullBoundary = [NSString stringWithFormat:@"--%@", boundary];
|
||||
// 按边界符分割内容,过滤空字符串和结束符(--boundary--)
|
||||
NSArray *parts = [content componentsSeparatedByString:fullBoundary];
|
||||
NSMutableArray *validParts = [NSMutableArray array];
|
||||
for (NSString *part in parts) {
|
||||
// 去除前后空白和换行符
|
||||
NSString *trimmedPart = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
if (trimmedPart.length > 0 && ![trimmedPart isEqualToString:@"--"]) { // 排除结束符
|
||||
[validParts addObject:trimmedPart];
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 解析每个字段块,提取 name 和值
|
||||
NSMutableDictionary *resultDict = [NSMutableDictionary dictionary];
|
||||
for (NSString *part in validParts) {
|
||||
// 字段块格式示例:
|
||||
// Content-Disposition: form-data; name="login_id"\r\n
|
||||
// \r\n
|
||||
// 11
|
||||
|
||||
// 分割字段描述和值(以 "\r\n\r\n" 为分隔点)
|
||||
NSArray *partComponents = [part componentsSeparatedByString:@"\r\n\r\n"];
|
||||
if (partComponents.count < 2) {
|
||||
continue; // 格式异常,跳过
|
||||
}
|
||||
|
||||
// 3.1 提取 name(从 Content-Disposition 中)
|
||||
NSString *dispositionLine = partComponents[0]; // 如 "Content-Disposition: form-data; name="login_id""
|
||||
NSString *name = [self extractNameFromDisposition:dispositionLine];
|
||||
if (!name) {
|
||||
continue; // 未找到 name,跳过
|
||||
}
|
||||
|
||||
// 3.2 提取字段值(去除可能的换行符)
|
||||
NSString *value = partComponents[1];
|
||||
value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
// 3.3 存入字典
|
||||
resultDict[name] = value;
|
||||
}
|
||||
|
||||
return resultDict.count > 0 ? [resultDict copy] : nil;
|
||||
}
|
||||
|
||||
/// 从 Content-Disposition 中提取 name 的值
|
||||
/// @param disposition 如 "Content-Disposition: form-data; name="login_id""
|
||||
/// @return name 的值(如 "login_id")
|
||||
- (NSString *)extractNameFromDisposition:(NSString *)disposition {
|
||||
if (!disposition) return nil;
|
||||
|
||||
// 正则匹配 name="xxx" 中的 xxx
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"name=\"([^\"]+)\""
|
||||
options:0
|
||||
error:nil];
|
||||
NSTextCheckingResult *match = [regex firstMatchInString:disposition
|
||||
options:0
|
||||
range:NSMakeRange(0, disposition.length)];
|
||||
if (match && match.numberOfRanges > 1) {
|
||||
NSRange nameRange = [match rangeAtIndex:1];
|
||||
return [disposition substringWithRange:nameRange];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
23
ShenQi/GDWebURLSessionService.h
Normal file
23
ShenQi/GDWebURLSessionService.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// GDWebURLSessionService.h
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "GDWebCustomURLSchemeProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GDWebURLSessionService : NSObject <GDWebCustomURLSchemeProtocol>
|
||||
|
||||
@property (nonatomic, strong) id<WKURLSchemeTask> schemeTask;
|
||||
@property (nonatomic, copy) void(^completion)(void);
|
||||
@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
|
||||
@property (nonatomic, weak) NSMutableDictionary *stopMarkDic;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
69
ShenQi/GDWebURLSessionService.m
Normal file
69
ShenQi/GDWebURLSessionService.m
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// GDWebURLSessionService.m
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import "GDWebURLSessionService.h"
|
||||
#import "GDWebURLSessionDelegate.h"
|
||||
|
||||
@implementation GDWebURLSessionService
|
||||
|
||||
#pragma mark - 初始化
|
||||
- (instancetype)initWithSchemeTask:(id<WKURLSchemeTask>)task {
|
||||
if (self = [super init]) {
|
||||
_schemeTask = task;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - GDWebCustomURLSchemeProtocol
|
||||
+ (BOOL)canService:(id<WKURLSchemeTask>)task {
|
||||
// 作为默认服务,理论上不需要实现(因为其他服务不处理时才会走到这里)
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)startLoading:(void (^)(void))completion {
|
||||
self.completion = completion;
|
||||
NSURLRequest *request = self.schemeTask.request;
|
||||
|
||||
// 发起常规网络请求,直接将结果返回给网页
|
||||
// self.dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
// if (error) {
|
||||
// [self.schemeTask didFailWithError:error];
|
||||
// } else {
|
||||
// [self.schemeTask didReceiveResponse:response];
|
||||
// if (data) [self.schemeTask didReceiveData:data];
|
||||
// [self.schemeTask didFinish];
|
||||
// }
|
||||
// if (completion) completion();
|
||||
// }];
|
||||
// [self.dataTask resume];
|
||||
|
||||
// =====新增:用自定义 NSURLSession + 代理处理重定)=====
|
||||
// 配置会话(默认配置即可,如需自定义超时、Cookie 可在此调整)
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
|
||||
// 创建自定义代理(关联 schemeTask,用于处理重定向和回调)
|
||||
GDWebURLSessionDelegate *sessionDelegate = [[GDWebURLSessionDelegate alloc] initWithSchemeTask:self.schemeTask completion:completion];
|
||||
sessionDelegate.stopMarkDic = self.stopMarkDic; // 传递 dic 引用
|
||||
|
||||
// 创建会话(绑定代理,delegateQueue 为 nil 表示用默认队列)
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:sessionDelegate delegateQueue:nil];
|
||||
|
||||
// 发起请求(替换原 sharedSession 的 dataTask)
|
||||
self.dataTask = [session dataTaskWithRequest:request];
|
||||
[self.dataTask resume];
|
||||
|
||||
}
|
||||
|
||||
- (void)stopLoading {
|
||||
[self.dataTask cancel];
|
||||
self.dataTask = nil;
|
||||
self.schemeTask = nil;
|
||||
if (self.completion) self.completion();
|
||||
}
|
||||
|
||||
@end
|
||||
19
ShenQi/GameWebViewController.h
Normal file
19
ShenQi/GameWebViewController.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// GameWebViewController.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Qwerdf on 2025/11/11.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GameWebViewController : UIViewController
|
||||
|
||||
@property (nonatomic, strong) WKWebViewConfiguration *gameConfiguration;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
38
ShenQi/GameWebViewController.m
Normal file
38
ShenQi/GameWebViewController.m
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// GameWebViewController.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Qwerdf on 2025/11/11.
|
||||
//
|
||||
|
||||
#import "GameWebViewController.h"
|
||||
|
||||
@interface GameWebViewController ()<WKUIDelegate,WKNavigationDelegate>
|
||||
|
||||
@property (strong, nonatomic) WKWebView *webView;
|
||||
@property (nonatomic,strong) WKUserContentController *wkUController;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GameWebViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
|
||||
wkWebConfig.preferences.javaScriptCanOpenWindowsAutomatically = YES;
|
||||
|
||||
|
||||
_wkUController = [[WKUserContentController alloc] init];
|
||||
|
||||
wkWebConfig.userContentController = _wkUController;
|
||||
|
||||
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.lastObject.windowScene.statusBarManager;
|
||||
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, statusBarManager.statusBarFrame.size.height, self.view.bounds.size.width, self.view.bounds.size.height-self.view.safeAreaInsets.bottom-statusBarManager.statusBarFrame.size.height) configuration:self.gameConfiguration];
|
||||
_webView.UIDelegate = self;
|
||||
_webView.navigationDelegate = self;
|
||||
[self.view addSubview:_webView];
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -3,17 +3,17 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>API_KEY</key>
|
||||
<string>AIzaSyBzxoVTlQF1Q7XEFqWAiS9dIFEZkcFk-o0</string>
|
||||
<string>AIzaSyCRrTj7LNAjqb7mT8VAiF2SzvsSUwKjVB4</string>
|
||||
<key>GCM_SENDER_ID</key>
|
||||
<string>989163327252</string>
|
||||
<string>875434561984</string>
|
||||
<key>PLIST_VERSION</key>
|
||||
<string>1</string>
|
||||
<key>BUNDLE_ID</key>
|
||||
<string>noti.OKEGO</string>
|
||||
<string>noti.NO1VA9SG4</string>
|
||||
<key>PROJECT_ID</key>
|
||||
<string>okego-a50f6</string>
|
||||
<string>nosgs-409e1</string>
|
||||
<key>STORAGE_BUCKET</key>
|
||||
<string>okego-a50f6.firebasestorage.app</string>
|
||||
<string>nosgs-409e1.firebasestorage.app</string>
|
||||
<key>IS_ADS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_ANALYTICS_ENABLED</key>
|
||||
@@ -25,6 +25,6 @@
|
||||
<key>IS_SIGNIN_ENABLED</key>
|
||||
<true></true>
|
||||
<key>GOOGLE_APP_ID</key>
|
||||
<string>1:989163327252:ios:f5e39cecd23cd49a567c01</string>
|
||||
<string>1:875434561984:ios:7a5199d245be0be58d3825</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -34,14 +34,20 @@
|
||||
[self setupGameURLData];
|
||||
}
|
||||
|
||||
-(void)intoMainWebView
|
||||
{
|
||||
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
|
||||
MainOldViewController *webViewController = [sb instantiateViewControllerWithIdentifier:@"MainOldViewController"];
|
||||
webViewController.mainURLString = self.mainURLString;
|
||||
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
appDelegate.mainURLString = self.mainURLString;
|
||||
appDelegate.window.rootViewController = webViewController;
|
||||
-(void)intoMainWebView:(NSString *)backupDomains {
|
||||
//主域名不行用备用域名
|
||||
NSArray *textArr = [backupDomains componentsSeparatedByString:@","];
|
||||
[self getAccessibleDomain:self.mainURLString backupDomains:textArr completion:^(NSString *accessibleDomain) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.mainURLString = accessibleDomain;
|
||||
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
|
||||
MainOldViewController *webViewController = [sb instantiateViewControllerWithIdentifier:@"MainOldViewController"];
|
||||
webViewController.mainURLString = self.mainURLString;
|
||||
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
appDelegate.mainURLString = self.mainURLString;
|
||||
appDelegate.window.rootViewController = webViewController;
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)setupGameURLData
|
||||
@@ -81,8 +87,9 @@
|
||||
|
||||
self.mainURLString = [datadic objectForKey:@"url"];
|
||||
self.mainURLString = [self.mainURLString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
NSString *backupDomains = [datadic objectForKey:@"backupDomains"];
|
||||
if (!ISNULLSTR(self.mainURLString)) {
|
||||
[self intoMainWebView];
|
||||
[self intoMainWebView:backupDomains];
|
||||
}
|
||||
}else{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@@ -131,4 +138,84 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)checkDomainAccessibility:(NSString *)domain completion:(void(^)(BOOL isAccessible))completion {
|
||||
NSString *urlString = domain;
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
|
||||
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
BOOL isAccessible = NO;
|
||||
|
||||
if (error) {
|
||||
// 请求失败
|
||||
NSLog(@"Domain %@ is not reachable: %@", domain, error.localizedDescription);
|
||||
} else {
|
||||
// 请求成功,检查返回的状态码
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
if (httpResponse.statusCode == 200) {
|
||||
isAccessible = YES;
|
||||
} else {
|
||||
NSLog(@"Domain %@ returned status code: %ld", domain, (long)httpResponse.statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
// 回调,返回访问状态
|
||||
if (completion) {
|
||||
completion(isAccessible);
|
||||
}
|
||||
}];
|
||||
[task resume];
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - 主域名不行用备用域名
|
||||
- (void)getAccessibleDomain:(NSString *)primaryDomain backupDomains:(NSArray<NSString *> *)backupDomains completion:(void(^)(NSString *accessibleDomain))completion {
|
||||
if (ISNULLARRAY(backupDomains)) {
|
||||
if (completion) {
|
||||
completion(primaryDomain);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 首先检查主域名
|
||||
[self checkDomainAccessibility:primaryDomain completion:^(BOOL isAccessible) {
|
||||
if (isAccessible) {
|
||||
// 如果主域名可访问,直接返回主域名
|
||||
if (completion) {
|
||||
completion(primaryDomain);
|
||||
}
|
||||
} else {
|
||||
// 主域名不可访问,遍历备用域名
|
||||
__block NSString *reachableDomain = nil;
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
|
||||
// 遍历备用域名进行检查
|
||||
for (NSString *backupDomain in backupDomains) {
|
||||
dispatch_group_enter(group);
|
||||
|
||||
[self checkDomainAccessibility:backupDomain completion:^(BOOL isAccessible) {
|
||||
if (isAccessible && !reachableDomain) {
|
||||
reachableDomain = backupDomain;
|
||||
}
|
||||
dispatch_group_leave(group);
|
||||
}];
|
||||
}
|
||||
|
||||
// 等待所有备用域名的检查完成
|
||||
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
||||
// 如果找到了可访问的备用域名,返回它
|
||||
if (reachableDomain) {
|
||||
if (completion) {
|
||||
completion(reachableDomain);
|
||||
}
|
||||
} else {
|
||||
// 如果所有域名都不可访问,返回主域名
|
||||
if (completion) {
|
||||
completion(primaryDomain);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
#define PushRecordsURL [NSString stringWithFormat:@"%@/api/push/pushRecords",BASEURL] // 推送中心
|
||||
|
||||
#define updataLoginUser [NSString stringWithFormat:@"%@/app/loginUser",BASEURL]
|
||||
|
||||
|
||||
#define TESTUserID @"2"
|
||||
|
||||
@@ -163,7 +165,7 @@
|
||||
#define AUKING777UserID @"186"
|
||||
#define PXP99auUserID @"187"
|
||||
#define OKEGOUserID @"188"
|
||||
|
||||
#define KONGBO96UserID @"189"
|
||||
|
||||
|
||||
|
||||
@@ -180,6 +182,7 @@
|
||||
#define Scr66myUserID @"21"
|
||||
#define WE88UserID @"22"
|
||||
#define Gey99UserID @"23"
|
||||
#define HariharispinUserID @"25"
|
||||
#define DatojudiUserID @"26"
|
||||
#define KakislotUserID @"27"
|
||||
#define Shell96UserID @"28"
|
||||
@@ -225,7 +228,7 @@
|
||||
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
|
||||
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
|
||||
|
||||
#define NowUserId OKEGOUserID
|
||||
#define NowUserId @"220"
|
||||
|
||||
#endif /* MacroDefine_h */
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#import "MainOldViewController.h"
|
||||
|
||||
|
||||
#import <Contacts/Contacts.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#import <SVProgressHUD.h>
|
||||
@@ -22,6 +23,8 @@
|
||||
#import "LinkConfig.h"
|
||||
|
||||
#import "NotiCenterViewController.h"
|
||||
#import "GDWebURLSchemeHandler.h"
|
||||
#import "GameWebViewController.h"
|
||||
|
||||
@interface MainOldViewController () <WKUIDelegate,WKNavigationDelegate,DSWebMenuDelegate>
|
||||
|
||||
@@ -32,6 +35,7 @@
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *dragHeightConstarint;
|
||||
@property (weak, nonatomic) IBOutlet DSWebMenuCollectionView *webMenuCollectionView;
|
||||
@property (nonatomic, strong) UIView *subBgView;
|
||||
//@property (nonatomic, copy) NSString *redirectUrl;
|
||||
|
||||
@end
|
||||
|
||||
@@ -52,6 +56,7 @@
|
||||
|
||||
WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
|
||||
wkWebConfig.preferences.javaScriptCanOpenWindowsAutomatically = YES;
|
||||
// [wkWebConfig setURLSchemeHandler:[GDWebURLSchemeHandler new] forURLScheme:@"https"];
|
||||
|
||||
_wkUController = [[WKUserContentController alloc] init];
|
||||
|
||||
@@ -63,18 +68,29 @@
|
||||
_webView.navigationDelegate = self;
|
||||
[self.view addSubview:_webView];
|
||||
|
||||
self.subBgView = [[UIView alloc] initWithFrame:self.view.frame];
|
||||
self.subBgView = [[UIView alloc] init];
|
||||
self.subBgView.backgroundColor = [UIColor whiteColor];
|
||||
self.subBgView.hidden = YES;
|
||||
[self.view addSubview:self.subBgView];
|
||||
self.subBgView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
// 上下左右边距均为0
|
||||
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:self.subBgView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
|
||||
|
||||
NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:self.subBgView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
|
||||
|
||||
NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:self.subBgView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
|
||||
|
||||
NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:self.subBgView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
|
||||
|
||||
[self.view addConstraints:@[top, left, right, bottom]];
|
||||
|
||||
NSMutableArray *menuArray = @[].mutableCopy;
|
||||
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
NSInteger height = 0 ;
|
||||
if (self.isPresent != YES) {
|
||||
// if (self.isPresent != YES) {
|
||||
// 回到菜单按钮
|
||||
height = 60;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuHomeType]];
|
||||
// height = 60;
|
||||
// [menuArray addObject:[NSNumber numberWithInteger:DSWebMenuHomeType]];
|
||||
// 回到主页
|
||||
height = height + 60;
|
||||
LinkConfig *config = [[LinkConfig alloc] init];
|
||||
@@ -84,47 +100,39 @@
|
||||
config.linkUrl = appDelegate.mainURLString;
|
||||
[menuArray addObject:config];
|
||||
|
||||
// height = height + 70;
|
||||
//
|
||||
// LinkConfig *config2 = [[LinkConfig alloc] init];
|
||||
// config2.isGoBack = NO;
|
||||
// config2.icon = @"missav2";
|
||||
// config2.name = @"missav2";
|
||||
// config2.linkUrl = @"https://zh.xhamster.com";
|
||||
// [menuArray addObject:config2];
|
||||
// 菜单
|
||||
if (!ISNULLSTR(appDelegate.data.linkConfig)) {
|
||||
NSError *jsonError;
|
||||
id linkConfigResponse = [NSJSONSerialization JSONObjectWithData:[appDelegate.data.linkConfig dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&jsonError];
|
||||
if (jsonError==nil && [linkConfigResponse isKindOfClass:[NSArray class]]) {
|
||||
NSArray *linkConfigArray = linkConfigResponse;
|
||||
height = height + linkConfigArray.count*70;
|
||||
for (NSDictionary *dic in linkConfigArray) {
|
||||
LinkConfig *linkModel = [LinkConfig modelWithDictionary:dic];
|
||||
[menuArray addObject:linkModel];
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (!ISNULLSTR(appDelegate.data.linkConfig)) {
|
||||
// NSError *jsonError;
|
||||
// id linkConfigResponse = [NSJSONSerialization JSONObjectWithData:[appDelegate.data.linkConfig dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&jsonError];
|
||||
// if (jsonError==nil && [linkConfigResponse isKindOfClass:[NSArray class]]) {
|
||||
// NSArray *linkConfigArray = linkConfigResponse;
|
||||
// height = height + linkConfigArray.count*70;
|
||||
// for (NSDictionary *dic in linkConfigArray) {
|
||||
// LinkConfig *linkModel = [LinkConfig modelWithDictionary:dic];
|
||||
// [menuArray addObject:linkModel];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// 客服平台
|
||||
if (!ISNULLSTR(appDelegate.data.fbUrl)) {
|
||||
height = height + 70;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuFacebookType]];
|
||||
}
|
||||
if (!ISNULLSTR(appDelegate.data.tgUrl)) {
|
||||
height = height + 70;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuTelegramType]];
|
||||
}
|
||||
if (!ISNULLSTR(appDelegate.data.wsUrl)) {
|
||||
height = height + 70;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuWhatsAppType]];
|
||||
}
|
||||
// if (!ISNULLSTR(appDelegate.data.fbUrl)) {
|
||||
// height = height + 70;
|
||||
// [menuArray addObject:[NSNumber numberWithInteger:DSWebMenuFacebookType]];
|
||||
// }
|
||||
// if (!ISNULLSTR(appDelegate.data.tgUrl)) {
|
||||
// height = height + 70;
|
||||
// [menuArray addObject:[NSNumber numberWithInteger:DSWebMenuTelegramType]];
|
||||
// }
|
||||
// if (!ISNULLSTR(appDelegate.data.wsUrl)) {
|
||||
// height = height + 70;
|
||||
// [menuArray addObject:[NSNumber numberWithInteger:DSWebMenuWhatsAppType]];
|
||||
// }
|
||||
// 刷新按钮
|
||||
height = height + 70;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuRefreshType]];
|
||||
// height = height + 70;
|
||||
// [menuArray addObject:[NSNumber numberWithInteger:DSWebMenuRefreshType]];
|
||||
// 推送中心按钮
|
||||
height = height + 70;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuNotiType]];
|
||||
}
|
||||
// }
|
||||
|
||||
self.webMenuCollectionView.shareArray = menuArray;
|
||||
self.webMenuCollectionView.webMenuDelegate = self;
|
||||
@@ -143,8 +151,8 @@
|
||||
if (self.isPresent == YES) {
|
||||
[self dismissViewControllerAnimated:YES completion:^{}];
|
||||
}else{
|
||||
self.webDragView.hidden = YES;
|
||||
self.webMenuCollectionView.hidden = NO;
|
||||
// self.webDragView.hidden = YES;
|
||||
// self.webMenuCollectionView.hidden = NO;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -229,8 +237,8 @@
|
||||
[self presentViewController:notiCenterViewController animated:NO completion:nil];
|
||||
}
|
||||
}
|
||||
self.webDragView.hidden = NO;
|
||||
self.webMenuCollectionView.hidden = YES;
|
||||
// self.webDragView.hidden = NO;
|
||||
// self.webMenuCollectionView.hidden = YES;
|
||||
}
|
||||
|
||||
-(void)intoMainWebView
|
||||
@@ -261,6 +269,17 @@
|
||||
newWebView.UIDelegate = self;
|
||||
newWebView.navigationDelegate = self;
|
||||
[self.subBgView addSubview:newWebView];
|
||||
newWebView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
// 上下左右边距均为0
|
||||
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:newWebView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.subBgView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
|
||||
|
||||
NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:newWebView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.subBgView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
|
||||
|
||||
NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:newWebView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.subBgView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
|
||||
|
||||
NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:newWebView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.subBgView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
|
||||
|
||||
[self.subBgView addConstraints:@[top, left, right, bottom]];
|
||||
|
||||
return newWebView;
|
||||
}else if (navigationAction.request.URL) {
|
||||
@@ -272,7 +291,10 @@
|
||||
view.isPresent = YES;
|
||||
view.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
[self presentViewController:view animated:YES completion:^{}];
|
||||
[view.view bringSubviewToFront:self.webMenuCollectionView];
|
||||
}
|
||||
|
||||
[self.view bringSubviewToFront:self.webMenuCollectionView];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
17
ShenQi/WKWebView+GDWebURLSchemeHandler.h
Normal file
17
ShenQi/WKWebView+GDWebURLSchemeHandler.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// WKWebView+GDWebURLSchemeHandler.h
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface WKWebView (GDWebURLSchemeHandler)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
32
ShenQi/WKWebView+GDWebURLSchemeHandler.m
Normal file
32
ShenQi/WKWebView+GDWebURLSchemeHandler.m
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// WKWebView+GDWebURLSchemeHandler.m
|
||||
// DESThreeTest
|
||||
//
|
||||
// Created by Qwerdf on 2025/10/24.
|
||||
// Copyright © 2025 zhang alan. All rights reserved.
|
||||
//
|
||||
|
||||
#import "WKWebView+GDWebURLSchemeHandler.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation WKWebView (GDWebURLSchemeHandler)
|
||||
|
||||
+ (void)load {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
Method originalMethod = class_getClassMethod(self, @selector(handlesURLScheme:));
|
||||
Method swizzledMethod = class_getClassMethod(self, @selector(gd_handlesURLScheme:));
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
});
|
||||
}
|
||||
|
||||
+ (BOOL)gd_handlesURLScheme:(NSString *)urlScheme {
|
||||
if ([urlScheme isEqualToString:@"https"]) {
|
||||
return NO;
|
||||
} else {
|
||||
return [self handlesURLScheme:urlScheme];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user