├── .DS_Store
├── Demo
├── .DS_Store
├── WechatIMG1822.png
└── SSWKURLDemo
│ ├── .DS_Store
│ ├── SSWKURLDemo
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ViewController.h
│ ├── AppDelegate.h
│ ├── SceneDelegate.h
│ ├── main.m
│ ├── AppDelegate.m
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── SceneDelegate.m
│ └── ViewController.m
│ └── SSWKURLDemo.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── sgcy.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ ├── xcuserdata
│ └── sgcy.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── project.pbxproj
├── SSWKURL
├── SSUtils.h
├── SSCache.h
├── SSResourceLoader.h
├── SSWKURL.h
├── SSUtils.m
├── SSResourceLoader.m
├── SSCache.m
└── SSWKURL.m
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lilidan/SSWKURL/HEAD/.DS_Store
--------------------------------------------------------------------------------
/Demo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lilidan/SSWKURL/HEAD/Demo/.DS_Store
--------------------------------------------------------------------------------
/Demo/WechatIMG1822.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lilidan/SSWKURL/HEAD/Demo/WechatIMG1822.png
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lilidan/SSWKURL/HEAD/Demo/SSWKURLDemo/.DS_Store
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo.xcodeproj/xcuserdata/sgcy.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo.xcodeproj/project.xcworkspace/xcuserdata/sgcy.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lilidan/SSWKURL/HEAD/Demo/SSWKURLDemo/SSWKURLDemo.xcodeproj/project.xcworkspace/xcuserdata/sgcy.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2020/5/11.
6 | // Copyright © 2020 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2020/5/11.
6 | // Copyright © 2020 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/SceneDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.h
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2020/5/11.
6 | // Copyright © 2020 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SceneDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow * window;
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/SSWKURL/SSUtils.h:
--------------------------------------------------------------------------------
1 | //
2 | // SSUtils.h
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2021/1/21.
6 | // Copyright © 2021 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface SSUtils : NSObject
14 |
15 | + (NSString *)requestIdForRequest:(NSURLRequest *)request;
16 |
17 | @end
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo.xcodeproj/xcuserdata/sgcy.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SSWKURLDemo.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2020/5/11.
6 | // Copyright © 2020 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | NSString * appDelegateClassName;
14 | @autoreleasepool {
15 | // Setup code that might create autoreleased objects goes here.
16 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
17 | }
18 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
19 | }
20 |
--------------------------------------------------------------------------------
/SSWKURL/SSCache.h:
--------------------------------------------------------------------------------
1 | //
2 | // SSCache.h
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2021/1/20.
6 | // Copyright © 2021 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface SSCache : NSObject
14 |
15 | + (instancetype)sharedCache;
16 |
17 | - (NSData *)dataForRequestId:(NSString *)requestId;
18 | - (NSDictionary *)responseHeadersWithRequestID:(NSString *)requestId;
19 |
20 | - (void)saveData:(NSData *)data forRequestId:(NSString *)requestId;
21 | - (void)saveResponseHeaders:(NSDictionary *)responseHeaders forRequestId:(NSString *)requestId;
22 | - (void)finishRequestForRequestId:(NSString *)requestId;
23 |
24 |
25 | @end
26 |
27 | NS_ASSUME_NONNULL_END
28 |
--------------------------------------------------------------------------------
/SSWKURL/SSResourceLoader.h:
--------------------------------------------------------------------------------
1 | //
2 | // SSResourceLoader.h
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2021/1/20.
6 | // Copyright © 2021 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface SSReourceItem : NSObject
14 |
15 | @property (nonatomic,strong) NSURLResponse *response;
16 | @property (nonatomic,strong) NSData *data;
17 | @property (nonatomic,strong) NSError *error;
18 |
19 | @end
20 |
21 |
22 | @interface SSResourceLoader : NSObject
23 |
24 | + (instancetype)sharedLoader;
25 |
26 | - (SSReourceItem *)loadResource:(NSURLRequest *)request;
27 |
28 | - (void)preloadResourceWithRequest:(NSURLRequest *)request;
29 |
30 | @end
31 |
32 | NS_ASSUME_NONNULL_END
33 |
--------------------------------------------------------------------------------
/SSWKURL/SSWKURL.h:
--------------------------------------------------------------------------------
1 | //
2 | // SSWKURL.h
3 | // SSWKURL
4 | //
5 | // Created by sgcy on 2020/4/21.
6 | // Copyright © 2020 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 |
13 | @interface SSWKURLProtocol:NSObject
14 |
15 | @property (nonatomic,readonly,copy) NSURLRequest *request;
16 |
17 | + (BOOL)canInitWithRequest:(NSURLRequest *)request;
18 | + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;
19 | - (void)startLoading:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;
20 | - (void)stopLoading;
21 |
22 | @end
23 |
24 |
25 | @interface WKWebViewConfiguration(ssRegisterURLProtocol)
26 |
27 | - (void)ssRegisterURLProtocol:(Class)protocolClass;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # SSWKURL
3 |
4 | Intercept and cache requests of WKWebView.
5 |
6 | 介绍[iOS完美请求拦截](https://www.jianshu.com/p/7b28cbd8f92a)
7 | [WKWebView缓存+请求拦截](https://www.jianshu.com/p/44f4fa1d3d12)
8 |
9 | 网易团队采用了更完整细致(原理相同)的解决方案,建议采用他们的:[WKWebView 请求拦截探索与实践](https://juejin.cn/post/6922625242796032007)
10 |
11 | ## Features
12 |
13 | - Intercept All Requests of WKWebView.
14 | - Cache requests.
15 |
16 |
17 |
18 |
19 | ## Installation
20 |
21 | Drag the `SSWKURL.h` and `SSWKURL.m` files into your project.
22 |
23 |
24 | ## Usage
25 |
26 | Subclass `SSWKURLProtocol` like `NSURLProtol`.
27 |
28 | Implement your own `-startLoading:` and `-stopLoading`.
29 |
30 | Then call `[yourWKURLConfiguration ssRegisterURLProtocol:[YourSSWKURLProtocol class]];`
31 |
32 | Then You could moniter requests or load cache for requests.
33 |
34 | ## Compare to VasSonic
35 |
36 | - support WKWebview
37 | - iOS SDK > 12
38 |
39 |
40 | ## Blog
41 |
42 | [WKWebView完美(?)网络请求拦截](https://www.jianshu.com/p/7b28cbd8f92a)
43 | [WKWebView缓存+请求拦截](https://www.jianshu.com/p/44f4fa1d3d12)
44 | 网易团队采用了更完整细致(原理相同)的解决方案,建议采用他们的:[WKWebView 请求拦截探索与实践](https://juejin.cn/post/6922625242796032007)
45 |
46 |
--------------------------------------------------------------------------------
/SSWKURL/SSUtils.m:
--------------------------------------------------------------------------------
1 | //
2 | // SSUtils.m
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2021/1/21.
6 | // Copyright © 2021 sgcy. All rights reserved.
7 | //
8 |
9 | #import "SSUtils.h"
10 | #import
11 |
12 | @implementation SSUtils
13 |
14 | + (NSString *)requestIdForRequest:(NSURLRequest *)request
15 | {
16 | NSString *url = request.URL.absoluteString;
17 | NSDictionary *headers = request.allHTTPHeaderFields;
18 | if (headers) {
19 | if ([NSJSONSerialization isValidJSONObject:headers]) {
20 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:headers options:1 error:nil];
21 | if (jsonData) {
22 | NSString *str = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
23 | // url = [url stringByAppendingString:str];
24 | }
25 | }
26 | }
27 | if (request.HTTPBody) {
28 | //POST BODY?
29 | }
30 | return [self md5:url];
31 | }
32 |
33 | + (NSString *)md5:(NSString *)string {
34 | const char *cStr = [string UTF8String];
35 | unsigned char digest[CC_MD5_DIGEST_LENGTH];
36 | CC_MD5(cStr, (CC_LONG)strlen(cStr), digest);
37 | NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
38 | for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
39 | [result appendFormat:@"%02X", digest[i]];
40 | }
41 | return result;
42 | }
43 |
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2020/5/11.
6 | // Copyright © 2020 sgcy. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 |
24 | #pragma mark - UISceneSession lifecycle
25 |
26 |
27 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
28 | // Called when a new scene session is being created.
29 | // Use this method to select a configuration to create the new scene with.
30 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
31 | }
32 |
33 |
34 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions {
35 | // Called when the user discards a scene session.
36 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
37 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
38 | }
39 |
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SSWKURL/SSResourceLoader.m:
--------------------------------------------------------------------------------
1 | //
2 | // SSResourceLoader.m
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2021/1/20.
6 | // Copyright © 2021 sgcy. All rights reserved.
7 | //
8 |
9 | #import "SSResourceLoader.h"
10 | #import "SSCache.h"
11 | #import "SSUtils.h"
12 |
13 | @implementation SSReourceItem
14 |
15 | @end
16 |
17 |
18 | @interface SSResourceLoader()
19 |
20 | @property (nonatomic,strong) NSMutableData *data;
21 | @property (nonatomic,strong) NSURLResponse *response;
22 |
23 | @end
24 |
25 | @implementation SSResourceLoader
26 |
27 | + (instancetype)sharedLoader
28 | {
29 | static SSResourceLoader *defaultLoader = nil;
30 | static dispatch_once_t onceToken;
31 | dispatch_once(&onceToken, ^{
32 | defaultLoader = [[self alloc]init];
33 | });
34 | return defaultLoader;
35 | }
36 |
37 | - (SSReourceItem *)loadResource:(NSURLRequest *)request
38 | {
39 | //load from cache
40 | NSString *requestId = [SSUtils requestIdForRequest:request];
41 | NSDictionary *responseHeaders = [[SSCache sharedCache] responseHeadersWithRequestID:requestId];
42 | if (responseHeaders) {
43 | SSReourceItem *item = [[SSReourceItem alloc] init];
44 | NSHTTPURLResponse *resp = [[NSHTTPURLResponse alloc]initWithURL:request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:responseHeaders];
45 | item.response = resp;
46 | NSData *data = [[SSCache sharedCache] dataForRequestId:requestId];
47 | if (data) {
48 | item.data = data;
49 | }
50 | return item;
51 | }else{
52 | return nil;
53 | }
54 | }
55 |
56 | - (void)preloadResourceWithRequest:(NSURLRequest *)request
57 | {
58 | //preload from cache
59 | SSReourceItem *item = [self loadResource:request];
60 | //preload from network
61 | if (!item) {
62 |
63 | }
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIMainStoryboardFile
45 | Main
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 | NSAppTransportSecurity
64 |
65 | NSAllowsArbitraryLoads
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2020/5/11.
6 | // Copyright © 2020 sgcy. All rights reserved.
7 | //
8 |
9 | #import "SceneDelegate.h"
10 |
11 | @interface SceneDelegate ()
12 |
13 | @end
14 |
15 | @implementation SceneDelegate
16 |
17 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
18 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
19 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
20 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
21 | }
22 |
23 |
24 | - (void)sceneDidDisconnect:(UIScene *)scene {
25 | // Called as the scene is being released by the system.
26 | // This occurs shortly after the scene enters the background, or when its session is discarded.
27 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
28 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
29 | }
30 |
31 |
32 | - (void)sceneDidBecomeActive:(UIScene *)scene {
33 | // Called when the scene has moved from an inactive state to an active state.
34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
35 | }
36 |
37 |
38 | - (void)sceneWillResignActive:(UIScene *)scene {
39 | // Called when the scene will move from an active state to an inactive state.
40 | // This may occur due to temporary interruptions (ex. an incoming phone call).
41 | }
42 |
43 |
44 | - (void)sceneWillEnterForeground:(UIScene *)scene {
45 | // Called as the scene transitions from the background to the foreground.
46 | // Use this method to undo the changes made on entering the background.
47 | }
48 |
49 |
50 | - (void)sceneDidEnterBackground:(UIScene *)scene {
51 | // Called as the scene transitions from the foreground to the background.
52 | // Use this method to save data, release shared resources, and store enough scene-specific state information
53 | // to restore the scene back to its current state.
54 | }
55 |
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2020/5/11.
6 | // Copyright © 2020 sgcy. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import
11 | #import "SSWKURL.h"
12 |
13 | @interface ViewController ()
14 |
15 | @property (nonatomic,strong) NSDictionary *timing;
16 | @property (nonatomic,strong) WKWebView *webView;
17 | @property (nonatomic,strong) NSDate *beginDate;
18 |
19 | @end
20 |
21 | @implementation ViewController
22 |
23 | - (void)viewDidLoad {
24 | [super viewDidLoad];
25 | // Do any additional se3tup after loading the view.
26 | WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
27 | [config.userContentController addScriptMessageHandler:self name:@"event"];
28 |
29 |
30 | NSString *jScript = @"window.webkit.messageHandlers.event.postMessage({\"\":\"\"});";
31 | WKUserScript *js = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
32 | [config.userContentController addUserScript:js];
33 |
34 | [config ssRegisterURLProtocol:[SSWKURLProtocol class]];
35 | WKWebView *wkWebView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
36 | wkWebView.navigationDelegate = self;
37 | [self.view addSubview:wkWebView];
38 |
39 | // NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://v.youku.com/v_show/id_XNDc1NDI5MzQ0OA==.html"]];
40 | NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.bilibili.com/video/BV1rf4y1e7MD?p=2"]];
41 |
42 | // NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.iqiyi.com/v_1pxfxfkiehg.html?vfrm=pcw_home&vfrmblk=D&vfrmrst=712211_focus_A_image4"]];
43 |
44 |
45 | [wkWebView loadRequest:request];
46 |
47 | self.webView = wkWebView;
48 | self.beginDate = [NSDate date];
49 | }
50 |
51 |
52 |
53 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
54 | {
55 | NSDate *nowDate = [NSDate date];
56 | NSTimeInterval delta = [nowDate timeIntervalSinceDate:self.beginDate];
57 | if (delta > 0.5) {
58 | NSLog(@"%f",delta);
59 | NSLog(@"--------------");
60 | }
61 |
62 | // [self.webView evaluateJavaScript:@"JSON.stringify(window.performance.timing.toJSON())" completionHandler:^(NSString * _Nullable timingStr, NSError * _Nullable error) {
63 | // if (!error) {、
64 | // self.timing = [NSJSONSerialization JSONObjectWithData:[timingStr dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
65 | // NSInteger before = [self.timing[@"domainLookupStart"] integerValue] - [self.timing[@"navigationStart"] integerValue];
66 | // NSInteger dnsTime = [self.timing[@"domainLookupEnd"] integerValue] - [self.timing[@"domainLookupStart"] integerValue];
67 | // NSInteger handShakeTime = [self.timing[@"connectEnd"] integerValue] - [self.timing[@"connectStart"] integerValue];
68 | //
69 | // NSInteger requestTime = [self.timing[@"responseStart"] integerValue] - [self.timing[@"requestStart"] integerValue];
70 | // NSInteger responseTime = [self.timing[@"responseEnd"] integerValue] - [self.timing[@"responseStart"] integerValue];
71 | // NSInteger domTime = [self.timing[@"domComplete"] integerValue] - [self.timing[@"responseEnd"] integerValue];
72 | //
73 | // NSLog(@"BEFORE %d",before);
74 | // NSLog(@"DNS %d",dnsTime);
75 | // NSLog(@"TCP %d",handShakeTime);
76 | // NSLog(@"REQUEST %d",requestTime);
77 | // NSLog(@"RESPONSE %d",responseTime);
78 | // NSLog(@"DOM %d",domTime);
79 | //
80 | //
81 | // }
82 | // }];
83 | }
84 |
85 | - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
86 | {
87 | NSLog(@"");
88 | }
89 |
90 | - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
91 | {
92 | NSLog(@"");
93 | }
94 |
95 | - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
96 | {
97 | NSLog(@"");
98 |
99 | }
100 |
101 | - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
102 | {
103 | NSLog(@"");
104 |
105 | }
106 |
107 |
108 |
109 |
110 | @end
111 |
--------------------------------------------------------------------------------
/SSWKURL/SSCache.m:
--------------------------------------------------------------------------------
1 | //
2 | // SSCache.m
3 | // SSWKURLDemo
4 | //
5 | // Created by sgcy on 2021/1/20.
6 | // Copyright © 2021 sgcy. All rights reserved.
7 | //
8 |
9 | #import "SSCache.h"
10 |
11 | @interface SSCache()
12 |
13 | @property (nonatomic,strong) NSMutableDictionary *responseCache;
14 | @property (nonatomic,strong) NSMutableDictionary *dataCache;
15 | @property (nonatomic,strong) NSMutableDictionary *requestFinished;
16 | @property (nonatomic,strong) NSLock *lock;
17 | @property (nonatomic,strong) NSString *rootCachePath;
18 |
19 | @end
20 |
21 | @implementation SSCache
22 |
23 |
24 | + (instancetype)sharedCache
25 | {
26 | static SSCache *sharedCache = nil;
27 | static dispatch_once_t onceToken;
28 | dispatch_once(&onceToken, ^{
29 | sharedCache = [[self alloc]init];
30 | });
31 | return sharedCache;
32 | }
33 |
34 | - (instancetype)init
35 | {
36 | if (self = [super init]) {
37 | self.responseCache = [[NSMutableDictionary alloc] init];
38 | self.dataCache = [[NSMutableDictionary alloc] init];
39 | self.requestFinished = [[NSMutableDictionary alloc] init];
40 | self.lock = [[NSLock alloc] init];
41 | [self setupCacheDirectory];
42 | }
43 | return self;
44 | }
45 |
46 | - (NSData *)dataForRequestId:(NSString *)requestId
47 | {
48 | //load from memory
49 | NSData *data = self.dataCache[requestId];
50 | if (data) {
51 | NSNumber *finished = self.requestFinished[requestId];
52 | if (finished && finished.boolValue) {
53 | return data;
54 | }
55 | }
56 |
57 | //load from disk
58 | NSString *cacheFilePath = [self filePathWithType:1 sessionID:requestId];
59 | return [NSData dataWithContentsOfFile:cacheFilePath];
60 | }
61 |
62 | - (NSDictionary *)responseHeadersWithRequestID:(NSString *)requestId
63 | {
64 | //load from memory
65 | NSDictionary *responseHeaders = self.responseCache[requestId];
66 | if (responseHeaders) {
67 | return responseHeaders;
68 | }
69 |
70 | //load from disk
71 | NSString *responsePath = [self filePathWithType:0 sessionID:requestId];
72 | return [NSDictionary dictionaryWithContentsOfFile:responsePath];
73 | }
74 |
75 | - (void)saveData:(NSData *)data forRequestId:(NSString *)requestId
76 | {
77 | NSMutableData *mutaData = self.dataCache[requestId];
78 | if (!mutaData) {
79 | mutaData = [[NSMutableData alloc] init];
80 | }
81 | [mutaData appendData:data];
82 | [self.dataCache setObject:mutaData forKey:requestId];
83 | }
84 |
85 | - (void)saveResponseHeaders:(NSDictionary *)responseHeaders forRequestId:(NSString *)requestId
86 | {
87 | [self.responseCache setObject:responseHeaders forKey:requestId];
88 | }
89 |
90 | - (void)finishRequestForRequestId:(NSString *)requestId
91 | {
92 | [self.requestFinished setObject:@(YES) forKey:requestId];
93 |
94 | NSDictionary *responseHeaders = self.responseCache[requestId];
95 | if (responseHeaders) {
96 | NSString *responsePath = [self filePathWithType:0 sessionID:requestId];
97 | BOOL isSuccess = [responseHeaders writeToFile:responsePath atomically:YES];
98 | }
99 |
100 | NSData *data = self.dataCache[requestId];
101 | if (data) {
102 | NSString *dataPath = [self filePathWithType:1 sessionID:requestId];
103 | BOOL isSuccess = [data writeToFile:dataPath atomically:YES];
104 | }
105 |
106 | }
107 |
108 | #pragma mark - file
109 |
110 | - (BOOL)setupCacheDirectory
111 | {
112 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
113 | _rootCachePath = [[self createDirectoryIfNotExist:[paths objectAtIndex:0] withSubPath:@"SSCache"] copy];
114 | return _rootCachePath.length > 0;
115 | }
116 |
117 | - (BOOL)checkCacheTypeExist:(NSInteger)type sessionID:(NSString *)sessionID
118 | {
119 | NSString *cachePath = [self filePathWithType:type sessionID:sessionID];
120 |
121 | return [[NSFileManager defaultManager] fileExistsAtPath:cachePath];
122 | }
123 |
124 | - (NSString *)filePathWithType:(NSInteger)type sessionID:(NSString *)sessionID
125 | {
126 | NSString *fileDir = [self sessionSubCacheDir:sessionID];
127 | if (fileDir.length == 0) {
128 | return nil;
129 | }
130 | NSString *cacheFileName = [sessionID stringByAppendingPathExtension:[@(type) stringValue]];
131 | return [fileDir stringByAppendingPathComponent:cacheFileName];
132 | }
133 |
134 | - (NSString *)sessionSubCacheDir:(NSString *)sessionID
135 | {
136 | return [self createDirectoryIfNotExist:_rootCachePath withSubPath:sessionID];
137 | }
138 |
139 | - (NSString *)createDirectoryIfNotExist:(NSString *)parent withSubPath:(NSString *)subPath
140 | {
141 | if(parent.length == 0 || subPath.length == 0){
142 | return nil;
143 | }
144 |
145 | BOOL isDir = YES;
146 | NSString *path = [parent stringByAppendingPathComponent:subPath];
147 | if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir]) {
148 | NSError *error = nil;
149 | [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];
150 | if (error) {
151 | return nil;
152 | }
153 | }
154 | return path;
155 | }
156 |
157 | @end
158 |
--------------------------------------------------------------------------------
/SSWKURL/SSWKURL.m:
--------------------------------------------------------------------------------
1 | //
2 | // SSWKURL.m
3 | // SSWKURL
4 | //
5 | // Created by sgcy on 2020/4/21.
6 | // Copyright © 2020 sgcy. All rights reserved.
7 | //
8 |
9 | #import "SSWKURL.h"
10 | #import
11 | #import "SSCache.h"
12 | #import "SSUtils.h"
13 | #import "SSResourceLoader.h"
14 |
15 | @interface WKWebView(handlesURLScheme)
16 |
17 |
18 | @end
19 |
20 | @implementation WKWebView(handlesURLScheme)
21 |
22 |
23 | + (BOOL)handlesURLScheme:(NSString *)urlScheme
24 | {
25 | return NO;
26 | }
27 |
28 | @end
29 |
30 | #pragma mark -
31 |
32 | typedef BOOL (^HTTPDNSCookieFilter)(NSHTTPCookie *, NSURL *);
33 |
34 | @interface NSURLRequest(requestId)
35 |
36 | @property (nonatomic,assign) BOOL ss_stop;
37 | - (NSString *)requestId;
38 | - (NSString *)requestRepresent;
39 |
40 | @end
41 |
42 | static char *kNSURLRequestSSTOPKEY = "kNSURLRequestSSTOPKEY";
43 |
44 | @implementation NSURLRequest(requestId)
45 |
46 | - (BOOL)ss_stop
47 | {
48 | return [objc_getAssociatedObject(self, kNSURLRequestSSTOPKEY) boolValue];
49 | }
50 |
51 | - (void)setSs_stop:(BOOL)ss_stop
52 | {
53 | objc_setAssociatedObject(self, kNSURLRequestSSTOPKEY, @(ss_stop), OBJC_ASSOCIATION_ASSIGN);
54 | }
55 |
56 | - (NSString *)requestId
57 | {
58 | return [@([self hash]) stringValue];
59 | }
60 |
61 | - (NSString *)requestRepresent
62 | {
63 | return [NSString stringWithFormat:@"%@---%@",self.URL.absoluteString,self.HTTPMethod];
64 | }
65 |
66 | + (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host {
67 | return YES;
68 | }
69 |
70 | + (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host {
71 |
72 | }
73 |
74 |
75 | @end
76 |
77 | #pragma mark -
78 |
79 | @interface SSWKTaskDelegate : NSObject
80 |
81 | @property (nonatomic,weak) id schemeTask;
82 |
83 | @end
84 |
85 | @implementation SSWKTaskDelegate
86 |
87 | - (void)URLSession:(NSURLSession *)session
88 | task:(NSURLSessionTask *)task
89 | didCompleteWithError:(NSError *)error
90 | {
91 | if (error) {
92 | [self.schemeTask didFailWithError:error];
93 | }else{
94 | [self.schemeTask didFinish];
95 | [[SSCache sharedCache] finishRequestForRequestId:[SSUtils requestIdForRequest:task.currentRequest]];
96 | }
97 | }
98 |
99 | - (void)URLSession:(NSURLSession *)session
100 | dataTask:(NSURLSessionDataTask *)dataTask
101 | didReceiveData:(NSData *)data
102 | {
103 | if (dataTask.state == NSURLSessionTaskStateCanceling) {
104 | return;
105 | }
106 | [self.schemeTask didReceiveData:data];
107 | [[SSCache sharedCache] saveData:data forRequestId:[SSUtils requestIdForRequest:dataTask.currentRequest]];
108 | }
109 |
110 |
111 | - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
112 | didReceiveResponse:(NSURLResponse *)response
113 | completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
114 | {
115 | if (dataTask.state == NSURLSessionTaskStateCanceling) {
116 | return;
117 | }
118 | [self.schemeTask didReceiveResponse:response];
119 | if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
120 | NSHTTPURLResponse *httpRes = (NSHTTPURLResponse *)response;
121 | [[SSCache sharedCache] saveResponseHeaders:httpRes.allHeaderFields forRequestId:[SSUtils requestIdForRequest:dataTask.currentRequest]];
122 |
123 | }
124 | }
125 |
126 |
127 | @end
128 |
129 |
130 | #pragma mark -
131 |
132 | @interface SSWKURLProtocol()
133 |
134 | @property (nonatomic,readwrite,copy) NSURLRequest *request;
135 |
136 | @end
137 |
138 | @implementation SSWKURLProtocol
139 |
140 |
141 | @end
142 |
143 |
144 |
145 | @interface SSWKURLHandler:NSObject
146 |
147 | @property (nonatomic,strong) Class protocolClass;
148 | @property (nonatomic,strong) NSURLSession *session;
149 | @property (nonatomic,strong) dispatch_queue_t queue;
150 |
151 | @property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
152 | @property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
153 | @property (readwrite, nonatomic, strong) NSLock *lock;
154 |
155 | @end
156 |
157 |
158 | @implementation SSWKURLHandler{
159 | HTTPDNSCookieFilter cookieFilter;
160 | }
161 |
162 | static SSWKURLHandler *sharedInstance = nil;
163 |
164 | + (SSWKURLHandler *)sharedInstance{
165 | static dispatch_once_t onceToken;
166 | dispatch_once(&onceToken, ^{
167 | sharedInstance = [[self alloc]init];
168 | sharedInstance->cookieFilter = ^BOOL(NSHTTPCookie *cookie, NSURL *URL) {
169 | if ([URL.host containsString:cookie.domain]) {
170 | return YES;
171 | }
172 | return NO;
173 | };
174 | });
175 | return sharedInstance;
176 | }
177 |
178 | - (instancetype)init
179 | {
180 | if (self = [super init]) {
181 | self.lock = [[NSLock alloc] init];
182 | self.operationQueue = [[NSOperationQueue alloc] init];
183 | self.operationQueue.maxConcurrentOperationCount = 1;
184 | self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
185 | [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"https"];
186 |
187 | }
188 | return self;
189 | }
190 |
191 |
192 | - (NSURLSession *)session
193 | {
194 | if (!_session) {
195 | NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
196 | _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:self.operationQueue];
197 | }
198 | return _session;
199 | }
200 |
201 |
202 | - (dispatch_queue_t)queue
203 | {
204 | if (!_queue) {
205 | _queue = dispatch_queue_create("SSWKURLHandler.queue", DISPATCH_QUEUE_SERIAL);
206 | _queue = dispatch_get_main_queue();
207 | }
208 | return _queue;
209 | }
210 |
211 | - (void)webView:(WKWebView *)webView startURLSchemeTask:(id )urlSchemeTask
212 | {
213 | // if (![self.protocolClass isKindOfClass:[SSWKURLProtocol class]]) {
214 | // @throw [NSException exceptionWithName:@"SSWKURLProtolRegisterFail" reason:@"URLProtocol is not subclass of SSWKURLProtol" userInfo:@{}];
215 | // }
216 | NSURLRequest *request = [urlSchemeTask request];
217 | NSMutableURLRequest *mutaRequest = [request mutableCopy];
218 | [mutaRequest setValue:[self getRequestCookieHeaderForURL:request.URL] forHTTPHeaderField:@"Cookie"];
219 | request = [mutaRequest copy];
220 |
221 | BOOL shouldCache = YES;
222 | if (request.HTTPMethod && ![request.HTTPMethod.uppercaseString isEqualToString:@"GET"]) {
223 | shouldCache = NO;
224 | }
225 | NSString *hasAjax = [request valueForHTTPHeaderField:@"X-Requested-With"];
226 | if (hasAjax != nil) {
227 | shouldCache = NO;
228 | }
229 |
230 | //
231 | SSReourceItem *item = [[SSResourceLoader sharedLoader] loadResource:request];
232 |
233 | NSDictionary *responseHeaders = [(NSHTTPURLResponse *)item.response allHeaderFields];
234 | NSString *contentRange = responseHeaders[@"content-range"];
235 | NSString *contentType = responseHeaders[@"Content-Type"];
236 | if ([contentType isEqualToString:@"video/mp4"]) {
237 | shouldCache = NO;
238 | }
239 |
240 | if (item && shouldCache) {
241 | [urlSchemeTask didReceiveResponse:item.response];
242 | if (item.data) {
243 | [urlSchemeTask didReceiveData:item.data];
244 | }
245 | [urlSchemeTask didFinish];
246 |
247 | }else{
248 | NSURLSessionTask *task = [self.session dataTaskWithRequest:request];
249 | SSWKTaskDelegate *delegate = [[SSWKTaskDelegate alloc] init];
250 | delegate.schemeTask = urlSchemeTask;
251 | [self setDelegate:delegate forTask:task];
252 | [task resume];
253 | }
254 | }
255 |
256 | - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id )urlSchemeTask
257 | {
258 | dispatch_async(self.queue, ^{
259 | urlSchemeTask.request.ss_stop = YES;
260 | });
261 | }
262 |
263 | #pragma mark - wkwebview信任https接口
264 | - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
265 | if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
266 | NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
267 | completionHandler(NSURLSessionAuthChallengeUseCredential, card);
268 | }
269 | }
270 |
271 |
272 | - (NSArray *)handleHeaderFields:(NSDictionary *)headerFields forURL:(NSURL *)URL {
273 | NSArray *cookieArray = [NSHTTPCookie cookiesWithResponseHeaderFields:headerFields forURL:URL];
274 | if (cookieArray.count == 0) {
275 | return cookieArray;
276 | }
277 | if (cookieArray != nil) {
278 | NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
279 | for (NSHTTPCookie *cookie in cookieArray) {
280 | if (cookieFilter(cookie, URL)) {
281 | [cookieStorage setCookie:cookie];
282 | }
283 | }
284 | }
285 | return cookieArray;
286 | }
287 |
288 | - (NSString *)getRequestCookieHeaderForURL:(NSURL *)URL {
289 | NSArray *cookieArray = [self searchAppropriateCookies:URL];
290 | if (cookieArray != nil && cookieArray.count > 0) {
291 | NSDictionary *cookieDic = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];
292 | if ([cookieDic objectForKey:@"Cookie"]) {
293 | return cookieDic[@"Cookie"];
294 | }
295 | }
296 | return nil;
297 | }
298 |
299 | - (NSArray *)searchAppropriateCookies:(NSURL *)URL {
300 | NSMutableArray *cookieArray = [NSMutableArray array];
301 | NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
302 | for (NSHTTPCookie *cookie in [cookieStorage cookies]) {
303 | if (cookieFilter(cookie, URL)) {
304 | [cookieArray addObject:cookie];
305 | }
306 | }
307 | return cookieArray;
308 | }
309 |
310 | #pragma mark - delegate
311 |
312 |
313 | - (void)setDelegate:(SSWKTaskDelegate *)delegate
314 | forTask:(NSURLSessionTask *)task
315 | {
316 | [self.lock lock];
317 | self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
318 | [self.lock unlock];
319 | }
320 |
321 | - (SSWKTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
322 | NSParameterAssert(task);
323 | SSWKTaskDelegate *delegate = nil;
324 | [self.lock lock];
325 | delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
326 | [self.lock unlock];
327 |
328 | return delegate;
329 | }
330 |
331 | - (void)removeDelegateForTask:(NSURLSessionTask *)task {
332 | NSParameterAssert(task);
333 | [self.lock lock];
334 | [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
335 | [self.lock unlock];
336 | }
337 |
338 | - (void)URLSession:(NSURLSession *)session
339 | task:(NSURLSessionTask *)task
340 | didCompleteWithError:(NSError *)error
341 | {
342 | SSWKTaskDelegate *delegate = [self delegateForTask:task];
343 | [delegate URLSession:session task:task didCompleteWithError:error];
344 | }
345 |
346 | - (void)URLSession:(NSURLSession *)session
347 | dataTask:(NSURLSessionDataTask *)dataTask
348 | didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
349 | {
350 | // SSWKTaskDelegate *delegate = [self delegateForTask:task];
351 | SSWKTaskDelegate *delegate = [self delegateForTask:dataTask];
352 | if (delegate) {
353 | [self removeDelegateForTask:dataTask];
354 | [self setDelegate:delegate forTask:downloadTask];
355 | }
356 |
357 | }
358 |
359 | - (void)URLSession:(NSURLSession *)session
360 | dataTask:(NSURLSessionDataTask *)dataTask
361 | didReceiveData:(NSData *)data
362 | {
363 | SSWKTaskDelegate *delegate = [self delegateForTask:dataTask];
364 | [delegate URLSession:session dataTask:dataTask didReceiveData:data];
365 | }
366 |
367 |
368 | - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
369 | didReceiveResponse:(NSURLResponse *)response
370 | completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
371 | {
372 | SSWKTaskDelegate *delegate = [self delegateForTask:dataTask];
373 | [delegate URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler];
374 |
375 | NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
376 | if (completionHandler) {
377 | completionHandler(disposition);
378 | }
379 | }
380 |
381 | //- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
382 | // didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
383 | // completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
384 | //{
385 | // NSLog(@"");
386 | //
387 | //}
388 |
389 |
390 | //}
391 |
392 | @end
393 |
394 | @implementation WKWebViewConfiguration(ssRegisterURLProtocol)
395 |
396 | - (void)ssRegisterURLProtocol:(Class)protocolClass
397 | {
398 | SSWKURLHandler *handler = [SSWKURLHandler sharedInstance];
399 | handler.protocolClass = protocolClass;
400 | [self setURLSchemeHandler:handler forURLScheme:@"https"];
401 | [self setURLSchemeHandler:handler forURLScheme:@"http"];
402 | }
403 |
404 | @end
405 |
--------------------------------------------------------------------------------
/Demo/SSWKURLDemo/SSWKURLDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D645EE3A24690218001F70E8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D645EE3924690218001F70E8 /* AppDelegate.m */; };
11 | D645EE3D24690218001F70E8 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D645EE3C24690218001F70E8 /* SceneDelegate.m */; };
12 | D645EE4024690218001F70E8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D645EE3F24690218001F70E8 /* ViewController.m */; };
13 | D645EE4324690218001F70E8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D645EE4124690218001F70E8 /* Main.storyboard */; };
14 | D645EE452469021C001F70E8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D645EE442469021C001F70E8 /* Assets.xcassets */; };
15 | D645EE482469021C001F70E8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D645EE462469021C001F70E8 /* LaunchScreen.storyboard */; };
16 | D645EE4B2469021C001F70E8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D645EE4A2469021C001F70E8 /* main.m */; };
17 | D645EE6F246903F2001F70E8 /* SSWKURL.m in Sources */ = {isa = PBXBuildFile; fileRef = D645EE6D246903F2001F70E8 /* SSWKURL.m */; };
18 | D66739FA25B8317B00DC44C8 /* SSCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D66739F925B8317B00DC44C8 /* SSCache.m */; };
19 | D66739FD25B9218F00DC44C8 /* SSUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = D66739FC25B9218F00DC44C8 /* SSUtils.m */; };
20 | D67A2F1525B825960012A787 /* SSResourceLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = D67A2F1425B825960012A787 /* SSResourceLoader.m */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXFileReference section */
24 | D645EE3524690218001F70E8 /* SSWKURLDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SSWKURLDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
25 | D645EE3824690218001F70E8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
26 | D645EE3924690218001F70E8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
27 | D645EE3B24690218001F70E8 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; };
28 | D645EE3C24690218001F70E8 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; };
29 | D645EE3E24690218001F70E8 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
30 | D645EE3F24690218001F70E8 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
31 | D645EE4224690218001F70E8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
32 | D645EE442469021C001F70E8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
33 | D645EE472469021C001F70E8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
34 | D645EE492469021C001F70E8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
35 | D645EE4A2469021C001F70E8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
36 | D645EE6D246903F2001F70E8 /* SSWKURL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSWKURL.m; sourceTree = ""; };
37 | D645EE6E246903F2001F70E8 /* SSWKURL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSWKURL.h; sourceTree = ""; };
38 | D66739F825B8317B00DC44C8 /* SSCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SSCache.h; sourceTree = ""; };
39 | D66739F925B8317B00DC44C8 /* SSCache.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SSCache.m; sourceTree = ""; };
40 | D66739FB25B9218F00DC44C8 /* SSUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SSUtils.h; sourceTree = ""; };
41 | D66739FC25B9218F00DC44C8 /* SSUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SSUtils.m; sourceTree = ""; };
42 | D67A2F1325B825960012A787 /* SSResourceLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SSResourceLoader.h; sourceTree = ""; };
43 | D67A2F1425B825960012A787 /* SSResourceLoader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SSResourceLoader.m; sourceTree = ""; };
44 | /* End PBXFileReference section */
45 |
46 | /* Begin PBXFrameworksBuildPhase section */
47 | D645EE3224690218001F70E8 /* Frameworks */ = {
48 | isa = PBXFrameworksBuildPhase;
49 | buildActionMask = 2147483647;
50 | files = (
51 | );
52 | runOnlyForDeploymentPostprocessing = 0;
53 | };
54 | /* End PBXFrameworksBuildPhase section */
55 |
56 | /* Begin PBXGroup section */
57 | D645EE2C24690218001F70E8 = {
58 | isa = PBXGroup;
59 | children = (
60 | D645EE3724690218001F70E8 /* SSWKURLDemo */,
61 | D645EE3624690218001F70E8 /* Products */,
62 | );
63 | sourceTree = "";
64 | };
65 | D645EE3624690218001F70E8 /* Products */ = {
66 | isa = PBXGroup;
67 | children = (
68 | D645EE3524690218001F70E8 /* SSWKURLDemo.app */,
69 | );
70 | name = Products;
71 | sourceTree = "";
72 | };
73 | D645EE3724690218001F70E8 /* SSWKURLDemo */ = {
74 | isa = PBXGroup;
75 | children = (
76 | D645EE6C246903F2001F70E8 /* SSWKURL */,
77 | D645EE3824690218001F70E8 /* AppDelegate.h */,
78 | D645EE3924690218001F70E8 /* AppDelegate.m */,
79 | D645EE3B24690218001F70E8 /* SceneDelegate.h */,
80 | D645EE3C24690218001F70E8 /* SceneDelegate.m */,
81 | D645EE3E24690218001F70E8 /* ViewController.h */,
82 | D645EE3F24690218001F70E8 /* ViewController.m */,
83 | D645EE4124690218001F70E8 /* Main.storyboard */,
84 | D645EE442469021C001F70E8 /* Assets.xcassets */,
85 | D645EE462469021C001F70E8 /* LaunchScreen.storyboard */,
86 | D645EE492469021C001F70E8 /* Info.plist */,
87 | D645EE4A2469021C001F70E8 /* main.m */,
88 | );
89 | path = SSWKURLDemo;
90 | sourceTree = "";
91 | };
92 | D645EE6C246903F2001F70E8 /* SSWKURL */ = {
93 | isa = PBXGroup;
94 | children = (
95 | D645EE6D246903F2001F70E8 /* SSWKURL.m */,
96 | D645EE6E246903F2001F70E8 /* SSWKURL.h */,
97 | D67A2F1325B825960012A787 /* SSResourceLoader.h */,
98 | D67A2F1425B825960012A787 /* SSResourceLoader.m */,
99 | D66739F825B8317B00DC44C8 /* SSCache.h */,
100 | D66739F925B8317B00DC44C8 /* SSCache.m */,
101 | D66739FB25B9218F00DC44C8 /* SSUtils.h */,
102 | D66739FC25B9218F00DC44C8 /* SSUtils.m */,
103 | );
104 | name = SSWKURL;
105 | path = ../../../SSWKURL;
106 | sourceTree = "";
107 | };
108 | /* End PBXGroup section */
109 |
110 | /* Begin PBXNativeTarget section */
111 | D645EE3424690218001F70E8 /* SSWKURLDemo */ = {
112 | isa = PBXNativeTarget;
113 | buildConfigurationList = D645EE4E2469021C001F70E8 /* Build configuration list for PBXNativeTarget "SSWKURLDemo" */;
114 | buildPhases = (
115 | D645EE3124690218001F70E8 /* Sources */,
116 | D645EE3224690218001F70E8 /* Frameworks */,
117 | D645EE3324690218001F70E8 /* Resources */,
118 | );
119 | buildRules = (
120 | );
121 | dependencies = (
122 | );
123 | name = SSWKURLDemo;
124 | productName = SSWKURLDemo;
125 | productReference = D645EE3524690218001F70E8 /* SSWKURLDemo.app */;
126 | productType = "com.apple.product-type.application";
127 | };
128 | /* End PBXNativeTarget section */
129 |
130 | /* Begin PBXProject section */
131 | D645EE2D24690218001F70E8 /* Project object */ = {
132 | isa = PBXProject;
133 | attributes = {
134 | LastUpgradeCheck = 1140;
135 | ORGANIZATIONNAME = sgcy;
136 | TargetAttributes = {
137 | D645EE3424690218001F70E8 = {
138 | CreatedOnToolsVersion = 11.4;
139 | };
140 | };
141 | };
142 | buildConfigurationList = D645EE3024690218001F70E8 /* Build configuration list for PBXProject "SSWKURLDemo" */;
143 | compatibilityVersion = "Xcode 9.3";
144 | developmentRegion = en;
145 | hasScannedForEncodings = 0;
146 | knownRegions = (
147 | en,
148 | Base,
149 | );
150 | mainGroup = D645EE2C24690218001F70E8;
151 | productRefGroup = D645EE3624690218001F70E8 /* Products */;
152 | projectDirPath = "";
153 | projectRoot = "";
154 | targets = (
155 | D645EE3424690218001F70E8 /* SSWKURLDemo */,
156 | );
157 | };
158 | /* End PBXProject section */
159 |
160 | /* Begin PBXResourcesBuildPhase section */
161 | D645EE3324690218001F70E8 /* Resources */ = {
162 | isa = PBXResourcesBuildPhase;
163 | buildActionMask = 2147483647;
164 | files = (
165 | D645EE482469021C001F70E8 /* LaunchScreen.storyboard in Resources */,
166 | D645EE452469021C001F70E8 /* Assets.xcassets in Resources */,
167 | D645EE4324690218001F70E8 /* Main.storyboard in Resources */,
168 | );
169 | runOnlyForDeploymentPostprocessing = 0;
170 | };
171 | /* End PBXResourcesBuildPhase section */
172 |
173 | /* Begin PBXSourcesBuildPhase section */
174 | D645EE3124690218001F70E8 /* Sources */ = {
175 | isa = PBXSourcesBuildPhase;
176 | buildActionMask = 2147483647;
177 | files = (
178 | D645EE4024690218001F70E8 /* ViewController.m in Sources */,
179 | D645EE3A24690218001F70E8 /* AppDelegate.m in Sources */,
180 | D67A2F1525B825960012A787 /* SSResourceLoader.m in Sources */,
181 | D645EE4B2469021C001F70E8 /* main.m in Sources */,
182 | D645EE6F246903F2001F70E8 /* SSWKURL.m in Sources */,
183 | D66739FD25B9218F00DC44C8 /* SSUtils.m in Sources */,
184 | D66739FA25B8317B00DC44C8 /* SSCache.m in Sources */,
185 | D645EE3D24690218001F70E8 /* SceneDelegate.m in Sources */,
186 | );
187 | runOnlyForDeploymentPostprocessing = 0;
188 | };
189 | /* End PBXSourcesBuildPhase section */
190 |
191 | /* Begin PBXVariantGroup section */
192 | D645EE4124690218001F70E8 /* Main.storyboard */ = {
193 | isa = PBXVariantGroup;
194 | children = (
195 | D645EE4224690218001F70E8 /* Base */,
196 | );
197 | name = Main.storyboard;
198 | sourceTree = "";
199 | };
200 | D645EE462469021C001F70E8 /* LaunchScreen.storyboard */ = {
201 | isa = PBXVariantGroup;
202 | children = (
203 | D645EE472469021C001F70E8 /* Base */,
204 | );
205 | name = LaunchScreen.storyboard;
206 | sourceTree = "";
207 | };
208 | /* End PBXVariantGroup section */
209 |
210 | /* Begin XCBuildConfiguration section */
211 | D645EE4C2469021C001F70E8 /* Debug */ = {
212 | isa = XCBuildConfiguration;
213 | buildSettings = {
214 | ALWAYS_SEARCH_USER_PATHS = NO;
215 | CLANG_ANALYZER_NONNULL = YES;
216 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
217 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
218 | CLANG_CXX_LIBRARY = "libc++";
219 | CLANG_ENABLE_MODULES = YES;
220 | CLANG_ENABLE_OBJC_ARC = YES;
221 | CLANG_ENABLE_OBJC_WEAK = YES;
222 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
223 | CLANG_WARN_BOOL_CONVERSION = YES;
224 | CLANG_WARN_COMMA = YES;
225 | CLANG_WARN_CONSTANT_CONVERSION = YES;
226 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
227 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
228 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
229 | CLANG_WARN_EMPTY_BODY = YES;
230 | CLANG_WARN_ENUM_CONVERSION = YES;
231 | CLANG_WARN_INFINITE_RECURSION = YES;
232 | CLANG_WARN_INT_CONVERSION = YES;
233 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
234 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
235 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
236 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
237 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
238 | CLANG_WARN_STRICT_PROTOTYPES = YES;
239 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
240 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
241 | CLANG_WARN_UNREACHABLE_CODE = YES;
242 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
243 | COPY_PHASE_STRIP = NO;
244 | DEBUG_INFORMATION_FORMAT = dwarf;
245 | ENABLE_STRICT_OBJC_MSGSEND = YES;
246 | ENABLE_TESTABILITY = YES;
247 | GCC_C_LANGUAGE_STANDARD = gnu11;
248 | GCC_DYNAMIC_NO_PIC = NO;
249 | GCC_NO_COMMON_BLOCKS = YES;
250 | GCC_OPTIMIZATION_LEVEL = 0;
251 | GCC_PREPROCESSOR_DEFINITIONS = (
252 | "DEBUG=1",
253 | "$(inherited)",
254 | );
255 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
256 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
257 | GCC_WARN_UNDECLARED_SELECTOR = YES;
258 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
259 | GCC_WARN_UNUSED_FUNCTION = YES;
260 | GCC_WARN_UNUSED_VARIABLE = YES;
261 | IPHONEOS_DEPLOYMENT_TARGET = 13.4;
262 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
263 | MTL_FAST_MATH = YES;
264 | ONLY_ACTIVE_ARCH = YES;
265 | SDKROOT = iphoneos;
266 | };
267 | name = Debug;
268 | };
269 | D645EE4D2469021C001F70E8 /* Release */ = {
270 | isa = XCBuildConfiguration;
271 | buildSettings = {
272 | ALWAYS_SEARCH_USER_PATHS = NO;
273 | CLANG_ANALYZER_NONNULL = YES;
274 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
275 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
276 | CLANG_CXX_LIBRARY = "libc++";
277 | CLANG_ENABLE_MODULES = YES;
278 | CLANG_ENABLE_OBJC_ARC = YES;
279 | CLANG_ENABLE_OBJC_WEAK = YES;
280 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
281 | CLANG_WARN_BOOL_CONVERSION = YES;
282 | CLANG_WARN_COMMA = YES;
283 | CLANG_WARN_CONSTANT_CONVERSION = YES;
284 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
285 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
286 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
287 | CLANG_WARN_EMPTY_BODY = YES;
288 | CLANG_WARN_ENUM_CONVERSION = YES;
289 | CLANG_WARN_INFINITE_RECURSION = YES;
290 | CLANG_WARN_INT_CONVERSION = YES;
291 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
292 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
293 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
294 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
295 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
296 | CLANG_WARN_STRICT_PROTOTYPES = YES;
297 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
298 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
299 | CLANG_WARN_UNREACHABLE_CODE = YES;
300 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
301 | COPY_PHASE_STRIP = NO;
302 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
303 | ENABLE_NS_ASSERTIONS = NO;
304 | ENABLE_STRICT_OBJC_MSGSEND = YES;
305 | GCC_C_LANGUAGE_STANDARD = gnu11;
306 | GCC_NO_COMMON_BLOCKS = YES;
307 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
308 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
309 | GCC_WARN_UNDECLARED_SELECTOR = YES;
310 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
311 | GCC_WARN_UNUSED_FUNCTION = YES;
312 | GCC_WARN_UNUSED_VARIABLE = YES;
313 | IPHONEOS_DEPLOYMENT_TARGET = 13.4;
314 | MTL_ENABLE_DEBUG_INFO = NO;
315 | MTL_FAST_MATH = YES;
316 | SDKROOT = iphoneos;
317 | VALIDATE_PRODUCT = YES;
318 | };
319 | name = Release;
320 | };
321 | D645EE4F2469021C001F70E8 /* Debug */ = {
322 | isa = XCBuildConfiguration;
323 | buildSettings = {
324 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
325 | CODE_SIGN_STYLE = Automatic;
326 | DEVELOPMENT_TEAM = 76Q3S5QZHK;
327 | INFOPLIST_FILE = SSWKURLDemo/Info.plist;
328 | LD_RUNPATH_SEARCH_PATHS = (
329 | "$(inherited)",
330 | "@executable_path/Frameworks",
331 | );
332 | PRODUCT_BUNDLE_IDENTIFIER = sgcy.SSWKURLDemo;
333 | PRODUCT_NAME = "$(TARGET_NAME)";
334 | TARGETED_DEVICE_FAMILY = "1,2";
335 | };
336 | name = Debug;
337 | };
338 | D645EE502469021C001F70E8 /* Release */ = {
339 | isa = XCBuildConfiguration;
340 | buildSettings = {
341 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
342 | CODE_SIGN_STYLE = Automatic;
343 | DEVELOPMENT_TEAM = 76Q3S5QZHK;
344 | INFOPLIST_FILE = SSWKURLDemo/Info.plist;
345 | LD_RUNPATH_SEARCH_PATHS = (
346 | "$(inherited)",
347 | "@executable_path/Frameworks",
348 | );
349 | PRODUCT_BUNDLE_IDENTIFIER = sgcy.SSWKURLDemo;
350 | PRODUCT_NAME = "$(TARGET_NAME)";
351 | TARGETED_DEVICE_FAMILY = "1,2";
352 | };
353 | name = Release;
354 | };
355 | /* End XCBuildConfiguration section */
356 |
357 | /* Begin XCConfigurationList section */
358 | D645EE3024690218001F70E8 /* Build configuration list for PBXProject "SSWKURLDemo" */ = {
359 | isa = XCConfigurationList;
360 | buildConfigurations = (
361 | D645EE4C2469021C001F70E8 /* Debug */,
362 | D645EE4D2469021C001F70E8 /* Release */,
363 | );
364 | defaultConfigurationIsVisible = 0;
365 | defaultConfigurationName = Release;
366 | };
367 | D645EE4E2469021C001F70E8 /* Build configuration list for PBXNativeTarget "SSWKURLDemo" */ = {
368 | isa = XCConfigurationList;
369 | buildConfigurations = (
370 | D645EE4F2469021C001F70E8 /* Debug */,
371 | D645EE502469021C001F70E8 /* Release */,
372 | );
373 | defaultConfigurationIsVisible = 0;
374 | defaultConfigurationName = Release;
375 | };
376 | /* End XCConfigurationList section */
377 | };
378 | rootObject = D645EE2D24690218001F70E8 /* Project object */;
379 | }
380 |
--------------------------------------------------------------------------------