Repository: li6185377/IMYWebLoader Branch: master Commit: 43b2b5b1445d Files: 73 Total size: 197.7 KB Directory structure: gitextract_x13ozi8z/ ├── .gitignore ├── Demo/ │ ├── IMYWebLoader/ │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets/ │ │ │ └── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── IMYIndexVC.h │ │ ├── IMYIndexVC.m │ │ ├── Info.plist │ │ ├── WKURLProtocolVC.h │ │ ├── WKURLProtocolVC.m │ │ └── main.m │ ├── IMYWebLoader.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── IMYWebLoader.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── IMYWebLoaderTests/ │ │ ├── IMYWebLoaderTests.m │ │ └── Info.plist │ ├── Podfile │ └── Pods/ │ ├── Local Podspecs/ │ │ └── IMYWebLoader.podspec.json │ ├── Pods.xcodeproj/ │ │ └── project.pbxproj │ ├── Target Support Files/ │ │ ├── IMYWebLoader/ │ │ │ ├── IMYWebLoader-dummy.m │ │ │ ├── IMYWebLoader-prefix.pch │ │ │ └── IMYWebLoader.xcconfig │ │ ├── Pods-IMYWebLoader/ │ │ │ ├── Pods-IMYWebLoader-acknowledgements.markdown │ │ │ ├── Pods-IMYWebLoader-acknowledgements.plist │ │ │ ├── Pods-IMYWebLoader-dummy.m │ │ │ ├── Pods-IMYWebLoader-frameworks.sh │ │ │ ├── Pods-IMYWebLoader-resources.sh │ │ │ ├── Pods-IMYWebLoader.debug.xcconfig │ │ │ └── Pods-IMYWebLoader.release.xcconfig │ │ └── XMLDictionary/ │ │ ├── XMLDictionary-dummy.m │ │ ├── XMLDictionary-prefix.pch │ │ └── XMLDictionary.xcconfig │ └── XMLDictionary/ │ ├── LICENCE.md │ ├── README.md │ └── XMLDictionary/ │ ├── XMLDictionary.h │ └── XMLDictionary.m ├── IMYWebLoader.podspec ├── LICENSE ├── README.md └── Sources/ ├── Private/ │ ├── Handler/ │ │ ├── IMYWebCacheHandlerDefaultImpl.h │ │ ├── IMYWebCacheHandlerDefaultImpl.m │ │ ├── IMYWebNetworkHandlerDefaultImpl.h │ │ ├── IMYWebNetworkHandlerDefaultImpl.m │ │ ├── IMYWebPrefetchHandlerDefaultImpl.h │ │ └── IMYWebPrefetchHandlerDefaultImpl.m │ ├── HookAjax/ │ │ ├── IMYWebAjaxHandlerDefaultImpl.h │ │ ├── IMYWebAjaxHandlerDefaultImpl.m │ │ └── WKUserContentController+IMYHookAjax.m │ ├── Loader/ │ │ ├── IMYWebLoader+Impl.h │ │ └── IMYWebLoader+Impl.m │ ├── URLProtocol/ │ │ ├── IMYWebRequestHandleManagerDefaultImpl.h │ │ ├── IMYWebRequestHandleManagerDefaultImpl.m │ │ ├── IMYWebRequestHandlerDefaultImpl.h │ │ ├── IMYWebRequestHandlerDefaultImpl.m │ │ ├── IMYWebURLProtocol.h │ │ ├── IMYWebURLProtocol.m │ │ ├── NSObject+WKCustomProtocolLoader.h │ │ └── NSObject+WKCustomProtocolLoader.m │ └── Utils/ │ ├── IMYWebUtils.h │ └── IMYWebUtils.m ├── Public/ │ ├── Data/ │ │ ├── IMYWebData.h │ │ └── IMYWebData.m │ ├── Handler/ │ │ ├── IMYWebAjaxHandler.h │ │ ├── IMYWebCacheHandler.h │ │ ├── IMYWebNetworkHandler.h │ │ ├── IMYWebPrefetchHandler.h │ │ └── IMYWebRequestHandleManager.h │ ├── Header/ │ │ ├── IMYWebDefines.h │ │ ├── IMYWebOperation.h │ │ └── WKUserContentController+IMYHookAjax.h │ └── IMYWebLoader.h └── Resources/ └── imywk_hookajax.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Build generated build/ DerivedData/ ## Various settings *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata/ ## Other *.moved-aside *.xcuserstate ## Obj-C/Swift specific *.hmap *.ipa *.dSYM.zip *.dSYM # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # # Pods/ # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md fastlane/report.xml fastlane/screenshots #Code Injection # # After new code Injection tools there's a generated folder /iOSInjectionProject # https://github.com/johnno1962/injectionforxcode iOSInjectionProject/ ================================================ FILE: Demo/IMYWebLoader/AppDelegate.h ================================================ // // AppDelegate.h // IMYWebLoader // // Created by ljh on 2017/2/27. // Copyright © 2017年 meetyou. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Demo/IMYWebLoader/AppDelegate.m ================================================ // // AppDelegate.m // IMYWebLoader // // Created by ljh on 2017/2/27. // Copyright © 2017年 meetyou. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: Demo/IMYWebLoader/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/IMYWebLoader/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Demo/IMYWebLoader/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Demo/IMYWebLoader/IMYIndexVC.h ================================================ // // IMYIndexVC.h // IMYWebLoader // // Created by ljh on 2017/4/10. // Copyright © 2017年 meetyou. All rights reserved. // #import @interface IMYIndexVC : UITableViewController @end ================================================ FILE: Demo/IMYWebLoader/IMYIndexVC.m ================================================ // // IMYIndexVC.m // IMYWebLoader // // Created by ljh on 2017/4/10. // Copyright © 2017年 meetyou. All rights reserved. // #import "IMYIndexVC.h" #import "WKURLProtocolVC.h" #import @interface IMYCacheNewsRequestHandler : NSObject @end @implementation IMYIndexVC { NSArray *array; } + (void)initialize { [[IMYWebLoader defaultRequestManager] addRequestHandlerClass:[IMYCacheNewsRequestHandler class]]; } - (void)viewDidLoad { [super viewDidLoad]; [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; array = @[@{@"id":@0, @"title":@"正常WKWebView"}, @{@"id":@1, @"title":@"Hook Ajax WKWebView"}, @{@"id":@2, @"title":@"正常加载-有缓存"}, @{@"id":@3, @"title":@"预加载"}]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return array.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; NSDictionary *dict = array[indexPath.row]; cell.textLabel.text = dict[@"title"]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; NSDictionary *dict = array[indexPath.row]; switch ([dict[@"id"] integerValue]) { case 0: { WKURLProtocolVC *vc = [WKURLProtocolVC new]; vc.urlString = @"http://www.w3school.com.cn/tiy/loadtext.asp?f=ajax_post2"; [self.navigationController pushViewController:vc animated:YES]; break; } case 1: { WKURLProtocolVC *vc = [WKURLProtocolVC new]; vc.urlString = @"http://www.w3school.com.cn/tiy/loadtext.asp?f=ajax_post2"; vc.testAjax = YES; [self.navigationController pushViewController:vc animated:YES]; break; } case 2: { NSString *urlString = @"https://news-node.seeyouyima.com/article?news_id=842947"; WKURLProtocolVC *vc = [WKURLProtocolVC new]; vc.urlString = urlString; [self.navigationController pushViewController:vc animated:YES]; break; } case 3: { [self prefetchWebVC]; break; } } } - (void)prefetchWebVC { NSString *urlString = @"https://news-node.seeyouyima.com/article?news_id=842947"; id data = [[IMYWebLoader defaultCacheHandler] dataForKey:urlString]; if (data) { WKURLProtocolVC *vc = [WKURLProtocolVC new]; vc.urlString = urlString; [self.navigationController pushViewController:vc animated:YES]; } else { id prefetcher = [[IMYWebLoader defaultPrefetchHandler] prefetchWebUrl:urlString]; /// kvo complated ... if (![(id)prefetcher observationInfo]) { [(id)prefetcher addObserver:self forKeyPath:@"complated" options:NSKeyValueObservingOptionNew context:nil]; } } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([change[NSKeyValueChangeNewKey] boolValue]) { NSLog(@"预加载完成!"); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self prefetchWebVC]; }); } [object removeObserver:self forKeyPath:@"complated"]; } @end @implementation IMYCacheNewsRequestHandler /// 是否要拦截该 request + (BOOL)shouldHookWithRequest:(NSURLRequest *)request { if ([request.URL.absoluteString containsString:@"news-node.seeyouyima.com"]) { return YES; } return NO; } /// 取消该 Request 的拦截,只要有一个 class 返回 YES,则不拦截该请求 + (BOOL)cancelHookWithRequest:(NSURLRequest *)request { return NO; } /// 根据 Request 返回具体的请求实例, 会使用第一个返回的请求对象 + (nullable id)requestHandlerWithRequest:(NSURLRequest *)request { return nil; } /// 开始加载 - (void)startLoadingWithDelegate:(id)delegate { } /// 停止加载 - (void)stopLoading { } @end ================================================ FILE: Demo/IMYWebLoader/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Demo/IMYWebLoader/WKURLProtocolVC.h ================================================ // // WKURLProtocolVC.h // IMYWebLoader // // Created by ljh on 2017/4/10. // Copyright © 2017年 meetyou. All rights reserved. // #import @interface WKURLProtocolVC : UIViewController @property (nonatomic, assign) BOOL testAjax; @property (nonatomic, copy) NSString *urlString; @end ================================================ FILE: Demo/IMYWebLoader/WKURLProtocolVC.m ================================================ // // WKURLProtocolVC.m // IMYWebLoader // // Created by ljh on 2017/4/10. // Copyright © 2017年 meetyou. All rights reserved. // #import "WKURLProtocolVC.h" #import #import @interface WKURLProtocolVC () @property (nonatomic, weak) WKWebView *webView; @end @implementation WKURLProtocolVC - (void)viewDidLoad { [super viewDidLoad]; WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; configuration.userContentController = [[WKUserContentController alloc] init]; if (self.testAjax) { [configuration.userContentController imy_installHookAjax]; } WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration]; webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self.view addSubview:webView]; self.webView = webView; [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.urlString]]]; } - (void)dealloc { [self.webView.configuration.userContentController imy_uninstallHookAjax]; } @end ================================================ FILE: Demo/IMYWebLoader/main.m ================================================ // // main.m // IMYWebLoader // // Created by ljh on 2017/2/27. // Copyright © 2017年 meetyou. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Demo/IMYWebLoader.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 362980621E64270A0091D742 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 362980611E64270A0091D742 /* main.m */; }; 362980651E64270A0091D742 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 362980641E64270A0091D742 /* AppDelegate.m */; }; 3629806B1E64270A0091D742 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 362980691E64270A0091D742 /* Main.storyboard */; }; 3629806D1E64270A0091D742 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3629806C1E64270A0091D742 /* Assets.xcassets */; }; 362980701E64270A0091D742 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3629806E1E64270A0091D742 /* LaunchScreen.storyboard */; }; 3629807B1E64270A0091D742 /* IMYWebLoaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3629807A1E64270A0091D742 /* IMYWebLoaderTests.m */; }; 36AF08DB1E9BB6F800BAC046 /* WKURLProtocolVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 36AF08DA1E9BB6F800BAC046 /* WKURLProtocolVC.m */; }; 36AF08E21E9BB91700BAC046 /* IMYIndexVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 36AF08E11E9BB91700BAC046 /* IMYIndexVC.m */; }; FCCBBD89D91DC203319EA56F /* libPods-IMYWebLoader.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 03710CF9824C45880EDAA428 /* libPods-IMYWebLoader.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 362980771E64270A0091D742 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 362980551E64270A0091D742 /* Project object */; proxyType = 1; remoteGlobalIDString = 3629805C1E64270A0091D742; remoteInfo = IMYWebLoader; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 03710CF9824C45880EDAA428 /* libPods-IMYWebLoader.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-IMYWebLoader.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 1E1013721227A4D6FC824714 /* Pods-IMYWebLoader.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IMYWebLoader.debug.xcconfig"; path = "Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader.debug.xcconfig"; sourceTree = ""; }; 3629805D1E64270A0091D742 /* IMYWebLoader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IMYWebLoader.app; sourceTree = BUILT_PRODUCTS_DIR; }; 362980611E64270A0091D742 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 362980631E64270A0091D742 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 362980641E64270A0091D742 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 3629806A1E64270A0091D742 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 3629806C1E64270A0091D742 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 3629806F1E64270A0091D742 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 362980711E64270A0091D742 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 362980761E64270A0091D742 /* IMYWebLoaderTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IMYWebLoaderTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3629807A1E64270A0091D742 /* IMYWebLoaderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IMYWebLoaderTests.m; sourceTree = ""; }; 3629807C1E64270A0091D742 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 36AF08D91E9BB6F800BAC046 /* WKURLProtocolVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKURLProtocolVC.h; sourceTree = ""; }; 36AF08DA1E9BB6F800BAC046 /* WKURLProtocolVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKURLProtocolVC.m; sourceTree = ""; }; 36AF08E01E9BB91700BAC046 /* IMYIndexVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMYIndexVC.h; sourceTree = ""; }; 36AF08E11E9BB91700BAC046 /* IMYIndexVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IMYIndexVC.m; sourceTree = ""; }; 433795A53BC2B8F0327E78AD /* Pods-IMYWebLoader.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IMYWebLoader.release.xcconfig"; path = "Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 3629805A1E64270A0091D742 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( FCCBBD89D91DC203319EA56F /* libPods-IMYWebLoader.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 362980731E64270A0091D742 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 25E668C9C0FB2F4B8A3E476A /* Frameworks */ = { isa = PBXGroup; children = ( 03710CF9824C45880EDAA428 /* libPods-IMYWebLoader.a */, ); name = Frameworks; sourceTree = ""; }; 362980541E64270A0091D742 = { isa = PBXGroup; children = ( 3629805F1E64270A0091D742 /* IMYWebLoader */, 362980791E64270A0091D742 /* IMYWebLoaderTests */, 3629805E1E64270A0091D742 /* Products */, 5023865AF897388D81F3E50F /* Pods */, 25E668C9C0FB2F4B8A3E476A /* Frameworks */, ); sourceTree = ""; }; 3629805E1E64270A0091D742 /* Products */ = { isa = PBXGroup; children = ( 3629805D1E64270A0091D742 /* IMYWebLoader.app */, 362980761E64270A0091D742 /* IMYWebLoaderTests.xctest */, ); name = Products; sourceTree = ""; }; 3629805F1E64270A0091D742 /* IMYWebLoader */ = { isa = PBXGroup; children = ( 362980631E64270A0091D742 /* AppDelegate.h */, 362980641E64270A0091D742 /* AppDelegate.m */, 362980691E64270A0091D742 /* Main.storyboard */, 3629806C1E64270A0091D742 /* Assets.xcassets */, 3629806E1E64270A0091D742 /* LaunchScreen.storyboard */, 362980711E64270A0091D742 /* Info.plist */, 362980601E64270A0091D742 /* Supporting Files */, 36AF08D91E9BB6F800BAC046 /* WKURLProtocolVC.h */, 36AF08DA1E9BB6F800BAC046 /* WKURLProtocolVC.m */, 36AF08E01E9BB91700BAC046 /* IMYIndexVC.h */, 36AF08E11E9BB91700BAC046 /* IMYIndexVC.m */, ); path = IMYWebLoader; sourceTree = ""; }; 362980601E64270A0091D742 /* Supporting Files */ = { isa = PBXGroup; children = ( 362980611E64270A0091D742 /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; 362980791E64270A0091D742 /* IMYWebLoaderTests */ = { isa = PBXGroup; children = ( 3629807A1E64270A0091D742 /* IMYWebLoaderTests.m */, 3629807C1E64270A0091D742 /* Info.plist */, ); path = IMYWebLoaderTests; sourceTree = ""; }; 5023865AF897388D81F3E50F /* Pods */ = { isa = PBXGroup; children = ( 1E1013721227A4D6FC824714 /* Pods-IMYWebLoader.debug.xcconfig */, 433795A53BC2B8F0327E78AD /* Pods-IMYWebLoader.release.xcconfig */, ); name = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 3629805C1E64270A0091D742 /* IMYWebLoader */ = { isa = PBXNativeTarget; buildConfigurationList = 3629807F1E64270A0091D742 /* Build configuration list for PBXNativeTarget "IMYWebLoader" */; buildPhases = ( EABFC25E6BE876D8287524E4 /* [CP] Check Pods Manifest.lock */, 362980591E64270A0091D742 /* Sources */, 3629805A1E64270A0091D742 /* Frameworks */, 3629805B1E64270A0091D742 /* Resources */, AE1F4A421A66A1E5D15F5120 /* [CP] Embed Pods Frameworks */, B33618F5C5C3A08ADC28888E /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = IMYWebLoader; productName = IMYWebLoader; productReference = 3629805D1E64270A0091D742 /* IMYWebLoader.app */; productType = "com.apple.product-type.application"; }; 362980751E64270A0091D742 /* IMYWebLoaderTests */ = { isa = PBXNativeTarget; buildConfigurationList = 362980821E64270A0091D742 /* Build configuration list for PBXNativeTarget "IMYWebLoaderTests" */; buildPhases = ( 362980721E64270A0091D742 /* Sources */, 362980731E64270A0091D742 /* Frameworks */, 362980741E64270A0091D742 /* Resources */, ); buildRules = ( ); dependencies = ( 362980781E64270A0091D742 /* PBXTargetDependency */, ); name = IMYWebLoaderTests; productName = IMYWebLoaderTests; productReference = 362980761E64270A0091D742 /* IMYWebLoaderTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 362980551E64270A0091D742 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0820; ORGANIZATIONNAME = meetyou; TargetAttributes = { 3629805C1E64270A0091D742 = { CreatedOnToolsVersion = 8.2.1; DevelopmentTeam = AX5C7YM44M; ProvisioningStyle = Automatic; }; 362980751E64270A0091D742 = { CreatedOnToolsVersion = 8.2.1; DevelopmentTeam = 588AWE66S7; ProvisioningStyle = Automatic; TestTargetID = 3629805C1E64270A0091D742; }; }; }; buildConfigurationList = 362980581E64270A0091D742 /* Build configuration list for PBXProject "IMYWebLoader" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 362980541E64270A0091D742; productRefGroup = 3629805E1E64270A0091D742 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 3629805C1E64270A0091D742 /* IMYWebLoader */, 362980751E64270A0091D742 /* IMYWebLoaderTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 3629805B1E64270A0091D742 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 362980701E64270A0091D742 /* LaunchScreen.storyboard in Resources */, 3629806D1E64270A0091D742 /* Assets.xcassets in Resources */, 3629806B1E64270A0091D742 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 362980741E64270A0091D742 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ AE1F4A421A66A1E5D15F5120 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; B33618F5C5C3A08ADC28888E /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader-resources.sh\"\n"; showEnvVarsInLog = 0; }; EABFC25E6BE876D8287524E4 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 362980591E64270A0091D742 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 362980651E64270A0091D742 /* AppDelegate.m in Sources */, 36AF08E21E9BB91700BAC046 /* IMYIndexVC.m in Sources */, 36AF08DB1E9BB6F800BAC046 /* WKURLProtocolVC.m in Sources */, 362980621E64270A0091D742 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 362980721E64270A0091D742 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3629807B1E64270A0091D742 /* IMYWebLoaderTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 362980781E64270A0091D742 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 3629805C1E64270A0091D742 /* IMYWebLoader */; targetProxy = 362980771E64270A0091D742 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 362980691E64270A0091D742 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 3629806A1E64270A0091D742 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 3629806E1E64270A0091D742 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 3629806F1E64270A0091D742 /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 3629807D1E64270A0091D742 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 10.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; 3629807E1E64270A0091D742 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 10.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 362980801E64270A0091D742 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 1E1013721227A4D6FC824714 /* Pods-IMYWebLoader.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = AX5C7YM44M; INFOPLIST_FILE = IMYWebLoader/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = meetyou.IMYWebLoader; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 362980811E64270A0091D742 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 433795A53BC2B8F0327E78AD /* Pods-IMYWebLoader.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = AX5C7YM44M; INFOPLIST_FILE = IMYWebLoader/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = meetyou.IMYWebLoader; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 362980831E64270A0091D742 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = 588AWE66S7; INFOPLIST_FILE = IMYWebLoaderTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = meetyou.IMYWebLoaderTests; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/IMYWebLoader.app/IMYWebLoader"; }; name = Debug; }; 362980841E64270A0091D742 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = 588AWE66S7; INFOPLIST_FILE = IMYWebLoaderTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = meetyou.IMYWebLoaderTests; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/IMYWebLoader.app/IMYWebLoader"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 362980581E64270A0091D742 /* Build configuration list for PBXProject "IMYWebLoader" */ = { isa = XCConfigurationList; buildConfigurations = ( 3629807D1E64270A0091D742 /* Debug */, 3629807E1E64270A0091D742 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 3629807F1E64270A0091D742 /* Build configuration list for PBXNativeTarget "IMYWebLoader" */ = { isa = XCConfigurationList; buildConfigurations = ( 362980801E64270A0091D742 /* Debug */, 362980811E64270A0091D742 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 362980821E64270A0091D742 /* Build configuration list for PBXNativeTarget "IMYWebLoaderTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 362980831E64270A0091D742 /* Debug */, 362980841E64270A0091D742 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 362980551E64270A0091D742 /* Project object */; } ================================================ FILE: Demo/IMYWebLoader.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/IMYWebLoader.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/IMYWebLoaderTests/IMYWebLoaderTests.m ================================================ // // IMYWebLoaderTests.m // IMYWebLoaderTests // // Created by ljh on 2017/2/27. // Copyright © 2017年 meetyou. All rights reserved. // #import @interface IMYWebLoaderTests : XCTestCase @end @implementation IMYWebLoaderTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testExample { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } @end ================================================ FILE: Demo/IMYWebLoaderTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleVersion 1 ================================================ FILE: Demo/Podfile ================================================ platform :ios,'7.0' target 'IMYWebLoader' do pod 'IMYWebLoader', :path => './..' end ================================================ FILE: Demo/Pods/Local Podspecs/IMYWebLoader.podspec.json ================================================ { "name": "IMYWebLoader", "version": "0.1", "description": "Web resources loading by Prefetch/Cache/Hook, Support UIWebView/WKWebView ... Orz", "license": "MIT", "summary": "支持对 UIWebView/WKWebView 的资源, 进行 预加载、缓存、拦截 等操作 ... Orz", "homepage": "https://github.com/li6185377/IMYWebLoader", "authors": { "ljh": "137249466@qq.com" }, "source": { "git": "https://github.com/li6185377/IMYWebLoader.git", "tag": "0.1" }, "requires_arc": true, "platforms": { "ios": "7.0" }, "source_files": [ "Sources/Private/**/*.{h,m}", "Sources/Public/**/*.{h,m}" ], "resources": "Sources/Resources/**/*.{js}", "weak_frameworks": [ "JavaScriptCore", "WebKit" ], "dependencies": { "XMLDictionary": [ ] } } ================================================ FILE: Demo/Pods/Pods.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 020FB6622AF33495BD84FAF17C229412 /* NSObject+WKCustomProtocolLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = D563AD4C2CB1406C681C506145FC62EB /* NSObject+WKCustomProtocolLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 049125CCBD1E4E48E417C30880AA5E70 /* IMYWebPrefetchHandlerDefaultImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = C3151AE5832162BBA2E875782D30D4CA /* IMYWebPrefetchHandlerDefaultImpl.h */; settings = {ATTRIBUTES = (Public, ); }; }; 074A90D82FA3046A062867BD2A3544AE /* IMYWebRequestHandleManagerDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = AE9A2574FC1CE0C1D33DB6F741D4BDBD /* IMYWebRequestHandleManagerDefaultImpl.m */; }; 0D7306FEABE5C52E9BD9222E515D17FC /* XMLDictionary-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 169B28CBA254ED18ED7D3572533C91F3 /* XMLDictionary-dummy.m */; }; 10C5BD4EF83CC79057DE8177FEAE2699 /* IMYWebDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = AF7055851C79D40C4D2601C30D6422F1 /* IMYWebDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; 118703A0B27D8BE032448BF8E7218876 /* XMLDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = D4822E3EFC2DBE89F4DB43D54B1E5ED3 /* XMLDictionary.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; 163E102EB5C64542EA2EE28DAC02B294 /* IMYWebLoader-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 607D3E9F26852D2EDD805CDE342E65EA /* IMYWebLoader-dummy.m */; }; 2519C632856C0906596A037A5C4B9AD6 /* Pods-IMYWebLoader-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EBAB6513E884072F16D57BBAE9057E1 /* Pods-IMYWebLoader-dummy.m */; }; 2C3A9DF7E9BEC4A02DBAC87DC32EDCA6 /* IMYWebLoader+Impl.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A4764B6ACA37506631A3877D6E6E660 /* IMYWebLoader+Impl.m */; }; 393409694F95312098AD4CBCBBE9BE10 /* IMYWebAjaxHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 05C70FCBA7C1CA0F7C708F4320CAC383 /* IMYWebAjaxHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 41473B39D21EC87364AB4AD3605A4965 /* IMYWebNetworkHandlerDefaultImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A6976A248C051C88E83FF9B656A771E /* IMYWebNetworkHandlerDefaultImpl.h */; settings = {ATTRIBUTES = (Public, ); }; }; 480DF9BEB028700172A6A4724B62ABB6 /* IMYWebData.h in Headers */ = {isa = PBXBuildFile; fileRef = B6772EDBE07BECC489A276FD7E267933 /* IMYWebData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A9E995FFA4DF1755755069970F51066 /* IMYWebUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = E7B5D2BEBA31696095327500F9698EFD /* IMYWebUtils.m */; }; 4FB83EAD7E47C7699BC80817DC0B7787 /* IMYWebData.m in Sources */ = {isa = PBXBuildFile; fileRef = 83E4BA401FF36F4113838FDF4605E109 /* IMYWebData.m */; }; 56C34BD106D3F8AA93DD5E6AED7FBC7A /* IMYWebAjaxHandlerDefaultImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = C3DD8EC76B96681EFD339E4BDC337F6A /* IMYWebAjaxHandlerDefaultImpl.h */; settings = {ATTRIBUTES = (Public, ); }; }; 58C66C9AE971D25506FB21529C072CFD /* IMYWebRequestHandlerDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = AF22F8742322EB29FF7FE5A004DD98E9 /* IMYWebRequestHandlerDefaultImpl.m */; }; 5A63288A557273DE6BC51B518DE95241 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */; }; 5B6AEB23A102D9197A955238B4E5292A /* WKUserContentController+IMYHookAjax.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F675D06FB5B17B7D7FCFEF44A7DB3EA /* WKUserContentController+IMYHookAjax.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5E1E68C8572414657003AB24D8562B5F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */; }; 5F453934EDB30AC4945532BD82E32BB2 /* IMYWebNetworkHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = C7EDC5D569D587B03CFFA90E3206EBB7 /* IMYWebNetworkHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 66C3480B3B6E130823872459A5199179 /* IMYWebCacheHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FD0817A11C996A0CA63088FAE30AC53 /* IMYWebCacheHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6FB88E598D5AC9A33828EFBF27BCD260 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */; }; 727B06978C5CBB50F80B45B88FE1148B /* NSObject+WKCustomProtocolLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A6B6D4CFCEADAEC7FCB92D162F4981E /* NSObject+WKCustomProtocolLoader.m */; }; 8988814BA9CB2157B9F6D1A4D6B43F22 /* IMYWebPrefetchHandlerDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A38C68E14CB0D7585B9EA83520863D2 /* IMYWebPrefetchHandlerDefaultImpl.m */; }; 89CC7BF2CEDA8E3BA62E223D882C5077 /* IMYWebUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C36820FD94D18405C045A443E8B7F589 /* IMYWebUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8EBCC077E0EFE525744B39BBFA3ACF08 /* XMLDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = BAA08F978C199208824F5C0AD0B1826D /* XMLDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; }; A2391408122F34925E05D113F64067DB /* IMYWebPrefetchHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 27C8F6576ECEF8D8FDE4BD6CB081DACC /* IMYWebPrefetchHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; A626681A504BCD5C042A806841A1FFC1 /* IMYWebNetworkHandlerDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 685466DEEC203371A152EE727B509A37 /* IMYWebNetworkHandlerDefaultImpl.m */; }; A95F7473CFD005F301C85DCE159DD62E /* IMYWebAjaxHandlerDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 094F14BF7FDFF3383E755F3C81C10B00 /* IMYWebAjaxHandlerDefaultImpl.m */; }; AE9F6F0011CBD0EC0A2C97565BC0CD72 /* IMYWebCacheHandlerDefaultImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 13A867AD455B01AA6393B4DBF1748626 /* IMYWebCacheHandlerDefaultImpl.h */; settings = {ATTRIBUTES = (Public, ); }; }; BAFBED3F5D9130823C222B61FBCB18CA /* WKUserContentController+IMYHookAjax.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FB6750E8F06E61EB6FF8EDFF88482EC /* WKUserContentController+IMYHookAjax.m */; }; CDEA55387077D27A7A826E542A2C3A2D /* IMYWebRequestHandleManagerDefaultImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = FC92C42DEC67C24F091E2F178D9F7D06 /* IMYWebRequestHandleManagerDefaultImpl.h */; settings = {ATTRIBUTES = (Public, ); }; }; D38DF02BBAA79F133E3EDCBEDA385DC6 /* IMYWebURLProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 343CEC2DFCD0883F7C92F15721883C6B /* IMYWebURLProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; D891C74C7D4C6DC141BDD41BED948F89 /* IMYWebRequestHandlerDefaultImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = C4BF8FB2355C9D40E51BA4E990E8BE0B /* IMYWebRequestHandlerDefaultImpl.h */; settings = {ATTRIBUTES = (Public, ); }; }; E13C3BC3E18442DCB64581CBE0DC4CFB /* IMYWebLoader+Impl.h in Headers */ = {isa = PBXBuildFile; fileRef = ACFF942CBE3C5683AC2E28FE70D4A27A /* IMYWebLoader+Impl.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB2BD6410EC057086C9636D555389FDD /* IMYWebCacheHandlerDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E17B39DDF2A484F9EB8BA8731D15ACD /* IMYWebCacheHandlerDefaultImpl.m */; }; F603231EDEF9DF53984C7FD60B34434A /* IMYWebOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 9018A400B7943ADD659A698352B06C89 /* IMYWebOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; F93C03442B4C7AA2EA67433D1FF97266 /* IMYWebLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F555E0AD9A5C533E4F2ADCDA9576A6 /* IMYWebLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; FB14628CCCCC8504854E13224E2532D3 /* IMYWebRequestHandleManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1792D41186D051341509C323CD5FEDAB /* IMYWebRequestHandleManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; FBB4661C8C2C3F8BC82F7C4A5A888267 /* IMYWebURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = D367B93F5860EBC39008EC0363C67C2C /* IMYWebURLProtocol.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 63CEC978B4479414747C699CE608E9FA /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = E8A71840FB9E9E20AD215722C2DE5F4F; remoteInfo = XMLDictionary; }; CFB636C1D56C964C27F70E7C18219108 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = CCEB5A5E4179EE67B3A38CDB55083BC8; remoteInfo = IMYWebLoader; }; D7F73BB0ED48B3EBFAF0CD5B58EA15E5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = E8A71840FB9E9E20AD215722C2DE5F4F; remoteInfo = XMLDictionary; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 04BA1C58D435CB2A9029BE02E8789909 /* Pods-IMYWebLoader.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-IMYWebLoader.debug.xcconfig"; sourceTree = ""; }; 05C70FCBA7C1CA0F7C708F4320CAC383 /* IMYWebAjaxHandler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebAjaxHandler.h; sourceTree = ""; }; 094F14BF7FDFF3383E755F3C81C10B00 /* IMYWebAjaxHandlerDefaultImpl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = IMYWebAjaxHandlerDefaultImpl.m; sourceTree = ""; }; 0A6B6D4CFCEADAEC7FCB92D162F4981E /* NSObject+WKCustomProtocolLoader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "NSObject+WKCustomProtocolLoader.m"; sourceTree = ""; }; 0F675D06FB5B17B7D7FCFEF44A7DB3EA /* WKUserContentController+IMYHookAjax.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "WKUserContentController+IMYHookAjax.h"; sourceTree = ""; }; 13A867AD455B01AA6393B4DBF1748626 /* IMYWebCacheHandlerDefaultImpl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebCacheHandlerDefaultImpl.h; sourceTree = ""; }; 169B28CBA254ED18ED7D3572533C91F3 /* XMLDictionary-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "XMLDictionary-dummy.m"; sourceTree = ""; }; 16F857CDF7EC83CF372AAA1E75343DB2 /* IMYWebLoader-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "IMYWebLoader-prefix.pch"; sourceTree = ""; }; 1792D41186D051341509C323CD5FEDAB /* IMYWebRequestHandleManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebRequestHandleManager.h; sourceTree = ""; }; 27C8F6576ECEF8D8FDE4BD6CB081DACC /* IMYWebPrefetchHandler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebPrefetchHandler.h; sourceTree = ""; }; 2A6976A248C051C88E83FF9B656A771E /* IMYWebNetworkHandlerDefaultImpl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebNetworkHandlerDefaultImpl.h; sourceTree = ""; }; 2C53C75BF246ADB8AA5611CC9F8F7181 /* IMYWebLoader.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = IMYWebLoader.xcconfig; sourceTree = ""; }; 343CEC2DFCD0883F7C92F15721883C6B /* IMYWebURLProtocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebURLProtocol.h; sourceTree = ""; }; 3A38C68E14CB0D7585B9EA83520863D2 /* IMYWebPrefetchHandlerDefaultImpl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = IMYWebPrefetchHandlerDefaultImpl.m; sourceTree = ""; }; 3E17B39DDF2A484F9EB8BA8731D15ACD /* IMYWebCacheHandlerDefaultImpl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = IMYWebCacheHandlerDefaultImpl.m; sourceTree = ""; }; 4EBAB6513E884072F16D57BBAE9057E1 /* Pods-IMYWebLoader-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-IMYWebLoader-dummy.m"; sourceTree = ""; }; 572F54EE9EBB713EEF7655E94000E667 /* Pods-IMYWebLoader-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-IMYWebLoader-acknowledgements.markdown"; sourceTree = ""; }; 607D3E9F26852D2EDD805CDE342E65EA /* IMYWebLoader-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "IMYWebLoader-dummy.m"; sourceTree = ""; }; 685466DEEC203371A152EE727B509A37 /* IMYWebNetworkHandlerDefaultImpl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = IMYWebNetworkHandlerDefaultImpl.m; sourceTree = ""; }; 6D1A0E5AFB90930B638BB83B1FF4184D /* XMLDictionary-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "XMLDictionary-prefix.pch"; sourceTree = ""; }; 6E73F934D6659D2F14126867C0877784 /* Pods-IMYWebLoader-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-IMYWebLoader-acknowledgements.plist"; sourceTree = ""; }; 6FD0817A11C996A0CA63088FAE30AC53 /* IMYWebCacheHandler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebCacheHandler.h; sourceTree = ""; }; 7103D1FAD6CCBB103036ED571878E985 /* imywk_hookajax.js */ = {isa = PBXFileReference; includeInIndex = 1; path = imywk_hookajax.js; sourceTree = ""; }; 7FB6750E8F06E61EB6FF8EDFF88482EC /* WKUserContentController+IMYHookAjax.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "WKUserContentController+IMYHookAjax.m"; sourceTree = ""; }; 83E4BA401FF36F4113838FDF4605E109 /* IMYWebData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = IMYWebData.m; sourceTree = ""; }; 860EF35475208355554ABDCF2F64FE77 /* Pods-IMYWebLoader.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-IMYWebLoader.release.xcconfig"; sourceTree = ""; }; 8A4764B6ACA37506631A3877D6E6E660 /* IMYWebLoader+Impl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "IMYWebLoader+Impl.m"; sourceTree = ""; }; 9018A400B7943ADD659A698352B06C89 /* IMYWebOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebOperation.h; sourceTree = ""; }; 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 95270427F9DA32931F1AADFD7E425AA5 /* libXMLDictionary.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libXMLDictionary.a; path = libXMLDictionary.a; sourceTree = BUILT_PRODUCTS_DIR; }; 9D93B3F4C8FB9DE0DFBAB64B3DAA08A0 /* XMLDictionary.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = XMLDictionary.xcconfig; sourceTree = ""; }; ACFF942CBE3C5683AC2E28FE70D4A27A /* IMYWebLoader+Impl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "IMYWebLoader+Impl.h"; sourceTree = ""; }; AE9A2574FC1CE0C1D33DB6F741D4BDBD /* IMYWebRequestHandleManagerDefaultImpl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = IMYWebRequestHandleManagerDefaultImpl.m; sourceTree = ""; }; AF22F8742322EB29FF7FE5A004DD98E9 /* IMYWebRequestHandlerDefaultImpl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = IMYWebRequestHandlerDefaultImpl.m; sourceTree = ""; }; AF7055851C79D40C4D2601C30D6422F1 /* IMYWebDefines.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebDefines.h; sourceTree = ""; }; B3F555E0AD9A5C533E4F2ADCDA9576A6 /* IMYWebLoader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebLoader.h; sourceTree = ""; }; B6772EDBE07BECC489A276FD7E267933 /* IMYWebData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebData.h; sourceTree = ""; }; BAA08F978C199208824F5C0AD0B1826D /* XMLDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = XMLDictionary.h; path = XMLDictionary/XMLDictionary.h; sourceTree = ""; }; BDD2B876D28BBE83C596DF885C9994BD /* Pods-IMYWebLoader-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-IMYWebLoader-frameworks.sh"; sourceTree = ""; }; C3151AE5832162BBA2E875782D30D4CA /* IMYWebPrefetchHandlerDefaultImpl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebPrefetchHandlerDefaultImpl.h; sourceTree = ""; }; C36820FD94D18405C045A443E8B7F589 /* IMYWebUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebUtils.h; sourceTree = ""; }; C3DD8EC76B96681EFD339E4BDC337F6A /* IMYWebAjaxHandlerDefaultImpl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebAjaxHandlerDefaultImpl.h; sourceTree = ""; }; C4BF8FB2355C9D40E51BA4E990E8BE0B /* IMYWebRequestHandlerDefaultImpl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebRequestHandlerDefaultImpl.h; sourceTree = ""; }; C7EDC5D569D587B03CFFA90E3206EBB7 /* IMYWebNetworkHandler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebNetworkHandler.h; sourceTree = ""; }; CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; CC403DCCADAF30EA6311CE68ED86AAF9 /* libIMYWebLoader.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libIMYWebLoader.a; path = libIMYWebLoader.a; sourceTree = BUILT_PRODUCTS_DIR; }; D367B93F5860EBC39008EC0363C67C2C /* IMYWebURLProtocol.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = IMYWebURLProtocol.m; sourceTree = ""; }; D4822E3EFC2DBE89F4DB43D54B1E5ED3 /* XMLDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = XMLDictionary.m; path = XMLDictionary/XMLDictionary.m; sourceTree = ""; }; D563AD4C2CB1406C681C506145FC62EB /* NSObject+WKCustomProtocolLoader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "NSObject+WKCustomProtocolLoader.h"; sourceTree = ""; }; E79EF483B6072452810534CB71B212BC /* Pods-IMYWebLoader-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-IMYWebLoader-resources.sh"; sourceTree = ""; }; E7B5D2BEBA31696095327500F9698EFD /* IMYWebUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = IMYWebUtils.m; sourceTree = ""; }; FA5D495661FAD88E273BE512814F3764 /* libPods-IMYWebLoader.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libPods-IMYWebLoader.a"; path = "libPods-IMYWebLoader.a"; sourceTree = BUILT_PRODUCTS_DIR; }; FC92C42DEC67C24F091E2F178D9F7D06 /* IMYWebRequestHandleManagerDefaultImpl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = IMYWebRequestHandleManagerDefaultImpl.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 19C6C87F901CC82DED0D07368255C9C7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5E1E68C8572414657003AB24D8562B5F /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; AA5EDE9B22F5F0CC997DAE5E3B420212 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5A63288A557273DE6BC51B518DE95241 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; F6597C59544BE77DBFCC4883D93F5A5B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 6FB88E598D5AC9A33828EFBF27BCD260 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 0AD3903B20B531B8FF8C02CD8A179B59 /* Public */ = { isa = PBXGroup; children = ( B3F555E0AD9A5C533E4F2ADCDA9576A6 /* IMYWebLoader.h */, 64904A2674266F7D056BE9CA7C210BF5 /* Data */, C6BDFFF6969FC266E6FBE1996584D5AE /* Handler */, BCA56F2061B7E6B3A88E7DA46A5FAB5D /* Header */, ); name = Public; path = Public; sourceTree = ""; }; 0BCA4367372A60D111C570818D82AA54 /* HookAjax */ = { isa = PBXGroup; children = ( C3DD8EC76B96681EFD339E4BDC337F6A /* IMYWebAjaxHandlerDefaultImpl.h */, 094F14BF7FDFF3383E755F3C81C10B00 /* IMYWebAjaxHandlerDefaultImpl.m */, 7FB6750E8F06E61EB6FF8EDFF88482EC /* WKUserContentController+IMYHookAjax.m */, ); name = HookAjax; path = HookAjax; sourceTree = ""; }; 2D43004A1A47B3CF4D2F51CE38EC8C72 /* Handler */ = { isa = PBXGroup; children = ( 13A867AD455B01AA6393B4DBF1748626 /* IMYWebCacheHandlerDefaultImpl.h */, 3E17B39DDF2A484F9EB8BA8731D15ACD /* IMYWebCacheHandlerDefaultImpl.m */, 2A6976A248C051C88E83FF9B656A771E /* IMYWebNetworkHandlerDefaultImpl.h */, 685466DEEC203371A152EE727B509A37 /* IMYWebNetworkHandlerDefaultImpl.m */, C3151AE5832162BBA2E875782D30D4CA /* IMYWebPrefetchHandlerDefaultImpl.h */, 3A38C68E14CB0D7585B9EA83520863D2 /* IMYWebPrefetchHandlerDefaultImpl.m */, ); name = Handler; path = Handler; sourceTree = ""; }; 2F48A9088B50D7D21F8E4033404AC906 /* Sources */ = { isa = PBXGroup; children = ( F969E99F15E7E7C4DBF2B480483A26EE /* Private */, 0AD3903B20B531B8FF8C02CD8A179B59 /* Public */, ); name = Sources; path = Sources; sourceTree = ""; }; 38CAC811CFDAAD6E81BD56D690D8A365 /* URLProtocol */ = { isa = PBXGroup; children = ( FC92C42DEC67C24F091E2F178D9F7D06 /* IMYWebRequestHandleManagerDefaultImpl.h */, AE9A2574FC1CE0C1D33DB6F741D4BDBD /* IMYWebRequestHandleManagerDefaultImpl.m */, C4BF8FB2355C9D40E51BA4E990E8BE0B /* IMYWebRequestHandlerDefaultImpl.h */, AF22F8742322EB29FF7FE5A004DD98E9 /* IMYWebRequestHandlerDefaultImpl.m */, 343CEC2DFCD0883F7C92F15721883C6B /* IMYWebURLProtocol.h */, D367B93F5860EBC39008EC0363C67C2C /* IMYWebURLProtocol.m */, D563AD4C2CB1406C681C506145FC62EB /* NSObject+WKCustomProtocolLoader.h */, 0A6B6D4CFCEADAEC7FCB92D162F4981E /* NSObject+WKCustomProtocolLoader.m */, ); name = URLProtocol; path = URLProtocol; sourceTree = ""; }; 391DF87CB0227C44FDD3CC3A52660E1F /* IMYWebLoader */ = { isa = PBXGroup; children = ( A99954895AAFB09C3690B0DED3F4D4C1 /* Resources */, 2F48A9088B50D7D21F8E4033404AC906 /* Sources */, 63429788802BB9F85BE627675864C0D5 /* Support Files */, ); name = IMYWebLoader; path = ../..; sourceTree = ""; }; 5503AA63D695479613CE4A40DB8C3FAF /* Support Files */ = { isa = PBXGroup; children = ( 9D93B3F4C8FB9DE0DFBAB64B3DAA08A0 /* XMLDictionary.xcconfig */, 169B28CBA254ED18ED7D3572533C91F3 /* XMLDictionary-dummy.m */, 6D1A0E5AFB90930B638BB83B1FF4184D /* XMLDictionary-prefix.pch */, ); name = "Support Files"; path = "../Target Support Files/XMLDictionary"; sourceTree = ""; }; 63429788802BB9F85BE627675864C0D5 /* Support Files */ = { isa = PBXGroup; children = ( 2C53C75BF246ADB8AA5611CC9F8F7181 /* IMYWebLoader.xcconfig */, 607D3E9F26852D2EDD805CDE342E65EA /* IMYWebLoader-dummy.m */, 16F857CDF7EC83CF372AAA1E75343DB2 /* IMYWebLoader-prefix.pch */, ); name = "Support Files"; path = "Demo/Pods/Target Support Files/IMYWebLoader"; sourceTree = ""; }; 64904A2674266F7D056BE9CA7C210BF5 /* Data */ = { isa = PBXGroup; children = ( B6772EDBE07BECC489A276FD7E267933 /* IMYWebData.h */, 83E4BA401FF36F4113838FDF4605E109 /* IMYWebData.m */, ); name = Data; path = Data; sourceTree = ""; }; 6AE9E238E700AEF2865A52BD08FDE28C /* Pods */ = { isa = PBXGroup; children = ( B0BFC7E6B5651385A2A56765D2F7E3E5 /* XMLDictionary */, ); name = Pods; sourceTree = ""; }; 6C96B80B90DD989FF5C36A2DA4D01287 /* Pods-IMYWebLoader */ = { isa = PBXGroup; children = ( 572F54EE9EBB713EEF7655E94000E667 /* Pods-IMYWebLoader-acknowledgements.markdown */, 6E73F934D6659D2F14126867C0877784 /* Pods-IMYWebLoader-acknowledgements.plist */, 4EBAB6513E884072F16D57BBAE9057E1 /* Pods-IMYWebLoader-dummy.m */, BDD2B876D28BBE83C596DF885C9994BD /* Pods-IMYWebLoader-frameworks.sh */, E79EF483B6072452810534CB71B212BC /* Pods-IMYWebLoader-resources.sh */, 04BA1C58D435CB2A9029BE02E8789909 /* Pods-IMYWebLoader.debug.xcconfig */, 860EF35475208355554ABDCF2F64FE77 /* Pods-IMYWebLoader.release.xcconfig */, ); name = "Pods-IMYWebLoader"; path = "Target Support Files/Pods-IMYWebLoader"; sourceTree = ""; }; 710772FAC4DE91299239BC29BF6D5501 /* Utils */ = { isa = PBXGroup; children = ( C36820FD94D18405C045A443E8B7F589 /* IMYWebUtils.h */, E7B5D2BEBA31696095327500F9698EFD /* IMYWebUtils.m */, ); name = Utils; path = Utils; sourceTree = ""; }; 7531C8F8DE19F1AA3C8A7AC97A91DC29 /* iOS */ = { isa = PBXGroup; children = ( CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */, ); name = iOS; sourceTree = ""; }; 7DB346D0F39D3F0E887471402A8071AB = { isa = PBXGroup; children = ( 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, B6295907AC34F746B0DF2A9EB860FE5E /* Development Pods */, BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */, 6AE9E238E700AEF2865A52BD08FDE28C /* Pods */, BB667D5BB4DF4917D340D0E6C81114DB /* Products */, A4E5A9ABEFF1416D6FC2869E01F6761F /* Targets Support Files */, ); sourceTree = ""; }; 892E878067BC7E26ED58C94042210329 /* Loader */ = { isa = PBXGroup; children = ( ACFF942CBE3C5683AC2E28FE70D4A27A /* IMYWebLoader+Impl.h */, 8A4764B6ACA37506631A3877D6E6E660 /* IMYWebLoader+Impl.m */, ); name = Loader; path = Loader; sourceTree = ""; }; 8F409B7A246ED1DD4274B2318AB604A5 /* Sources */ = { isa = PBXGroup; children = ( D8C4D965C9F91FB3005CAC0F851634D0 /* Resources */, ); name = Sources; path = Sources; sourceTree = ""; }; A4E5A9ABEFF1416D6FC2869E01F6761F /* Targets Support Files */ = { isa = PBXGroup; children = ( 6C96B80B90DD989FF5C36A2DA4D01287 /* Pods-IMYWebLoader */, ); name = "Targets Support Files"; sourceTree = ""; }; A99954895AAFB09C3690B0DED3F4D4C1 /* Resources */ = { isa = PBXGroup; children = ( 8F409B7A246ED1DD4274B2318AB604A5 /* Sources */, ); name = Resources; sourceTree = ""; }; B0BFC7E6B5651385A2A56765D2F7E3E5 /* XMLDictionary */ = { isa = PBXGroup; children = ( BAA08F978C199208824F5C0AD0B1826D /* XMLDictionary.h */, D4822E3EFC2DBE89F4DB43D54B1E5ED3 /* XMLDictionary.m */, 5503AA63D695479613CE4A40DB8C3FAF /* Support Files */, ); name = XMLDictionary; path = XMLDictionary; sourceTree = ""; }; B6295907AC34F746B0DF2A9EB860FE5E /* Development Pods */ = { isa = PBXGroup; children = ( 391DF87CB0227C44FDD3CC3A52660E1F /* IMYWebLoader */, ); name = "Development Pods"; sourceTree = ""; }; BB667D5BB4DF4917D340D0E6C81114DB /* Products */ = { isa = PBXGroup; children = ( CC403DCCADAF30EA6311CE68ED86AAF9 /* libIMYWebLoader.a */, FA5D495661FAD88E273BE512814F3764 /* libPods-IMYWebLoader.a */, 95270427F9DA32931F1AADFD7E425AA5 /* libXMLDictionary.a */, ); name = Products; sourceTree = ""; }; BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */ = { isa = PBXGroup; children = ( 7531C8F8DE19F1AA3C8A7AC97A91DC29 /* iOS */, ); name = Frameworks; sourceTree = ""; }; BCA56F2061B7E6B3A88E7DA46A5FAB5D /* Header */ = { isa = PBXGroup; children = ( AF7055851C79D40C4D2601C30D6422F1 /* IMYWebDefines.h */, 9018A400B7943ADD659A698352B06C89 /* IMYWebOperation.h */, 0F675D06FB5B17B7D7FCFEF44A7DB3EA /* WKUserContentController+IMYHookAjax.h */, ); name = Header; path = Header; sourceTree = ""; }; C6BDFFF6969FC266E6FBE1996584D5AE /* Handler */ = { isa = PBXGroup; children = ( 05C70FCBA7C1CA0F7C708F4320CAC383 /* IMYWebAjaxHandler.h */, 6FD0817A11C996A0CA63088FAE30AC53 /* IMYWebCacheHandler.h */, C7EDC5D569D587B03CFFA90E3206EBB7 /* IMYWebNetworkHandler.h */, 27C8F6576ECEF8D8FDE4BD6CB081DACC /* IMYWebPrefetchHandler.h */, 1792D41186D051341509C323CD5FEDAB /* IMYWebRequestHandleManager.h */, ); name = Handler; path = Handler; sourceTree = ""; }; D8C4D965C9F91FB3005CAC0F851634D0 /* Resources */ = { isa = PBXGroup; children = ( 7103D1FAD6CCBB103036ED571878E985 /* imywk_hookajax.js */, ); name = Resources; path = Resources; sourceTree = ""; }; F969E99F15E7E7C4DBF2B480483A26EE /* Private */ = { isa = PBXGroup; children = ( 2D43004A1A47B3CF4D2F51CE38EC8C72 /* Handler */, 0BCA4367372A60D111C570818D82AA54 /* HookAjax */, 892E878067BC7E26ED58C94042210329 /* Loader */, 38CAC811CFDAAD6E81BD56D690D8A365 /* URLProtocol */, 710772FAC4DE91299239BC29BF6D5501 /* Utils */, ); name = Private; path = Private; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 0308E3DA32E83ED37A5DB3D3A6277FF7 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 393409694F95312098AD4CBCBBE9BE10 /* IMYWebAjaxHandler.h in Headers */, 56C34BD106D3F8AA93DD5E6AED7FBC7A /* IMYWebAjaxHandlerDefaultImpl.h in Headers */, 66C3480B3B6E130823872459A5199179 /* IMYWebCacheHandler.h in Headers */, AE9F6F0011CBD0EC0A2C97565BC0CD72 /* IMYWebCacheHandlerDefaultImpl.h in Headers */, 480DF9BEB028700172A6A4724B62ABB6 /* IMYWebData.h in Headers */, 10C5BD4EF83CC79057DE8177FEAE2699 /* IMYWebDefines.h in Headers */, E13C3BC3E18442DCB64581CBE0DC4CFB /* IMYWebLoader+Impl.h in Headers */, F93C03442B4C7AA2EA67433D1FF97266 /* IMYWebLoader.h in Headers */, 5F453934EDB30AC4945532BD82E32BB2 /* IMYWebNetworkHandler.h in Headers */, 41473B39D21EC87364AB4AD3605A4965 /* IMYWebNetworkHandlerDefaultImpl.h in Headers */, F603231EDEF9DF53984C7FD60B34434A /* IMYWebOperation.h in Headers */, A2391408122F34925E05D113F64067DB /* IMYWebPrefetchHandler.h in Headers */, 049125CCBD1E4E48E417C30880AA5E70 /* IMYWebPrefetchHandlerDefaultImpl.h in Headers */, FB14628CCCCC8504854E13224E2532D3 /* IMYWebRequestHandleManager.h in Headers */, CDEA55387077D27A7A826E542A2C3A2D /* IMYWebRequestHandleManagerDefaultImpl.h in Headers */, D891C74C7D4C6DC141BDD41BED948F89 /* IMYWebRequestHandlerDefaultImpl.h in Headers */, D38DF02BBAA79F133E3EDCBEDA385DC6 /* IMYWebURLProtocol.h in Headers */, 89CC7BF2CEDA8E3BA62E223D882C5077 /* IMYWebUtils.h in Headers */, 020FB6622AF33495BD84FAF17C229412 /* NSObject+WKCustomProtocolLoader.h in Headers */, 5B6AEB23A102D9197A955238B4E5292A /* WKUserContentController+IMYHookAjax.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 6043592D68D7CF44F3AB9BBBE65FE793 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 8EBCC077E0EFE525744B39BBFA3ACF08 /* XMLDictionary.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 6D36EB059E1F0FA769F14EB4A779D62C /* Pods-IMYWebLoader */ = { isa = PBXNativeTarget; buildConfigurationList = 1FC8E087C2455228045CA2758E9A24CC /* Build configuration list for PBXNativeTarget "Pods-IMYWebLoader" */; buildPhases = ( A745DADB2BF7481A22D63BDC20DEC541 /* Sources */, 19C6C87F901CC82DED0D07368255C9C7 /* Frameworks */, ); buildRules = ( ); dependencies = ( AE7F7B0FF105C7F4CBFC9D6216D86AD8 /* PBXTargetDependency */, BB3041077DE99DCB55708F26B7007FDC /* PBXTargetDependency */, ); name = "Pods-IMYWebLoader"; productName = "Pods-IMYWebLoader"; productReference = FA5D495661FAD88E273BE512814F3764 /* libPods-IMYWebLoader.a */; productType = "com.apple.product-type.library.static"; }; CCEB5A5E4179EE67B3A38CDB55083BC8 /* IMYWebLoader */ = { isa = PBXNativeTarget; buildConfigurationList = 93DF2762F24F62AC49443A55BA7B16AB /* Build configuration list for PBXNativeTarget "IMYWebLoader" */; buildPhases = ( AE11C0B05918784135F1BC0A0A955A79 /* Sources */, AA5EDE9B22F5F0CC997DAE5E3B420212 /* Frameworks */, 0308E3DA32E83ED37A5DB3D3A6277FF7 /* Headers */, ); buildRules = ( ); dependencies = ( FC33FC277DA4A267D0959FDA5E27BEE3 /* PBXTargetDependency */, ); name = IMYWebLoader; productName = IMYWebLoader; productReference = CC403DCCADAF30EA6311CE68ED86AAF9 /* libIMYWebLoader.a */; productType = "com.apple.product-type.library.static"; }; E8A71840FB9E9E20AD215722C2DE5F4F /* XMLDictionary */ = { isa = PBXNativeTarget; buildConfigurationList = 49A9703DCBD48D66885334E748917A64 /* Build configuration list for PBXNativeTarget "XMLDictionary" */; buildPhases = ( FC14A0DE2A45EF9CD1B139F119524419 /* Sources */, F6597C59544BE77DBFCC4883D93F5A5B /* Frameworks */, 6043592D68D7CF44F3AB9BBBE65FE793 /* Headers */, ); buildRules = ( ); dependencies = ( ); name = XMLDictionary; productName = XMLDictionary; productReference = 95270427F9DA32931F1AADFD7E425AA5 /* libXMLDictionary.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; LastUpgradeCheck = 0700; }; buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 7DB346D0F39D3F0E887471402A8071AB; productRefGroup = BB667D5BB4DF4917D340D0E6C81114DB /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( CCEB5A5E4179EE67B3A38CDB55083BC8 /* IMYWebLoader */, 6D36EB059E1F0FA769F14EB4A779D62C /* Pods-IMYWebLoader */, E8A71840FB9E9E20AD215722C2DE5F4F /* XMLDictionary */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ A745DADB2BF7481A22D63BDC20DEC541 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 2519C632856C0906596A037A5C4B9AD6 /* Pods-IMYWebLoader-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; AE11C0B05918784135F1BC0A0A955A79 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A95F7473CFD005F301C85DCE159DD62E /* IMYWebAjaxHandlerDefaultImpl.m in Sources */, EB2BD6410EC057086C9636D555389FDD /* IMYWebCacheHandlerDefaultImpl.m in Sources */, 4FB83EAD7E47C7699BC80817DC0B7787 /* IMYWebData.m in Sources */, 2C3A9DF7E9BEC4A02DBAC87DC32EDCA6 /* IMYWebLoader+Impl.m in Sources */, 163E102EB5C64542EA2EE28DAC02B294 /* IMYWebLoader-dummy.m in Sources */, A626681A504BCD5C042A806841A1FFC1 /* IMYWebNetworkHandlerDefaultImpl.m in Sources */, 8988814BA9CB2157B9F6D1A4D6B43F22 /* IMYWebPrefetchHandlerDefaultImpl.m in Sources */, 074A90D82FA3046A062867BD2A3544AE /* IMYWebRequestHandleManagerDefaultImpl.m in Sources */, 58C66C9AE971D25506FB21529C072CFD /* IMYWebRequestHandlerDefaultImpl.m in Sources */, FBB4661C8C2C3F8BC82F7C4A5A888267 /* IMYWebURLProtocol.m in Sources */, 4A9E995FFA4DF1755755069970F51066 /* IMYWebUtils.m in Sources */, 727B06978C5CBB50F80B45B88FE1148B /* NSObject+WKCustomProtocolLoader.m in Sources */, BAFBED3F5D9130823C222B61FBCB18CA /* WKUserContentController+IMYHookAjax.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; FC14A0DE2A45EF9CD1B139F119524419 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 0D7306FEABE5C52E9BD9222E515D17FC /* XMLDictionary-dummy.m in Sources */, 118703A0B27D8BE032448BF8E7218876 /* XMLDictionary.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ AE7F7B0FF105C7F4CBFC9D6216D86AD8 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = IMYWebLoader; target = CCEB5A5E4179EE67B3A38CDB55083BC8 /* IMYWebLoader */; targetProxy = CFB636C1D56C964C27F70E7C18219108 /* PBXContainerItemProxy */; }; BB3041077DE99DCB55708F26B7007FDC /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = XMLDictionary; target = E8A71840FB9E9E20AD215722C2DE5F4F /* XMLDictionary */; targetProxy = D7F73BB0ED48B3EBFAF0CD5B58EA15E5 /* PBXContainerItemProxy */; }; FC33FC277DA4A267D0959FDA5E27BEE3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = XMLDictionary; target = E8A71840FB9E9E20AD215722C2DE5F4F /* XMLDictionary */; targetProxy = 63CEC978B4479414747C699CE608E9FA /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 179CD57130FEECD73A4ACEE132CF28EE /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 2C53C75BF246ADB8AA5611CC9F8F7181 /* IMYWebLoader.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PREFIX_HEADER = "Target Support Files/IMYWebLoader/IMYWebLoader-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; }; name = Release; }; 783CB3AEAEB930FDC900204A28CFD711 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9D93B3F4C8FB9DE0DFBAB64B3DAA08A0 /* XMLDictionary.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PREFIX_HEADER = "Target Support Files/XMLDictionary/XMLDictionary-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 4.3; MTL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; }; name = Debug; }; 79B0C2E66EFA9917ED6EDDB8FC6A7684 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGNING_REQUIRED = NO; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_PREPROCESSOR_DEFINITIONS = ( "POD_CONFIGURATION_RELEASE=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; STRIP_INSTALLED_PRODUCT = NO; SYMROOT = "${SRCROOT}/../build"; VALIDATE_PRODUCT = YES; }; name = Release; }; A4B4F3E9FBF3648C96678BDB7503E047 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 04BA1C58D435CB2A9029BE02E8789909 /* Pods-IMYWebLoader.debug.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; }; name = Debug; }; B771A82457A70746785FC18B569EF9B7 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9D93B3F4C8FB9DE0DFBAB64B3DAA08A0 /* XMLDictionary.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PREFIX_HEADER = "Target Support Files/XMLDictionary/XMLDictionary-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 4.3; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; }; name = Release; }; CF1C3F20C6BAEA7A0B874DC4311C28D7 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 860EF35475208355554ABDCF2F64FE77 /* Pods-IMYWebLoader.release.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; }; name = Release; }; CF7953F66E785E8876EB4D370D777D50 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGNING_REQUIRED = NO; COPY_PHASE_STRIP = NO; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "POD_CONFIGURATION_DEBUG=1", "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; ONLY_ACTIVE_ARCH = YES; PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; STRIP_INSTALLED_PRODUCT = NO; SYMROOT = "${SRCROOT}/../build"; }; name = Debug; }; F4AB01876E18F63E248D80B66EC8EAFB /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 2C53C75BF246ADB8AA5611CC9F8F7181 /* IMYWebLoader.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PREFIX_HEADER = "Target Support Files/IMYWebLoader/IMYWebLoader-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MTL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; }; name = Debug; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 1FC8E087C2455228045CA2758E9A24CC /* Build configuration list for PBXNativeTarget "Pods-IMYWebLoader" */ = { isa = XCConfigurationList; buildConfigurations = ( A4B4F3E9FBF3648C96678BDB7503E047 /* Debug */, CF1C3F20C6BAEA7A0B874DC4311C28D7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( CF7953F66E785E8876EB4D370D777D50 /* Debug */, 79B0C2E66EFA9917ED6EDDB8FC6A7684 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 49A9703DCBD48D66885334E748917A64 /* Build configuration list for PBXNativeTarget "XMLDictionary" */ = { isa = XCConfigurationList; buildConfigurations = ( 783CB3AEAEB930FDC900204A28CFD711 /* Debug */, B771A82457A70746785FC18B569EF9B7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 93DF2762F24F62AC49443A55BA7B16AB /* Build configuration list for PBXNativeTarget "IMYWebLoader" */ = { isa = XCConfigurationList; buildConfigurations = ( F4AB01876E18F63E248D80B66EC8EAFB /* Debug */, 179CD57130FEECD73A4ACEE132CF28EE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; } ================================================ FILE: Demo/Pods/Target Support Files/IMYWebLoader/IMYWebLoader-dummy.m ================================================ #import @interface PodsDummy_IMYWebLoader : NSObject @end @implementation PodsDummy_IMYWebLoader @end ================================================ FILE: Demo/Pods/Target Support Files/IMYWebLoader/IMYWebLoader-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Demo/Pods/Target Support Files/IMYWebLoader/IMYWebLoader.xcconfig ================================================ CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/IMYWebLoader GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/IMYWebLoader" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/IMYWebLoader" "${PODS_ROOT}/Headers/Public/XMLDictionary" LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/XMLDictionary" OTHER_LDFLAGS = -weak_framework "JavaScriptCore" -weak_framework "WebKit" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES ================================================ FILE: Demo/Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader-acknowledgements.markdown ================================================ # Acknowledgements This application makes use of the following third party libraries: ## IMYWebLoader MIT License Copyright (c) 2017 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ## XMLDictionary XMLDictionary Copyright (C) 2011 Charcoal Design This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Generated by CocoaPods - https://cocoapods.org ================================================ FILE: Demo/Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader-acknowledgements.plist ================================================ PreferenceSpecifiers FooterText This application makes use of the following third party libraries: Title Acknowledgements Type PSGroupSpecifier FooterText MIT License Copyright (c) 2017 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License MIT Title IMYWebLoader Type PSGroupSpecifier FooterText XMLDictionary Copyright (C) 2011 Charcoal Design This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. License zlib Title XMLDictionary Type PSGroupSpecifier FooterText Generated by CocoaPods - https://cocoapods.org Title Type PSGroupSpecifier StringsTable Acknowledgements Title Acknowledgements ================================================ FILE: Demo/Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader-dummy.m ================================================ #import @interface PodsDummy_Pods_IMYWebLoader : NSObject @end @implementation PodsDummy_Pods_IMYWebLoader @end ================================================ FILE: Demo/Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader-frameworks.sh ================================================ #!/bin/sh set -e echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" install_framework() { if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then local source="${BUILT_PRODUCTS_DIR}/$1" elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" elif [ -r "$1" ]; then local source="$1" fi local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" if [ -L "${source}" ]; then echo "Symlinked..." source="$(readlink "${source}")" fi # use filter instead of exclude so missing patterns dont' throw errors echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" local basename basename="$(basename -s .framework "$1")" binary="${destination}/${basename}.framework/${basename}" if ! [ -r "$binary" ]; then binary="${destination}/${basename}" fi # Strip invalid architectures so "fat" simulator / device frameworks work on device if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then strip_invalid_archs "$binary" fi # Resign the code if required by the build settings to avoid unstable apps code_sign_if_enabled "${destination}/$(basename "$1")" # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then local swift_runtime_libs swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) for lib in $swift_runtime_libs; do echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" code_sign_if_enabled "${destination}/${lib}" done fi } # Signs a framework with the provided identity code_sign_if_enabled() { if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then # Use the current code_sign_identitiy echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\"" /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1" fi } # Strip invalid architectures strip_invalid_archs() { binary="$1" # Get architectures for current file archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" stripped="" for arch in $archs; do if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then # Strip non-valid architectures in-place lipo -remove "$arch" -output "$binary" "$binary" || exit 1 stripped="$stripped $arch" fi done if [[ "$stripped" ]]; then echo "Stripped $binary of architectures:$stripped" fi } ================================================ FILE: Demo/Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader-resources.sh ================================================ #!/bin/sh set -e mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt > "$RESOURCES_TO_COPY" XCASSET_FILES=() case "${TARGETED_DEVICE_FAMILY}" in 1,2) TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" ;; 1) TARGET_DEVICE_ARGS="--target-device iphone" ;; 2) TARGET_DEVICE_ARGS="--target-device ipad" ;; *) TARGET_DEVICE_ARGS="--target-device mac" ;; esac install_resource() { if [[ "$1" = /* ]] ; then RESOURCE_PATH="$1" else RESOURCE_PATH="${PODS_ROOT}/$1" fi if [[ ! -e "$RESOURCE_PATH" ]] ; then cat << EOM error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. EOM exit 1 fi case $RESOURCE_PATH in *.storyboard) echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} ;; *.xib) echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} ;; *.framework) echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" ;; *.xcdatamodel) echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" ;; *.xcdatamodeld) echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" ;; *.xcmappingmodel) echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" ;; *.xcassets) ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") ;; *) echo "$RESOURCE_PATH" echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" ;; esac } if [[ "$CONFIGURATION" == "Debug" ]]; then install_resource "../../Sources/Resources/imywk_hookajax.js" fi if [[ "$CONFIGURATION" == "Release" ]]; then install_resource "../../Sources/Resources/imywk_hookajax.js" fi mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" fi rm -f "$RESOURCES_TO_COPY" if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] then # Find all other xcassets (this unfortunately includes those of path pods and other targets). OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) while read line; do if [[ $line != "${PODS_ROOT}*" ]]; then XCASSET_FILES+=("$line") fi done <<<"$OTHER_XCASSETS" printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" fi ================================================ FILE: Demo/Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader.debug.xcconfig ================================================ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/IMYWebLoader" "${PODS_ROOT}/Headers/Public/XMLDictionary" LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/IMYWebLoader" "$PODS_CONFIGURATION_BUILD_DIR/XMLDictionary" OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/IMYWebLoader" -isystem "${PODS_ROOT}/Headers/Public/XMLDictionary" OTHER_LDFLAGS = $(inherited) -ObjC -l"IMYWebLoader" -l"XMLDictionary" -weak_framework "JavaScriptCore" -weak_framework "WebKit" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT}/Pods ================================================ FILE: Demo/Pods/Target Support Files/Pods-IMYWebLoader/Pods-IMYWebLoader.release.xcconfig ================================================ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/IMYWebLoader" "${PODS_ROOT}/Headers/Public/XMLDictionary" LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/IMYWebLoader" "$PODS_CONFIGURATION_BUILD_DIR/XMLDictionary" OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/IMYWebLoader" -isystem "${PODS_ROOT}/Headers/Public/XMLDictionary" OTHER_LDFLAGS = $(inherited) -ObjC -l"IMYWebLoader" -l"XMLDictionary" -weak_framework "JavaScriptCore" -weak_framework "WebKit" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT}/Pods ================================================ FILE: Demo/Pods/Target Support Files/XMLDictionary/XMLDictionary-dummy.m ================================================ #import @interface PodsDummy_XMLDictionary : NSObject @end @implementation PodsDummy_XMLDictionary @end ================================================ FILE: Demo/Pods/Target Support Files/XMLDictionary/XMLDictionary-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Demo/Pods/Target Support Files/XMLDictionary/XMLDictionary.xcconfig ================================================ CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/XMLDictionary GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/XMLDictionary" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/IMYWebLoader" "${PODS_ROOT}/Headers/Public/XMLDictionary" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES ================================================ FILE: Demo/Pods/XMLDictionary/LICENCE.md ================================================ XMLDictionary Copyright (C) 2011 Charcoal Design This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. ================================================ FILE: Demo/Pods/XMLDictionary/README.md ================================================ Purpose -------------- XMLDictionary is a class designed to simplify parsing and generating of XML on iOS and Mac OS. XMLDictionary is built on top of the NSXMLParser classes, but behaves more like a DOM-style parser rather than SAX parser, in that it creates a tree of objects rather than generating events at the start and end of each node. Unlike other DOM parsers, XMLDictionary does not attempt to replicate all of the nuances of the XML standard such as the ability to nest tags within text. If you need to represent something like an HTML document then XMLDictionary won't work for you. If you want to use XML as a data interchange format for passing nested data structures then XMLDictionary may well provide a simpler solution than other DOM-based parsers. Supported OS & SDK Versions ----------------------------- * Supported build target - iOS 10.2 / Mac OS 10.12 (Xcode 8.2, Apple LLVM compiler 8.0) * Earliest supported deployment target - iOS 8.0 / Mac OS 10.10 * Earliest compatible deployment target - iOS 4.3 / Mac OS 10.6 NOTE: 'Supported' means that the library has been tested with this version. 'Compatible' means that the library should work on this OS version (i.e. it doesn't rely on any unavailable SDK features) but is no longer being tested for compatibility and may require tweaking or bug fixes to run correctly. ARC Compatibility ------------------ As of version 1.1, XMLDictionary requires ARC. If you wish to use XMLDictionary in a non-ARC project, just add the -fobjc-arc compiler flag to the XMLDictionary.m class. To do this, go to the Build Phases tab in your target settings, open the Compile Sources group, double-click XMLDictionary.m in the list and type -fobjc-arc into the popover. If you wish to convert your whole project to ARC, comment out the #error line in XMLDictionary.m, then run the Edit > Refactor > Convert to Objective-C ARC... tool in Xcode and make sure all files that you wish to use ARC for (including XMLDictionary.m) are checked. Thread Safety -------------- XMLDictionary's methods should all be thread safe. It is safe to use multiple XMLDictionaryParsers concurrently on different threads, but it is not safe to call the same parser concurrently on multiple threads. Installation -------------- To use the XMLDictionary in an app, just drag the class files into your project. XMLDictionaryParser --------------------- The XMLDictionaryParser class is responsible for parsing an XML file into a dictionary. You don't normally need to use this class explicitly as you can just use the utility methods added to NSDictionary, however it can be useful if you want to modify the default parser settings. You can create new instances of XMLDictionaryParser if you need to use multiple different settings for different dictionaries. Once you have created an XMLDictionaryParser you can use the following methods to parse XML files using that specific parser instance: - (NSDictionary *)dictionaryWithData:(NSData *)data; - (NSDictionary *)dictionaryWithString:(NSString *)string; - (NSDictionary *)dictionaryWithFile:(NSString *)path; - (NSDictionary *)dictionaryWithParser:(NSXMLParser *)parser; Alternatively, you can simply modify the settings of `[XMLDictionaryParser sharedInstance]` to affect the settings for all dictionaries parsed subsequently using the NSDictionary category extension methods. Use the following properties to tweak the parsing behaviour: @property (nonatomic, assign) BOOL collapseTextNodes; If YES (the default value), tags that contain only text and have no children, attributes or comments will be collapsed into a single string object, simplifying traversal of the object tree. @property (nonatomic, assign) BOOL stripEmptyNodes; If YES (the default value), tags that are empty (have no children, attributes, text or comments) will be stripped. @property (nonatomic, assign) BOOL trimWhiteSpace; If YES (the default value), leading and trailing white space will be trimmed from text nodes, and text nodes containing only white space will be omitted from the dictionary. @property (nonatomic, assign) BOOL alwaysUseArrays; If `YES`, the every child node will be represented as an array, even if there is only one of them. This simplifies the logic needed to cope with properties that may be duplicated because you don't need to use `[value isKindOfClass:[NSArray class]]` to check the for the singular case. Defaults to `NO`. @property (nonatomic, assign) BOOL preserveComments; If `YES`, XML comments will be grouped into an array under the key `__comments` and can be accessed via the `comments` method. Defaults to `NO`. @property (nonatomic, assign) XMLDictionaryAttributesMode attributesMode; This property controls how XML attributes are handled. The default is `XMLDictionaryAttributesModePrefixed` meaning that attributes will be included in the dictionary, with an _ (underscore) prefix to avoid namespace collisions. Alternative values are `XMLDictionaryAttributesModeDictionary`, which will place all the attributes in a separate dictionary, `XMLDictionaryAttributesModeUnprefixed`, which includes the attributes without prefix (which may cause collisions with nodes) and `XMLDictionaryAttributesModeDiscard`, which will strip the attributes. @property (nonatomic, assign) XMLDictionaryNodeNameMode nodeNameMode; This property controls how the node name is handled. The default value is `XMLDictionaryNodeNameModeRootOnly`, meaning that the node name will only be included in the root dictionary (the names for the children can be inferred from the dictionary keys, but the `nodeName` method won't work for anything except the root node). Alternative values are `XMLDictionaryNodeNameModeAlways`, meaning that the node name will be included in the dictionary with the key `__name` (and can be accessed using the `nodeName`) method, or `XMLDictionaryNodeNameModeNever` which will never include the `__name' key. Category Methods ----------------- XMLDictionary extends NSDictionary with the following methods: + (NSDictionary *)dictionaryWithXMLParser:(NSParser *)parser; Create a new NSDictionary object from an existing NSXMLParser. Useful if fetching data through AFNetworking. + (NSDictionary *)dictionaryWithXMLData:(NSData *)data; Create a new NSDictionary object from XML-encoded data. + (NSDictionary *)dictionaryWithXMLString:(NSString *)string; Create a new NSDictionary object from XML-encoded string. + (NSDictionary *)dictionaryWithXMLFile:(NSString *)path; Create a new NSDictionary object from and XML-encoded file. - (NSString *)attributeForKey:(NSString *)key; Get the XML attribute for a given key (key name should not include prefix). - (NSDictionary *)attributes; Get a dictionary of all XML attributes for a given node's dictionary. If the node has no attributes then this will return nil. - (NSDictionary *)childNodes; Get a dictionary of all child nodes for a given node's dictionary. If multiple nodes have the same name they will be grouped into an array. If the node has no children then this will return nil. - (NSArray *)comments; Get an array of all comments for a given node. Note that the nesting relative to other nodes is not preserved. If the node has no comments then this will return nil. - (NSString *)nodeName; Get the name of the node. If the name is not known this will return nil. - (NSString *)innerText; Get the text content of the node. If the node has no text content, this will return nil; - (NSString *)innerXML; Get the contents of the node as an XML-encoded string. This XML string will not include the container node itself. - (NSString *)XMLString; Get the node and its content as an XML-encoded string. If the node name is not known, the top level tag will be called ``. - (NSArray *)arrayValueForKeyPath:(NSString *)keyPath; Works just like `valueForKeyPath:` except that the value returned will always be an array. So if there is only a single value, it will be returned as `@[value]`. - (NSString *)stringValueForKeyPath:(NSString *)keyPath; Works just like `valueForKeyPath:` except that the value returned will always be a string. So if the value is a dictionary, the text value of `innerText` will be returned, and if the value is an array, the first item will be returned. - (NSDictionary *)dictionaryValueForKeyPath:(NSString *)keyPath; Works just like `valueForKeyPath:` except that the value returned will always be a dictionary. So if the collapseTextNodes option is enabled and the value is a string, this will convert it back to a dictionary before returning, and if the value is an array, the first item will be returned. Usage -------- The simplest way to load an XML file is as follows: NSString *filePath = [[NSBundle mainBundle] pathForResource:@"someFile" ofType:@"xml"]; NSDictionary *xmlDoc = [NSDictionary dictionaryWithXMLFile:filePath]; You can then iterate over the dictionary as you would with any other object tree, e.g. one loaded from a Plist. To access nested nodes and attributes, you can use the valueForKeyPath syntax. For example to get the string value of `` from the following XML: Hello World Was his name-oh You would write: NSString *foo = [xmlDoc valueForKeyPath:@"bar.foo"]; The above examples assumes that you are using the default setting for `collapseTextNodes` and `alwaysUseArrays`. If `collapseTextNodes` is disabled then you would instead access ``'s value by writing: NSString *foo = [[xmlDoc valueForKeyPath:@"bar.foo"] innerText]; If the `alwaysUseArrays` option is enabled then would use one of the following, depending on the `collapseTextNodes` property: NSString *foo = [[xmlDoc valueForKeyPath:@"bar.foo"] firstObject]; NSString *foo = [[[xmlDoc valueForKeyPath:@"bar.foo"] firstObject] innerText]; To get the cliche attribute of `bar`, you could write: NSString *barCliche = [xmlDoc[@"bar] attributes][@"cliche"]; If the `attributesMode` is set to the default value of `XMLDictionaryAttributesModePrefixed` then you can also do this: NSString *barCliche = [xmlDoc valueForKeyPath:@"bar._cliche"]; Or if it is set to `XMLDictionaryAttributesModeUnprefixed` you would simply do this: NSString *barCliche = [xmlDoc valueForKeyPath:@"bar.cliche"]; Release Notes ---------------- Version 1.4.1 - Upgraded for Xcode 8.2 - Added tvOS and watchOS support to podspec Version 1.4 - Added dictionaryWithXMLParser: constructor method - Added wrapRootNode option as a nicer way to preserve root node name - No longer crashes if non-string values are used as keys or attributes - Now complies with the -Weverything warning level Version 1.3 - added stripEmptyNodes property (defaults to YES) - added arrayValueForKeyPath, stringValueForKeyPath and dictionaryValueForKeyPath methods to simplify working with data Version 1.2.2 - sharedInstance method no longer returns a new instance each time Version 1.2.1 - Removed isa reference, deprecated in iOS 7 Version 1.2 - Exposed XMLDictionaryParser object, which can be used to configure the parser - Parsing options can now be changed without modifying the library - Added option to always encode properties as arrays - `__name` and `__coment` keys are no longer included by default - Apostrophe is now encoded as `'` - removed `attributeForKey:` method Version 1.1 - Updated to use ARC - Added podspec Version 1.0 - Initial release ================================================ FILE: Demo/Pods/XMLDictionary/XMLDictionary/XMLDictionary.h ================================================ // // XMLDictionary.h // // Version 1.4.1 // // Created by Nick Lockwood on 15/11/2010. // Copyright 2010 Charcoal Design. All rights reserved. // // Get the latest version of XMLDictionary from here: // // https://github.com/nicklockwood/XMLDictionary // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source distribution. // #import #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis" NS_ASSUME_NONNULL_BEGIN typedef NS_ENUM(NSInteger, XMLDictionaryAttributesMode) { XMLDictionaryAttributesModePrefixed = 0, //default XMLDictionaryAttributesModeDictionary, XMLDictionaryAttributesModeUnprefixed, XMLDictionaryAttributesModeDiscard }; typedef NS_ENUM(NSInteger, XMLDictionaryNodeNameMode) { XMLDictionaryNodeNameModeRootOnly = 0, //default XMLDictionaryNodeNameModeAlways, XMLDictionaryNodeNameModeNever }; static NSString *const XMLDictionaryAttributesKey = @"__attributes"; static NSString *const XMLDictionaryCommentsKey = @"__comments"; static NSString *const XMLDictionaryTextKey = @"__text"; static NSString *const XMLDictionaryNodeNameKey = @"__name"; static NSString *const XMLDictionaryAttributePrefix = @"_"; @interface XMLDictionaryParser : NSObject + (XMLDictionaryParser *)sharedInstance; @property (nonatomic, assign) BOOL collapseTextNodes; // defaults to YES @property (nonatomic, assign) BOOL stripEmptyNodes; // defaults to YES @property (nonatomic, assign) BOOL trimWhiteSpace; // defaults to YES @property (nonatomic, assign) BOOL alwaysUseArrays; // defaults to NO @property (nonatomic, assign) BOOL preserveComments; // defaults to NO @property (nonatomic, assign) BOOL wrapRootNode; // defaults to NO @property (nonatomic, assign) XMLDictionaryAttributesMode attributesMode; @property (nonatomic, assign) XMLDictionaryNodeNameMode nodeNameMode; - (nullable NSDictionary *)dictionaryWithParser:(NSXMLParser *)parser; - (nullable NSDictionary *)dictionaryWithData:(NSData *)data; - (nullable NSDictionary *)dictionaryWithString:(NSString *)string; - (nullable NSDictionary *)dictionaryWithFile:(NSString *)path; @end @interface NSDictionary (XMLDictionary) + (nullable NSDictionary *)dictionaryWithXMLParser:(NSXMLParser *)parser; + (nullable NSDictionary *)dictionaryWithXMLData:(NSData *)data; + (nullable NSDictionary *)dictionaryWithXMLString:(NSString *)string; + (nullable NSDictionary *)dictionaryWithXMLFile:(NSString *)path; @property (nonatomic, readonly, copy, nullable) NSDictionary *attributes; @property (nonatomic, readonly, copy, nullable) NSDictionary *childNodes; @property (nonatomic, readonly, copy, nullable) NSArray *comments; @property (nonatomic, readonly, copy, nullable) NSString *nodeName; @property (nonatomic, readonly, copy, nullable) NSString *innerText; @property (nonatomic, readonly, copy) NSString *innerXML; @property (nonatomic, readonly, copy) NSString *XMLString; - (nullable NSArray *)arrayValueForKeyPath:(NSString *)keyPath; - (nullable NSString *)stringValueForKeyPath:(NSString *)keyPath; - (nullable NSDictionary *)dictionaryValueForKeyPath:(NSString *)keyPath; @end @interface NSString (XMLDictionary) @property (nonatomic, readonly, copy) NSString *XMLEncodedString; @end NS_ASSUME_NONNULL_END #pragma GCC diagnostic pop ================================================ FILE: Demo/Pods/XMLDictionary/XMLDictionary/XMLDictionary.m ================================================ // // XMLDictionary.m // // Version 1.4.1 // // Created by Nick Lockwood on 15/11/2010. // Copyright 2010 Charcoal Design. All rights reserved. // // Get the latest version of XMLDictionary from here: // // https://github.com/nicklockwood/XMLDictionary // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source distribution. // #import "XMLDictionary.h" #pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis" #pragma GCC diagnostic ignored "-Wpartial-availability" #pragma GCC diagnostic ignored "-Wdirect-ivar-access" #pragma GCC diagnostic ignored "-Wformat-non-iso" #pragma GCC diagnostic ignored "-Wgnu" #import #if !__has_feature(objc_arc) #error This class requires automatic reference counting #endif @interface XMLDictionaryParser () @property (nonatomic, strong) NSMutableDictionary *root; @property (nonatomic, strong) NSMutableArray *stack; @property (nonatomic, strong) NSMutableString *text; @end @implementation XMLDictionaryParser + (XMLDictionaryParser *)sharedInstance { static dispatch_once_t once; static XMLDictionaryParser *sharedInstance; dispatch_once(&once, ^{ sharedInstance = [[XMLDictionaryParser alloc] init]; }); return sharedInstance; } - (instancetype)init { if ((self = [super init])) { _collapseTextNodes = YES; _stripEmptyNodes = YES; _trimWhiteSpace = YES; _alwaysUseArrays = NO; _preserveComments = NO; _wrapRootNode = NO; } return self; } - (id)copyWithZone:(NSZone *)zone { XMLDictionaryParser *copy = [[[self class] allocWithZone:zone] init]; copy.collapseTextNodes = _collapseTextNodes; copy.stripEmptyNodes = _stripEmptyNodes; copy.trimWhiteSpace = _trimWhiteSpace; copy.alwaysUseArrays = _alwaysUseArrays; copy.preserveComments = _preserveComments; copy.attributesMode = _attributesMode; copy.nodeNameMode = _nodeNameMode; copy.wrapRootNode = _wrapRootNode; return copy; } - (NSDictionary *)dictionaryWithParser:(NSXMLParser *)parser { parser.delegate = self; [parser parse]; id result = _root; _root = nil; _stack = nil; _text = nil; return result; } - (NSDictionary *)dictionaryWithData:(NSData *)data { NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; return [self dictionaryWithParser:parser]; } - (NSDictionary *)dictionaryWithString:(NSString *)string { NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; return [self dictionaryWithData:data]; } - (NSDictionary *)dictionaryWithFile:(NSString *)path { NSData *data = [NSData dataWithContentsOfFile:path]; return [self dictionaryWithData:data]; } + (NSString *)XMLStringForNode:(id)node withNodeName:(NSString *)nodeName { if ([node isKindOfClass:[NSArray class]]) { NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:[node count]]; for (id individualNode in node) { [nodes addObject:[self XMLStringForNode:individualNode withNodeName:nodeName]]; } return [nodes componentsJoinedByString:@"\n"]; } else if ([node isKindOfClass:[NSDictionary class]]) { NSDictionary *attributes = [(NSDictionary *)node attributes]; NSMutableString *attributeString = [NSMutableString string]; [attributes enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, __unused BOOL *stop) { [attributeString appendFormat:@" %@=\"%@\"", key.description.XMLEncodedString, value.description.XMLEncodedString]; }]; NSString *innerXML = [node innerXML]; if (innerXML.length) { return [NSString stringWithFormat:@"<%1$@%2$@>%3$@", nodeName, attributeString, innerXML]; } else { return [NSString stringWithFormat:@"<%@%@/>", nodeName, attributeString]; } } else { return [NSString stringWithFormat:@"<%1$@>%2$@", nodeName, [node description].XMLEncodedString]; } } - (void)endText { if (_trimWhiteSpace) { _text = [[_text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] mutableCopy]; } if (_text.length) { NSMutableDictionary *top = _stack.lastObject; id existing = top[XMLDictionaryTextKey]; if ([existing isKindOfClass:[NSArray class]]) { [existing addObject:_text]; } else if (existing) { top[XMLDictionaryTextKey] = [@[existing, _text] mutableCopy]; } else { top[XMLDictionaryTextKey] = _text; } } _text = nil; } - (void)addText:(NSString *)text { if (!_text) { _text = [NSMutableString stringWithString:text]; } else { [_text appendString:text]; } } - (void)parser:(__unused NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName attributes:(NSDictionary *)attributeDict { [self endText]; NSMutableDictionary *node = [NSMutableDictionary dictionary]; switch (_nodeNameMode) { case XMLDictionaryNodeNameModeRootOnly: { if (!_root) { node[XMLDictionaryNodeNameKey] = elementName; } break; } case XMLDictionaryNodeNameModeAlways: { node[XMLDictionaryNodeNameKey] = elementName; break; } case XMLDictionaryNodeNameModeNever: { break; } } if (attributeDict.count) { switch (_attributesMode) { case XMLDictionaryAttributesModePrefixed: { for (NSString *key in attributeDict) { node[[XMLDictionaryAttributePrefix stringByAppendingString:key]] = attributeDict[key]; } break; } case XMLDictionaryAttributesModeDictionary: { node[XMLDictionaryAttributesKey] = attributeDict; break; } case XMLDictionaryAttributesModeUnprefixed: { [node addEntriesFromDictionary:attributeDict]; break; } case XMLDictionaryAttributesModeDiscard: { break; } } } if (!_root) { _root = node; _stack = [NSMutableArray arrayWithObject:node]; if (_wrapRootNode) { _root = [NSMutableDictionary dictionaryWithObject:_root forKey:elementName]; [_stack insertObject:_root atIndex:0]; } } else { NSMutableDictionary *top = _stack.lastObject; id existing = top[elementName]; if ([existing isKindOfClass:[NSArray class]]) { [(NSMutableArray *)existing addObject:node]; } else if (existing) { top[elementName] = [@[existing, node] mutableCopy]; } else if (_alwaysUseArrays) { top[elementName] = [NSMutableArray arrayWithObject:node]; } else { top[elementName] = node; } [_stack addObject:node]; } } - (NSString *)nameForNode:(NSDictionary *)node inDictionary:(NSDictionary *)dict { if (node.nodeName) { return node.nodeName; } else { for (NSString *name in dict) { id object = dict[name]; if (object == node) { return name; } else if ([object isKindOfClass:[NSArray class]] && [(NSArray *)object containsObject:node]) { return name; } } } return nil; } - (void)parser:(__unused NSXMLParser *)parser didEndElement:(__unused NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName { [self endText]; NSMutableDictionary *top = _stack.lastObject; [_stack removeLastObject]; if (!top.attributes && !top.childNodes && !top.comments) { NSMutableDictionary *newTop = _stack.lastObject; NSString *nodeName = [self nameForNode:top inDictionary:newTop]; if (nodeName) { id parentNode = newTop[nodeName]; NSString *innerText = top.innerText; if (innerText && _collapseTextNodes) { if ([parentNode isKindOfClass:[NSArray class]]) { parentNode[[parentNode count] - 1] = innerText; } else { newTop[nodeName] = innerText; } } else if (!innerText) { if (_stripEmptyNodes) { if ([parentNode isKindOfClass:[NSArray class]]) { [(NSMutableArray *)parentNode removeLastObject]; } else { [newTop removeObjectForKey:nodeName]; } } else if (!_collapseTextNodes) { top[XMLDictionaryTextKey] = @""; } } } } } - (void)parser:(__unused NSXMLParser *)parser foundCharacters:(NSString *)string { [self addText:string]; } - (void)parser:(__unused NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock { [self addText:[[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding]]; } - (void)parser:(__unused NSXMLParser *)parser foundComment:(NSString *)comment { if (_preserveComments) { NSMutableDictionary *top = _stack.lastObject; NSMutableArray *comments = top[XMLDictionaryCommentsKey]; if (!comments) { comments = [@[comment] mutableCopy]; top[XMLDictionaryCommentsKey] = comments; } else { [comments addObject:comment]; } } } @end @implementation NSDictionary(XMLDictionary) + (NSDictionary *)dictionaryWithXMLParser:(NSXMLParser *)parser { return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithParser:parser]; } + (NSDictionary *)dictionaryWithXMLData:(NSData *)data { return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithData:data]; } + (NSDictionary *)dictionaryWithXMLString:(NSString *)string { return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithString:string]; } + (NSDictionary *)dictionaryWithXMLFile:(NSString *)path { return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithFile:path]; } - (nullable NSDictionary *)attributes { NSDictionary *attributes = self[XMLDictionaryAttributesKey]; if (attributes) { return attributes.count? attributes: nil; } else { NSMutableDictionary *filteredDict = [NSMutableDictionary dictionaryWithDictionary:self]; [filteredDict removeObjectsForKeys:@[XMLDictionaryCommentsKey, XMLDictionaryTextKey, XMLDictionaryNodeNameKey]]; for (NSString *key in filteredDict.allKeys) { [filteredDict removeObjectForKey:key]; if ([key hasPrefix:XMLDictionaryAttributePrefix]) { filteredDict[[key substringFromIndex:XMLDictionaryAttributePrefix.length]] = self[key]; } } return filteredDict.count? filteredDict: nil; } return nil; } - (nullable NSDictionary *)childNodes { NSMutableDictionary *filteredDict = [self mutableCopy]; [filteredDict removeObjectsForKeys:@[XMLDictionaryAttributesKey, XMLDictionaryCommentsKey, XMLDictionaryTextKey, XMLDictionaryNodeNameKey]]; for (NSString *key in filteredDict.allKeys) { if ([key hasPrefix:XMLDictionaryAttributePrefix]) { [filteredDict removeObjectForKey:key]; } } return filteredDict.count? filteredDict: nil; } - (nullable NSArray *)comments { return self[XMLDictionaryCommentsKey]; } - (nullable NSString *)nodeName { return self[XMLDictionaryNodeNameKey]; } - (id)innerText { id text = self[XMLDictionaryTextKey]; if ([text isKindOfClass:[NSArray class]]) { return [text componentsJoinedByString:@"\n"]; } else { return text; } } - (NSString *)innerXML { NSMutableArray *nodes = [NSMutableArray array]; for (NSString *comment in [self comments]) { [nodes addObject:[NSString stringWithFormat:@"", [comment XMLEncodedString]]]; } NSDictionary *childNodes = [self childNodes]; for (NSString *key in childNodes) { [nodes addObject:[XMLDictionaryParser XMLStringForNode:childNodes[key] withNodeName:key]]; } NSString *text = [self innerText]; if (text) { [nodes addObject:[text XMLEncodedString]]; } return [nodes componentsJoinedByString:@"\n"]; } - (NSString *)XMLString { if (self.count == 1 && ![self nodeName]) { //ignore outermost dictionary return [self innerXML]; } else { return [XMLDictionaryParser XMLStringForNode:self withNodeName:[self nodeName] ?: @"root"]; } } - (nullable NSArray *)arrayValueForKeyPath:(NSString *)keyPath { id value = [self valueForKeyPath:keyPath]; if (value && ![value isKindOfClass:[NSArray class]]) { return @[value]; } return value; } - (nullable NSString *)stringValueForKeyPath:(NSString *)keyPath { id value = [self valueForKeyPath:keyPath]; if ([value isKindOfClass:[NSArray class]]) { value = ((NSArray *)value).firstObject; } if ([value isKindOfClass:[NSDictionary class]]) { return [(NSDictionary *)value innerText]; } return value; } - (nullable NSDictionary *)dictionaryValueForKeyPath:(NSString *)keyPath { id value = [self valueForKeyPath:keyPath]; if ([value isKindOfClass:[NSArray class]]) { value = [value count]? value[0]: nil; } if ([value isKindOfClass:[NSString class]]) { return @{XMLDictionaryTextKey: value}; } return value; } @end @implementation NSString (XMLDictionary) - (NSString *)XMLEncodedString { return [[[[[self stringByReplacingOccurrencesOfString:@"&" withString:@"&"] stringByReplacingOccurrencesOfString:@"<" withString:@"<"] stringByReplacingOccurrencesOfString:@">" withString:@">"] stringByReplacingOccurrencesOfString:@"\"" withString:@"""] stringByReplacingOccurrencesOfString:@"\'" withString:@"'"]; } @end ================================================ FILE: IMYWebLoader.podspec ================================================ Pod::Spec.new do |s| s.name = 'IMYWebLoader' s.version = '0.1' s.description = 'Web resources loading by Prefetch/Cache/Hook, Support UIWebView/WKWebView ... Orz' s.license = 'MIT' s.summary = '支持对 UIWebView/WKWebView 的资源, 进行 预加载、缓存、拦截 等操作 ... Orz' s.homepage = 'https://github.com/li6185377/IMYWebLoader' s.authors = { 'ljh' => '137249466@qq.com' } s.source = { :git => 'https://github.com/li6185377/IMYWebLoader.git', :tag => '0.1' } s.requires_arc = true s.ios.deployment_target = '7.0' s.source_files = 'Sources/Private/**/*.{h,m}', 'Sources/Public/**/*.{h,m}' s.resources = 'Sources/Resources/**/*.{js}' s.weak_frameworks = 'JavaScriptCore', 'WebKit' s.dependency 'XMLDictionary' end ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2017 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # IMYWebLoader 支持对 UIWebView/WKWebView 的资源, 进行 预加载、缓存、拦截 等操作 ... Orz ### 屁话 UIWebView 缓存控制这块本身很弱,几乎无法用系统API 来完成我们的扩展,于是大家找到了 NSURLProtcol 来进行缓存或者拦截的操作, 总体来说还是满足了大家的需求 iOS8 除了WKWebView 之后更是连 NSURLProtocol 都不支持了,还好 WebKit 是开源的,大家通过搜索发现了 通过注册 CustomScheme,来拦截相应scheme的请求,于是大家进行了 http、https 的拦截 但是由于 WebKit 源码的限制,request body 永远都没法互相传递, 通过大量尝试,使用 fishhook,hook c++虚函数,均已失败告终 最终放弃了在 Native 层的拦截 突然有一天... 突然想到 前端的 post body 请求,大都都是通过 XMLHttpRequest 来请求的,为何我不能在 JS 层去 hook 呢? (还在使用 from 表单的,就让它去屎吧) hook-ajax 可能支持的没那么全,遇到问题可以帮忙改改,然后提个 pull request (一般的AJAX请求 肯定都是没问题的啦) 懒得写 readme ... 了 ### 功能 - 支持对 UIWebView/WKWebView 的数据缓存 - 支持 WKWebView 带 request body 的 AJAX 请求 - 支持断网后阅读 - 支持预加载方法,直接解析 html,提前下载其中的静态资源 - 支持功能实现替换,没写死,都使用协议编程 - ... ### 参考 - [WKWebView 那些坑](https://mp.weixin.qq.com/s/rhYKLIbXOsUJC_n6dt9UfA)
- [WebKit::WKCustomProtocolLoader](https://github.com/WebKit/webkit/blob/11c7bf06fa29f362a5ebd620bca4b703dc7f733a/Source/WebKit2/UIProcess/Cocoa/LegacyCustomProtocolManagerClient.mm#L51) - [让 WKWebView 支持 NSURLProtocol](https://blog.yeatse.com/2016/10/26/support-nsurlprotocol-in-wkwebview) - [Hook-Ajax](https://github.com/wendux/Ajax-hook) ================================================ FILE: Sources/Private/Handler/IMYWebCacheHandlerDefaultImpl.h ================================================ // // IMYWebCacheHandlerDefaultImpl.h // Pods // // Created by ljh on 2017/2/28. // // #import #import "IMYWebCacheHandler.h" @interface IMYWebCacheHandlerDefaultImpl : NSObject @end ================================================ FILE: Sources/Private/Handler/IMYWebCacheHandlerDefaultImpl.m ================================================ // // IMYWebCacheHandlerDefaultImpl.m // Pods // // Created by ljh on 2017/2/28. // // #import "IMYWebCacheHandlerDefaultImpl.h" #import @interface IMYWebCacheHandlerDefaultImpl () @property (nonatomic, strong) NSCache *memCache; @property (nonatomic, strong) NSString *dirPath; @end @implementation IMYWebCacheHandlerDefaultImpl - (instancetype)init { self = [super init]; if (self) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); self.dirPath = [paths.firstObject stringByAppendingPathComponent:@"imy.web.default.cache"]; } return self; } - (void)applicationDidReceiveMemoryWarning { [self.memCache removeAllObjects]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (NSString *)cacheKeyForRequest:(NSURLRequest *)request { return request.URL.absoluteString; } - (NSString *)fileNameForKey:(NSString *)key { if (!key) { return @""; } NSData *data = [key dataUsingEncoding:NSUTF8StringEncoding]; // CC_SHA1_DIGEST_LENGTH : 20 uint8_t digest[20]; CC_SHA1(data.bytes, (unsigned int)data.length, digest); NSString *sha1 = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15], digest[16], digest[17], digest[18], digest[19]]; return sha1; } - (NSString *)filePathForKey:(NSString *)key { NSString *fileName = [self fileNameForKey:key]; NSFileManager *fileManager = [NSFileManager defaultManager]; if (![fileManager fileExistsAtPath:_dirPath]) { [fileManager createDirectoryAtPath:_dirPath withIntermediateDirectories:YES attributes:nil error:NULL]; } NSString *filePath = [_dirPath stringByAppendingPathComponent:fileName]; return filePath; } - (void)setData:(IMYWebData *)data forKey:(NSString *)key { [self.memCache setObject:data forKey:key]; NSString *filePath = [self filePathForKey:key]; NSData *fileData = nil; if (data) { fileData = [NSKeyedArchiver archivedDataWithRootObject:data]; } if (fileData) { [fileData writeToFile:filePath atomically:YES]; } else { [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil]; } } - (IMYWebData *)dataForKey:(NSString *)key { IMYWebData *data = [self.memCache objectForKey:key]; if (!data) { NSString *filePath = [self filePathForKey:key]; NSData *fileData = [NSData dataWithContentsOfFile:filePath]; if (fileData) { data = [NSKeyedUnarchiver unarchiveObjectWithData:fileData]; } } return data; } @end ================================================ FILE: Sources/Private/Handler/IMYWebNetworkHandlerDefaultImpl.h ================================================ // // IMYWebNetworkHandlerDefaultImpl.h // Pods // // Created by ljh on 2017/2/28. // // #import #import "IMYWebNetworkHandler.h" @interface IMYWebNetworkHandlerDefaultImpl : NSObject @end ================================================ FILE: Sources/Private/Handler/IMYWebNetworkHandlerDefaultImpl.m ================================================ // // IMYWebNetworkHandlerDefaultImpl.m // Pods // // Created by ljh on 2017/2/28. // // #import "IMYWebNetworkHandlerDefaultImpl.h" @implementation IMYWebNetworkHandlerDefaultImpl - (NSURLRequest *)requestWithString:(NSString *)urlString { NSURL *url = [NSURL URLWithString:urlString]; if (!url) { return nil; } NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30]; request.HTTPMethod = @"GET"; return request; } - (id)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable, NSURLResponse * _Nullable, NSError * _Nullable))completionHandler { NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:completionHandler]; [task resume]; return (id)task; } + (void)networkRequestThreadEntryPoint { @autoreleasepool { [[NSThread currentThread] setName:@"IMYWebNetworkThread"]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; [runLoop run]; } } - (NSThread *)networkRequestThread { static NSThread *_networkRequestThread = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{ _networkRequestThread = [[NSThread alloc] initWithTarget:[IMYWebNetworkHandlerDefaultImpl class] selector:@selector(networkRequestThreadEntryPoint) object:nil]; [_networkRequestThread start]; }); return _networkRequestThread; } @end ================================================ FILE: Sources/Private/Handler/IMYWebPrefetchHandlerDefaultImpl.h ================================================ // // IMYWebPrefetchHandlerDefaultImpl.h // Pods // // Created by ljh on 2017/2/28. // // #import #import "IMYWebPrefetchHandler.h" @interface IMYWebPrefetchHandlerDefaultImpl : NSObject @end ================================================ FILE: Sources/Private/Handler/IMYWebPrefetchHandlerDefaultImpl.m ================================================ // // IMYWebPrefetchHandlerDefaultImpl.m // Pods // // Created by ljh on 2017/2/28. // // #import "IMYWebPrefetchHandlerDefaultImpl.h" #import "XMLDictionary.h" #import "IMYWebLoader.h" #import "IMYWebUtils.h" @interface IMYWebPrefetchOperater : NSObject @property (nonatomic, copy) NSString *webUrl; @property (nonatomic, assign, getter=isComplated) BOOL complated; @property (nonatomic, weak) id operation; @property (nonatomic, strong) NSMutableDictionary *detailMaps; - (void)startLoading:(NSURLRequest *)request cacheKey:(NSString *)cacheKey; @end @interface IMYWebPrefetchHandlerDefaultImpl () @property (nonatomic, strong) NSMutableDictionary *webUrls; @end @implementation IMYWebPrefetchHandlerDefaultImpl - (instancetype)init { self = [super init]; if (self) { self.webUrls = [NSMutableDictionary dictionary]; } return self; } - (id)prefetchWebUrl:(NSString *)webUrl { if (!webUrl.length) { return nil; } id prefetcher = nil; @synchronized (self) { prefetcher = self.webUrls[webUrl]; //已存在,一次运行周期内 只预加载一次 if (prefetcher) { return prefetcher; } prefetcher = [self lockPrefetchHTMLDetail:webUrl]; } return prefetcher; } - (id)lockPrefetchHTMLDetail:(NSString *)urlString { NSURLRequest *request = [[IMYWebLoader defaultNetworkHandler] requestWithString:urlString]; if (!request) { return nil; } IMYWebPrefetchOperater *operater = [IMYWebPrefetchOperater new]; operater.webUrl = urlString; NSString *cacheKey = [[IMYWebLoader defaultCacheHandler] cacheKeyForRequest:request]; IMYWebData *data = [[IMYWebLoader defaultCacheHandler] dataForKey:cacheKey]; ///已有缓存 if (data) { operater.complated = YES; return operater; } [operater startLoading:request cacheKey:cacheKey]; return operater; } - (void)cancelAllPrefetcherLoading { @synchronized (self) { [self.webUrls enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, IMYWebPrefetchOperater * _Nonnull obj, BOOL * _Nonnull stop) { [obj cancel]; }]; } } - (void)removePrefetcherForWebUrl:(NSString *)webUrl { @synchronized (self) { [self.webUrls removeObjectForKey:webUrl]; } } @end @implementation IMYWebPrefetchOperater - (instancetype)init { self = [super init]; if (self) { self.detailMaps = [NSMutableDictionary dictionary]; } return self; } - (void)startLoading:(NSURLRequest *)request cacheKey:(NSString *)cacheKey { self.operation = [[IMYWebLoader defaultNetworkHandler] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (!data.length || error) { return; } NSInteger statusCode = 0; if ([response isKindOfClass:[NSHTTPURLResponse class]]) { statusCode = [(NSHTTPURLResponse *)response statusCode]; } if(statusCode < 200 || statusCode >= 300) { return; } NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; ///过滤可能的错误,html 文本长度过短,或者 内容包含 404错误字眼等 if (!html.length || [html containsString:@"404错误"] || [html containsString:@" 404 "]) { return; } IMYWebData *webData = [IMYWebData new]; webData.data = data; webData.response = response; webData.request = request; //数据缓存 [[IMYWebLoader defaultCacheHandler] setData:webData forKey:cacheKey]; ///标志已完成 self.complated = YES; ///加载静态资源 [self prefetchResourcesWithHTML:html baseURL:response.URL]; }]; } - (void)prefetchResourcesWithHTML:(NSString *)html baseURL:(NSURL *)baseURL { ///替换 换行符,正则没匹配 \n html = [html stringByReplacingOccurrencesOfString:@"\n" withString:@" "]; [self prefetchCSSWithHTML:html baseURL:baseURL]; [self prefetchScriptWithHTML:html baseURL:baseURL]; [self prefetchImagesWithHTML:html baseURL:baseURL]; } /// 没有导太多的 pods,只能手动写了 - (NSArray *)filter:(NSArray *)array block:(BOOL(^)(id element))block { if (!array || !block) { return [NSArray array]; } NSMutableArray *result = [NSMutableArray array]; [array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if (block(obj)) { [result addObject:obj]; } }]; return result; } - (void)prefetchCSSWithHTML:(NSString *)html baseURL:(NSURL *)baseURL { NSArray *urls = [self urlsWithHTML:html regular:[self cssHrefExpression] forKey:@"href" baseURL:baseURL]; urls = [self filter:urls block:^BOOL(id element) { return [element containsString:@".css"] || [element containsString:@".ico"]; }]; if (urls.count) { [self prefetchFileWithUrls:urls]; } } - (void)prefetchScriptWithHTML:(NSString *)html baseURL:(NSURL *)baseURL { NSArray *urls = [self urlsWithHTML:html regular:[self scriptSrcExpression] forKey:@"src" baseURL:baseURL]; urls = [self filter:urls block:^BOOL(id element) { return [element containsString:@".js"]; }]; if (urls.count) { [self prefetchFileWithUrls:urls]; } } - (void)prefetchFileWithUrls:(NSArray *)urls { @synchronized (self) { [self lockPrefetchFileWithUrls:urls]; } } - (void)lockPrefetchFileWithUrls:(NSArray *)urls { [urls enumerateObjectsUsingBlock:^(NSString *fileURL, NSUInteger idx, BOOL * _Nonnull stop) { IMYWebPrefetchOperater *operater = self.detailMaps[fileURL]; if (operater) { return ; } NSURLRequest *request = [[IMYWebLoader defaultNetworkHandler] requestWithString:fileURL]; if (!request) { return; } operater = [IMYWebPrefetchOperater new]; operater.webUrl = fileURL; self.detailMaps[fileURL] = operater; NSString *cacheKey = [[IMYWebLoader defaultCacheHandler] cacheKeyForRequest:request]; IMYWebData *data = [[IMYWebLoader defaultCacheHandler] dataForKey:cacheKey]; ///已有缓存 if (data) { operater.complated = YES; return; } operater.operation = [[IMYWebLoader defaultNetworkHandler] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (!data.length || error) { return; } NSInteger statusCode = 0; if ([response isKindOfClass:[NSHTTPURLResponse class]]) { statusCode = [(NSHTTPURLResponse *)response statusCode]; } if(statusCode < 200 || statusCode >= 300) { return; } NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; ///过滤可能的错误,html 文本长度过短,或者 内容包含 404错误字眼等 if ([html containsString:@"404错误"] || [html containsString:@" 404 "]) { return; } operater.complated = YES; IMYWebData *cacheData = [IMYWebData new]; cacheData.data = data; cacheData.response = response; cacheData.request = request; [[IMYWebLoader defaultCacheHandler] setData:cacheData forKey:cacheKey]; }]; }]; } - (void)prefetchImagesWithHTML:(NSString *)html baseURL:(NSURL *)baseURL { NSMutableArray *prefetchImages = [NSMutableArray array]; NSArray *imgArray = [self urlsWithHTML:html regular:[self imgSrcExpression] forKey:@"src" baseURL:baseURL]; if (imgArray.count > 3) { imgArray = [imgArray subarrayWithRange:NSMakeRange(0, 3)]; } if (imgArray.count) { [prefetchImages addObjectsFromArray:imgArray]; } NSArray *posterArray = [self urlsWithHTML:html regular:[self videoPosterExpression] forKey:@"poster" baseURL:baseURL]; if (posterArray.count) { [prefetchImages addObjectsFromArray:posterArray]; } [self prefetchFileWithUrls:prefetchImages]; } - (NSArray *)urlsWithHTML:(NSString *)html regular:(NSRegularExpression *)regular forKey:(NSString *)key baseURL:(NSURL *)baseURL { if (!html || !regular || !key) { return nil; } NSArray *results = [regular matchesInString:html options:0 range:NSMakeRange(0, html.length)]; NSMutableArray *urls = [NSMutableArray array]; [results enumerateObjectsUsingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSString *substring = [html substringWithRange:obj.range]; NSDictionary *xmlNode = [NSDictionary dictionaryWithXMLString:substring]; if (!xmlNode) { NSCharacterSet *whitespaces = [NSCharacterSet whitespaceCharacterSet]; NSArray *parts = [substring componentsSeparatedByCharactersInSet:whitespaces]; NSArray *filteredArray = [self filter:parts block:^BOOL(id element) { return [element hasPrefix:@"<"] || [element containsString:@"="] || [element hasSuffix:@">"]; }]; NSString *nodeString = [filteredArray componentsJoinedByString:@" "]; xmlNode = [NSDictionary dictionaryWithXMLString:nodeString]; } ///获取 src url __block NSString *srcURL = nil; [xmlNode enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull nodeName, NSString * _Nonnull nodeValue, BOOL * _Nonnull stop) { if ([nodeName hasSuffix:key] && [nodeValue isKindOfClass:[NSString class]] && nodeValue.length > 0) { srcURL = nodeValue; *stop = YES; } }]; srcURL = [IMYWebUtils URLWithString:srcURL baseURL:baseURL].absoluteString; if (srcURL) { [urls addObject:srcURL]; } }]; return urls; } - (NSRegularExpression *)cssHrefExpression { return [NSRegularExpression regularExpressionWithPattern:@"" options:0 error:nil]; } - (NSRegularExpression *)scriptSrcExpression { return [NSRegularExpression regularExpressionWithPattern:@"" options:0 error:nil]; } - (NSRegularExpression *)imgSrcExpression { return [NSRegularExpression regularExpressionWithPattern:@"" options:0 error:nil]; } - (NSRegularExpression *)videoPosterExpression { return [NSRegularExpression regularExpressionWithPattern:@"" options:0 error:nil]; } - (void)cancel { @synchronized (self) { if (self.operation) { [self.operation cancel]; self.operation = nil; } [self.detailMaps enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, IMYWebPrefetchOperater * _Nonnull obj, BOOL * _Nonnull stop) { [obj cancel]; }]; } } @end ================================================ FILE: Sources/Private/HookAjax/IMYWebAjaxHandlerDefaultImpl.h ================================================ // // IMYWebAjaxHandlerDefaultImpl.h // Pods // // Created by ljh on 2017/4/10. // // #import #import "IMYWebAjaxHandler.h" @interface IMYWebAjaxHandlerDefaultImpl : NSObject @end ================================================ FILE: Sources/Private/HookAjax/IMYWebAjaxHandlerDefaultImpl.m ================================================ // // IMYWebAjaxHandlerDefaultImpl.m // Pods // // Created by ljh on 2017/4/10. // // #import "IMYWebAjaxHandlerDefaultImpl.h" #import "IMYWebUtils.h" #import "IMYWebLoader.h" @implementation IMYWebAjaxHandlerDefaultImpl - (void)startWithMethod:(NSString *)method url:(NSString *)urlString baseURL:(NSURL *)baseURL headers:(NSDictionary *)headers body:(id)body completedBlock:(void (^)(NSInteger, NSDictionary * _Nullable, NSString * _Nullable))completedBlock { NSURL *URL = [IMYWebUtils URLWithString:urlString baseURL:baseURL]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30]; request.HTTPMethod = method.uppercaseString; if ([body isKindOfClass:[NSString class]]) { request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding]; } else if ([body isKindOfClass:[NSData class]]) { request.HTTPBody = body; } else if ([NSJSONSerialization isValidJSONObject:body]) { NSError *err = nil; request.HTTPBody = [NSJSONSerialization dataWithJSONObject:body options:0 error:&err]; } [request setAllHTTPHeaderFields:headers]; [[IMYWebLoader defaultNetworkHandler] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSHTTPURLResponse *httpResponse = nil; if ([response isKindOfClass:[NSHTTPURLResponse class]]) { httpResponse = (id)response; } NSDictionary *allHeaderFields = httpResponse.allHeaderFields; NSString *responseString = nil; if (data.length > 0) { responseString = [self responseStringWithData:data charset:allHeaderFields[@"Content-Type"]]; } if (completedBlock) { completedBlock(httpResponse.statusCode, allHeaderFields, responseString); } }]; } - (NSString *)responseStringWithData:(NSData *)data charset:(NSString *)charset { NSStringEncoding stringEncoding = NSUTF8StringEncoding; /// 对一些国内常见编码进行支持 charset = charset.lowercaseString; if ([charset containsString:@"gb2312"]) { stringEncoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000); } NSString *responseString = [[NSString alloc] initWithData:data encoding:stringEncoding]; return responseString; } @end ================================================ FILE: Sources/Private/HookAjax/WKUserContentController+IMYHookAjax.m ================================================ // // WKUserContentController+IMYHookAjax.m // IMYViewKit // // Created by ljh on 2017/3/24. // Copyright © 2017年 IMY. All rights reserved. // #import "WKUserContentController+IMYHookAjax.h" #import #import "IMYWebUtils.h" #import "IMYWebLoader.h" @interface _IMYWKHookAjaxHandler : NSObject @property (nonatomic, weak) WKWebView *webView; @end @implementation _IMYWKHookAjaxHandler - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { self.webView = message.webView; [self requestWithBody:message.body]; } - (void)requestWithBody:(NSDictionary *)body { id requestID = body[@"id"]; NSString *method = body[@"method"]; id requestData = body[@"data"]; NSDictionary *requestHeaders = body[@"headers"]; NSString *urlString = body[@"url"]; [[IMYWebLoader defaultAjaxHandler] startWithMethod:method url:urlString baseURL:self.webView.URL headers:requestHeaders body:requestData completedBlock:^(NSInteger httpCode, NSDictionary * _Nullable headers, NSString * _Nullable data) { [self requestCallback:requestID httpCode:httpCode headers:headers data:data]; }]; } - (void)requestCallback:(id)requestId httpCode:(NSInteger)httpCode headers:(NSDictionary *)headers data:(NSString *)data { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"status"] = @(httpCode); dict[@"headers"] = headers; if (data.length > 0) { dict[@"data"] = data; } NSString *jsonString = nil; NSError *err = nil; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&err]; if (jsonData.length > 0) { jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; } NSString *jsScript = [NSString stringWithFormat:@"window.imy_realxhr_callback(%@, %@);", requestId, jsonString?:@"{}"]; dispatch_async(dispatch_get_main_queue(), ^{ [self.webView evaluateJavaScript:jsScript completionHandler:^(id result, NSError *error) { }]; }); } @end @implementation WKUserContentController (IMYHookAjax) static const void *IMYHookAjaxKey = &IMYHookAjaxKey; - (void)imy_uninstallHookAjax { [self removeScriptMessageHandlerForName:@"IMYXHR"]; objc_setAssociatedObject(self, IMYHookAjaxKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)imy_installHookAjax { BOOL installed = [objc_getAssociatedObject(self, IMYHookAjaxKey) boolValue]; if (installed) { return; } objc_setAssociatedObject(self, IMYHookAjaxKey, @YES, OBJC_ASSOCIATION_RETAIN_NONATOMIC); _IMYWKHookAjaxHandler *handler = [_IMYWKHookAjaxHandler new]; [self addScriptMessageHandler:handler name:@"IMYXHR"]; // add wk hook { NSString *path = [[NSBundle mainBundle] pathForResource:@"imywk_hookajax" ofType:@"js"]; NSString *jsScript = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; WKUserScript *userScript = [[WKUserScript alloc] initWithSource:jsScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; [self addUserScript:userScript]; } } @end ================================================ FILE: Sources/Private/Loader/IMYWebLoader+Impl.h ================================================ // // IMYWebLoader+Impl.h // Pods // // Created by ljh on 2017/2/27. // // #import "IMYWebLoader.h" @interface IMYWebLoader () @end ================================================ FILE: Sources/Private/Loader/IMYWebLoader+Impl.m ================================================ // // IMYWebLoader+Impl.m // Pods // // Created by ljh on 2017/2/27. // // #import "IMYWebLoader+Impl.h" #import #import "IMYWebCacheHandlerDefaultImpl.h" #import "IMYWebNetworkHandlerDefaultImpl.h" #import "IMYWebPrefetchHandlerDefaultImpl.h" #import "IMYWebAjaxHandlerDefaultImpl.h" #import "IMYWebRequestHandleManagerDefaultImpl.h" static pthread_mutex_t _lock; static NSMutableDictionary *_instanceMap = nil; static NSMutableDictionary *_classMap = nil; @implementation IMYWebLoader + (void)setHandlerClass:(Class)handlerClass forProtocol:(Protocol *)protocol { if (!handlerClass || !protocol) { NSAssert(NO, @"handlerClass/protocol can't nil !"); return; } NSString *key = NSStringFromProtocol(protocol); pthread_mutex_lock(&_lock); [_instanceMap removeObjectForKey:key]; [_classMap setObject:handlerClass forKey:key]; pthread_mutex_unlock(&_lock); } + (id)handlerForProtocol:(Protocol *)protocol { if (!protocol) { NSAssert(NO, @"protocol can't nil !"); return nil; } NSString *key = NSStringFromProtocol(protocol); pthread_mutex_lock(&_lock); id handler = [_instanceMap objectForKey:key]; if (!handler) { Class clazz = [_classMap objectForKey:key]; handler = [[clazz alloc] init]; if (handler) { [_instanceMap setObject:handler forKey:key]; } else { NSAssert(NO, @"not found handler with %@ protocol !", key); } } pthread_mutex_unlock(&_lock); return handler; } + (void)initialize { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ pthread_mutex_init(&_lock, NULL); _instanceMap = [NSMutableDictionary dictionary]; _classMap = [NSMutableDictionary dictionary]; [self setHandlerClass:[IMYWebCacheHandlerDefaultImpl class] forProtocol:@protocol(IMYWebCacheHandler)]; [self setHandlerClass:[IMYWebPrefetchHandlerDefaultImpl class] forProtocol:@protocol(IMYWebPrefetchHandler)]; [self setHandlerClass:[IMYWebNetworkHandlerDefaultImpl class] forProtocol:@protocol(IMYWebNetworkHandler)]; [self setHandlerClass:[IMYWebAjaxHandlerDefaultImpl class] forProtocol:@protocol(IMYWebAjaxHandler)]; [self setHandlerClass:[IMYWebRequestHandleManagerDefaultImpl class] forProtocol:@protocol(IMYWebRequestHandleManager)]; }); } @end @implementation IMYWebLoader (Guest) + (id)defaultRequestManager { return [self handlerForProtocol:@protocol(IMYWebRequestHandleManager)]; } + (id)defaultAjaxHandler { return [self handlerForProtocol:@protocol(IMYWebAjaxHandler)]; } + (id)defaultCacheHandler { return [self handlerForProtocol:@protocol(IMYWebCacheHandler)]; } + (id)defaultNetworkHandler { return [self handlerForProtocol:@protocol(IMYWebNetworkHandler)]; } + (id)defaultPrefetchHandler { return [self handlerForProtocol:@protocol(IMYWebPrefetchHandler)]; } @end ================================================ FILE: Sources/Private/URLProtocol/IMYWebRequestHandleManagerDefaultImpl.h ================================================ // // IMYWebRequestHandleManagerDefaultImpl.h // Pods // // Created by ljh on 2017/4/10. // // #import #import "IMYWebRequestHandleManager.h" @interface IMYWebRequestHandleManagerDefaultImpl : NSObject @end ================================================ FILE: Sources/Private/URLProtocol/IMYWebRequestHandleManagerDefaultImpl.m ================================================ // // IMYWebRequestHandleManagerDefaultImpl.m // Pods // // Created by ljh on 2017/4/10. // // #import "IMYWebRequestHandleManagerDefaultImpl.h" #import "IMYWebURLProtocol.h" #import "IMYWebRequestHandlerDefaultImpl.h" @interface IMYWebRequestHandleManagerDefaultImpl () { NSArray *_requestHandlerClass; } @end @implementation IMYWebRequestHandleManagerDefaultImpl - (instancetype)init { self = [super init]; if (self) { self.enableWKCustomProtocol = YES; [self addRequestHandlerClass:[IMYWebRequestHandlerDefaultImpl class]]; } return self; } - (void)addRequestHandlerClass:(Class)handlerClass { NSArray *array = _requestHandlerClass ?: [NSArray array]; const NSInteger index = [array indexOfObject:handlerClass]; if (index != NSNotFound) { return; } @synchronized (self) { array = [array arrayByAddingObject:handlerClass]; array = [array sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { NSInteger priority1 = [obj1 respondsToSelector:@selector(priority)] ? [obj1 priority] : 0; NSInteger priority2 = [obj2 respondsToSelector:@selector(priority)] ? [obj2 priority] : 0; if (priority1 < priority2) { return NSOrderedDescending; } else if (priority1 > priority2) { return NSOrderedAscending; } else { return NSOrderedSame; } }]; id holdArray = _requestHandlerClass; dispatch_async(dispatch_get_main_queue(), ^{ [holdArray description]; }); _requestHandlerClass = array; } } - (void)removeRequestHandlerClass:(Class)handlerClass { NSArray *array = _requestHandlerClass ?: [NSArray array]; const NSInteger index = [array indexOfObject:handlerClass]; if (index == NSNotFound) { return; } @synchronized (self) { NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array]; [mutableArray removeObjectAtIndex:index]; id holdArray = _requestHandlerClass; dispatch_async(dispatch_get_main_queue(), ^{ [holdArray description]; }); _requestHandlerClass = [mutableArray copy]; } } - (NSArray> *)requestHandlerClass { NSArray *array = _requestHandlerClass; return array; } - (void)setEnableWKCustomProtocol:(BOOL)enableWKCustomProtocol { [IMYWebURLProtocol setEnableWKCustomProtocol:enableWKCustomProtocol]; } - (BOOL)enableWKCustomProtocol { return [IMYWebURLProtocol enableWKCustomProtocol]; } @end ================================================ FILE: Sources/Private/URLProtocol/IMYWebRequestHandlerDefaultImpl.h ================================================ // // IMYWebRequestHandlerDefaultImpl.h // Pods // // Created by ljh on 2017/4/11. // // #import #import "IMYWebRequestHandleManager.h" @interface IMYWebRequestHandlerDefaultImpl : NSObject @end ================================================ FILE: Sources/Private/URLProtocol/IMYWebRequestHandlerDefaultImpl.m ================================================ // // IMYWebRequestHandlerDefaultImpl.m // Pods // // Created by ljh on 2017/4/11. // // #import "IMYWebRequestHandlerDefaultImpl.h" #import "IMYWebLoader.h" static NSString * const IMYWebDXP = @"IMYWebDXP"; @interface IMYWebRequestHandlerDefaultImpl () @property (nonatomic, strong) NSURLRequest *request; @property (nonatomic, weak) id operation; @end @implementation IMYWebRequestHandlerDefaultImpl + (BOOL)shouldHookWithRequest:(NSURLRequest *)request { ///只缓存get请求 if (request.HTTPMethod && ![request.HTTPMethod.uppercaseString isEqualToString:@"GET"]) { return NO; } ///通过UA 来判断是否UIWebView发起的请求 NSString *UA = [request valueForHTTPHeaderField:@"User-Agent"]; if ([UA containsString:@" AppleWebKit/"] == NO) { return NO; } /// 不缓存 ajax 请求 NSString *hasAjax = [request valueForHTTPHeaderField:@"X-Requested-With"]; if (hasAjax != nil) { return NO; } NSString *pathExtension = [request.URL.absoluteString componentsSeparatedByString:@"?"].firstObject.pathExtension.lowercaseString; NSArray *validExtension = @[ @"jpg", @"jpeg", @"gif", @"png", @"webp", @"bmp", @"tif", @"ico", @"js", @"css", @"html", @"htm", @"ttf", @"svg"]; if (pathExtension && [validExtension containsObject:pathExtension]) { return YES; } return NO; } + (BOOL)cancelHookWithRequest:(NSURLRequest *)request { ///已被拦截 if ([request valueForHTTPHeaderField:IMYWebDXP]) { return YES; } return NO; } + (id)requestHandlerWithRequest:(NSURLRequest *)request { IMYWebRequestHandlerDefaultImpl *handler = [IMYWebRequestHandlerDefaultImpl new]; handler.request = request; return handler; } - (void)startLoadingWithDelegate:(id)delegate { NSString *cacheKey = [[IMYWebLoader defaultCacheHandler] cacheKeyForRequest:self.request]; IMYWebData *webData = [[IMYWebLoader defaultCacheHandler] dataForKey:cacheKey]; if (webData) { [delegate request:self didReceiveResponse:webData.response]; [delegate request:self didReceiveData:webData.data]; [delegate requestDidFinishLoading:self]; return; } NSThread *thread = [NSThread currentThread]; NSMutableURLRequest *request = [self.request mutableCopy]; [request setValue:@"1" forHTTPHeaderField:IMYWebDXP]; __weak id wself = self; self.operation = [[IMYWebLoader defaultNetworkHandler] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { __strong IMYWebRequestHandlerDefaultImpl *self = wself; [self performSelector:@selector(performBlock:) onThread:thread withObject:^{ __strong IMYWebRequestHandlerDefaultImpl *self = wself; if (response) { [delegate request:self didReceiveResponse:response]; } if (error) { [delegate request:self didFailWithError:error]; } else { [delegate request:self didReceiveData:data]; [delegate requestDidFinishLoading:self]; IMYWebData *webData = [IMYWebData new]; webData.data = data; webData.response = response; webData.request = self.request; [[IMYWebLoader defaultCacheHandler] setData:webData forKey:cacheKey]; } } waitUntilDone:NO]; }]; } - (void)performBlock:(dispatch_block_t)block { if (block) { block(); } } - (void)stopLoading { [self.operation cancel]; } @end ================================================ FILE: Sources/Private/URLProtocol/IMYWebURLProtocol.h ================================================ // // IMYWebURLProtocol.h // Pods // // Created by ljh on 2017/2/28. // // #import @interface IMYWebURLProtocol : NSURLProtocol @end @interface IMYWebURLProtocol (WKCustomProtocol) @property (class, nonatomic) BOOL enableWKCustomProtocol; @end ================================================ FILE: Sources/Private/URLProtocol/IMYWebURLProtocol.m ================================================ // // IMYWebURLProtocol.m // Pods // // Created by ljh on 2017/2/28. // // #import "IMYWebURLProtocol.h" #import "IMYWebLoader+Impl.h" #import "IMYWebRequestHandleManager.h" #import @interface IMYWebURLProtocol () @property (nonatomic, assign) BOOL receivedResponse; @property (nonatomic, assign) BOOL stoppedLoading; @property (nonatomic, strong) id requestHandler; @end @implementation IMYWebURLProtocol + (void)load { [NSURLProtocol registerClass:self]; } + (BOOL)canInitWithTask:(NSURLSessionTask *)task { return [self canInitWithRequest:task.currentRequest]; } + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { return request; } + (BOOL)canInitWithRequest:(NSURLRequest *)request { NSArray *requestHandlerClass = [IMYWebLoader defaultRequestManager].requestHandlerClass; if (!requestHandlerClass.count) { return NO; } BOOL shouldHook = NO; BOOL cancelHook = NO; for (Class handlerClass in requestHandlerClass) { shouldHook = [handlerClass shouldHookWithRequest:request]; if (shouldHook) { break; } } for (Class handlerClass in requestHandlerClass) { cancelHook = [handlerClass cancelHookWithRequest:request]; if (cancelHook) { break; } } return shouldHook && !cancelHook; } - (void)startLoading { NSURLRequest *request = self.request; id requestHandler = nil; NSArray *requestHandlerClass = [IMYWebLoader defaultRequestManager].requestHandlerClass; for (Class handlerClass in requestHandlerClass) { requestHandler = [handlerClass requestHandlerWithRequest:request]; if (requestHandler) { break; } } if (!requestHandler) { NSError *error = [NSError errorWithDomain:@"no request handler !" code:-999 userInfo:nil]; [self callbackRequestDidFailWithError:error]; } else { self.requestHandler = requestHandler; [self.requestHandler startLoadingWithDelegate:self]; } } - (void)stopLoading { self.stoppedLoading = YES; [self.requestHandler stopLoading]; } /// 保证 Response URL 跟请求时一致 - (NSURLResponse *)callbackResponseWithResponse:(NSURLResponse *)response { NSHTTPURLResponse *httpResponse = (id)response; if ([httpResponse isKindOfClass:[NSHTTPURLResponse class]]) { if (![httpResponse.URL isEqual:self.request.URL]) { httpResponse = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:httpResponse.statusCode HTTPVersion:@"HTTP/1.1" headerFields:httpResponse.allHeaderFields]; } } return httpResponse; } - (void)callbackRequestWasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response { if (self.receivedResponse) { NSError *error = [NSError errorWithDomain:@"only return first received response !!" code:-999 userInfo:nil]; NSAssert(NO, error.domain); return; } if (self.stoppedLoading) { return; } response = [self callbackResponseWithResponse:response]; if (!response) { NSError *error = [NSError errorWithDomain:@"wasRedirectedToRequest redirectResponse not found !!" code:-999 userInfo:nil]; [self callbackRequestDidFailWithError:error]; } else { self.receivedResponse = YES; [self.client URLProtocol:self wasRedirectedToRequest:request redirectResponse:response]; } } - (void)callbackRequestDidReceiveResponse:(NSURLResponse *)response { if (self.receivedResponse) { NSError *error = [NSError errorWithDomain:@"only return first received response !!" code:-999 userInfo:nil]; NSAssert(NO, error.domain); return; } if (self.stoppedLoading) { return; } response = [self callbackResponseWithResponse:response]; if (!response) { NSError *error = [NSError errorWithDomain:@"response not found !!" code:-999 userInfo:nil]; NSLog(@"%@", error.domain); } else { self.receivedResponse = YES; [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; } } - (void)callbackRequestDidLoadData:(NSData *)data { if (self.stoppedLoading) { return; } if (!self.receivedResponse) { NSError *error = [NSError errorWithDomain:@"didReceiveData to be scheduled before didReceiveResponse !!" code:-999 userInfo:nil]; NSLog(@"%@", error.domain); } else if (data.length > 0) { [self.client URLProtocol:self didLoadData:data]; } } - (void)callbackRequestDidFailWithError:(NSError *)error { if (self.stoppedLoading) { return; } NSLog(@"%@", error.domain); [self.client URLProtocol:self didFailWithError:error]; } - (void)callbackRequestDidFinishLoading { if (self.stoppedLoading) { return; } if (!self.receivedResponse) { NSError *error = [NSError errorWithDomain:@"didFinishLoading to be scheduled before didReceiveResponse !!" code:-999 userInfo:nil]; [self callbackRequestDidFailWithError:error]; } else { [self.client URLProtocolDidFinishLoading:self]; } } #pragma mark - request delegate - (void)request:(id)request wasRedirectedToRequest:(NSURLRequest *)redirectRequest redirectResponse:(NSURLResponse *)redirectResponse { [self callbackRequestWasRedirectedToRequest:redirectRequest redirectResponse:redirectResponse]; } - (void)request:(id)request didReceiveResponse:(NSURLResponse *)response { [self callbackRequestDidReceiveResponse:response]; } - (void)request:(id)request didReceiveData:(NSData *)data { [self callbackRequestDidLoadData:data]; } - (void)requestDidFinishLoading:(id)request { [self callbackRequestDidFinishLoading]; } - (void)request:(id)request didFailWithError:(NSError *)error { [self callbackRequestDidFailWithError:error]; } @end @implementation IMYWebURLProtocol (WKCustomProtocol) static BOOL kIMYEnableWKCustomProtocol = NO; + (void)setEnableWKCustomProtocol:(BOOL)enableWKCustomProtocol { kIMYEnableWKCustomProtocol = enableWKCustomProtocol; id contextController = NSClassFromString([NSString stringWithFormat:@"%@%@%@",@"WK",@"Browsing",@"ContextController"]); if (!contextController) { return; } SEL performSEL = nil; if (enableWKCustomProtocol) { performSEL = NSSelectorFromString([NSString stringWithFormat:@"%@%@",@"register",@"SchemeForCustomProtocol:"]); } else { performSEL = NSSelectorFromString([NSString stringWithFormat:@"%@%@",@"unregister",@"SchemeForCustomProtocol:"]); } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" if ([contextController respondsToSelector:performSEL]) { [contextController performSelector:performSEL withObject:@"http"]; [contextController performSelector:performSEL withObject:@"https"]; } #pragma clang diagnostic pop } + (BOOL)enableWKCustomProtocol { return kIMYEnableWKCustomProtocol; } @end ================================================ FILE: Sources/Private/URLProtocol/NSObject+WKCustomProtocolLoader.h ================================================ // // NSObject+WKCustomProtocolLoader.h // Pods // // Created by ljh on 2017/4/10. // // #import /// 原始 WKCustomProtocolLoader 是在主线程进行网络请求,这边进行 hook 改为在子线程请求 @interface NSObject (WKCustomProtocolLoader) @end ================================================ FILE: Sources/Private/URLProtocol/NSObject+WKCustomProtocolLoader.m ================================================ // // NSObject+WKCustomProtocolLoader.m // Pods // // Created by ljh on 2017/4/10. // // #import "NSObject+WKCustomProtocolLoader.h" #import "IMYWebLoader.h" #import "IMYWebUtils.h" @interface _IMYWKProtocolLoader : NSObject @property (nonatomic, weak) id wkloader; @property (nonatomic, strong) NSURLRequest *request; @end @implementation _IMYWKProtocolLoader @end /// 原始 WKCustomProtocolLoader 是在主线程进行网络请求,这边进行 hook 改为在子线程请求 @implementation NSObject (WKCustomProtocolLoader) + (void)load { Class clazz = NSClassFromString([NSString stringWithFormat:@"%@%@%@",@"WK",@"Custom",@"ProtocolLoader"]); SEL swizzleSEL = NSSelectorFromString([NSString stringWithFormat:@"%@%@%@",@"initWithCustomProtocol",@"ManagerProxy:customProtocolID",@":request:connection:"]); [IMYWebUtils swizzleClass:clazz origMethod:swizzleSEL withMethod:@selector(wkloader_initWithProtocolManager:protocolID:request:connection:)]; SEL swizzleLegacySEL = NSSelectorFromString([NSString stringWithFormat:@"%@%@",@"initWithLegacyCustomProtocolManagerProxy",@":customProtocolID:request:"]); [IMYWebUtils swizzleClass:clazz origMethod:swizzleLegacySEL withMethod:@selector(wkloader_initWithLegacyCustomProtocolManagerProxy:customProtocolID:request:)]; } - (id)wkloader_initWithLegacyCustomProtocolManagerProxy:(void*)customProtocolManagerProxy customProtocolID:(uint64_t)customProtocolID request:(NSURLRequest *)request { id wkloader = [self wkloader_initWithLegacyCustomProtocolManagerProxy:customProtocolManagerProxy customProtocolID:customProtocolID request:[NSURLRequest new]]; [NSObject wkloader_hookWKLoader:wkloader request:request]; return wkloader; } - (id)wkloader_initWithProtocolManager:(void *)protocolManager protocolID:(uint64_t)protocolID request:(NSURLRequest *)request connection:(void *)connection { id wkloader = [self wkloader_initWithProtocolManager:protocolManager protocolID:protocolID request:[NSURLRequest new] connection:connection]; [NSObject wkloader_hookWKLoader:wkloader request:request]; return wkloader; } + (void)wkloader_hookWKLoader:(id)wkloader request:(NSURLRequest *)request { NSURLConnection *urlConnection = [wkloader valueForKey:@"_urlConnection"]; [urlConnection setValue:nil forKeyPath:@"_internal._delegate"]; [urlConnection unscheduleFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; [urlConnection cancel]; _IMYWKProtocolLoader *weakObj = [_IMYWKProtocolLoader new]; weakObj.wkloader = wkloader; weakObj.request = request; [self performSelector:@selector(wkloader_startConnection:) onThread:[[IMYWebLoader defaultNetworkHandler] networkRequestThread] withObject:weakObj waitUntilDone:NO]; } + (void)wkloader_startConnection:(_IMYWKProtocolLoader *)weakObj { id wkloader = weakObj.wkloader; if (!wkloader) { return; } NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:weakObj.request delegate:wkloader startImmediately:NO]; [urlConnection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; [urlConnection start]; [wkloader setValue:urlConnection forKey:@"_urlConnection"]; } @end ================================================ FILE: Sources/Private/Utils/IMYWebUtils.h ================================================ // // IMYWebUtils.h // Pods // // Created by ljh on 2017/4/10. // // #import @interface IMYWebUtils : NSObject ///模拟网页的 URL 生成规则 + (NSURL *)URLWithString:(NSString *)urlString baseURL:(NSURL *)baseURL; + (BOOL)swizzleClass:(Class)clazz origMethod:(SEL)origSel_ withMethod:(SEL)altSel_; @end ================================================ FILE: Sources/Private/Utils/IMYWebUtils.m ================================================ // // IMYWebUtils.m // Pods // // Created by ljh on 2017/4/10. // // #import "IMYWebUtils.h" #import @implementation IMYWebUtils + (NSURL *)URLWithString:(NSString *)urlString baseURL:(NSURL *)baseURL { if (!urlString.length) { return nil; } if (![urlString containsString:@"://"]) { if ([urlString hasPrefix:@"//"]) { urlString = [NSString stringWithFormat:@"%@:%@", baseURL.scheme?:@"http", urlString]; } else if ([urlString hasPrefix:@"/"]) { urlString = [NSString stringWithFormat:@"%@://%@%@", baseURL.scheme?:@"http", baseURL.host, urlString]; } else { urlString = [NSString stringWithFormat:@"%@://%@", baseURL.scheme?:@"http", urlString]; } } NSURL *URL = [NSURL URLWithString:urlString]; if (!URL) { urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; URL = [NSURL URLWithString:urlString]; } return URL; } + (BOOL)swizzleClass:(Class)clazz origMethod:(SEL)origSel_ withMethod:(SEL)altSel_ { Method origMethod = class_getInstanceMethod(clazz, origSel_); if (!origMethod) { return NO; } Method altMethod = class_getInstanceMethod(clazz, altSel_); if (!altMethod) { return NO; } class_addMethod(clazz, origSel_, class_getMethodImplementation(clazz, origSel_), method_getTypeEncoding(origMethod)); class_addMethod(clazz, altSel_, class_getMethodImplementation(clazz, altSel_), method_getTypeEncoding(altMethod)); method_exchangeImplementations(class_getInstanceMethod(clazz, origSel_), class_getInstanceMethod(clazz, altSel_)); return YES; } @end ================================================ FILE: Sources/Public/Data/IMYWebData.h ================================================ // // IMYWebData.h // Pods // // Created by ljh on 2017/2/27. // // #import NS_ASSUME_NONNULL_BEGIN @interface IMYWebData : NSObject @property (nullable, nonatomic, copy) NSURLRequest *request; /**< 请求链接*/ @property (nullable, nonatomic, copy) NSURLRequest *redirectRequest; /**< 重定向链接*/ @property (nullable, nonatomic, copy) NSURLResponse *response; /**< 服务器返回的response*/ @property (nullable, nonatomic, copy) NSData *data; /**< 数据*/ @property (nullable, nonatomic, copy) NSError *error; /**< 错误*/ @property (nullable, nonatomic, copy) NSDate *createDate; /**< 创建时间*/ @property (nullable, nonatomic, copy) NSDictionary *userInfo; /**< 用户数据*/ @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/Public/Data/IMYWebData.m ================================================ // // IMYWebData.m // Pods // // Created by ljh on 2017/2/27. // // #import "IMYWebData.h" static NSString * const kRequestKey = @"request"; static NSString * const kRedirectRequestKey = @"redirectRequest"; static NSString * const kResponseKey = @"response"; static NSString * const kDataKey = @"data"; static NSString * const kErrorKey = @"error"; static NSString * const kCreateDateKey = @"createDate"; static NSString * const kUserInfoKey = @"userInfo"; @implementation IMYWebData - (instancetype)init { self = [super init]; if (self) { _createDate = [NSDate date]; } return self; } + (BOOL)supportsSecureCoding { return YES; } - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:_request forKey:kRequestKey]; [aCoder encodeObject:_redirectRequest forKey:kRedirectRequestKey]; [aCoder encodeObject:_response forKey:kResponseKey]; [aCoder encodeObject:_data forKey:kDataKey]; [aCoder encodeObject:_error forKey:kErrorKey]; [aCoder encodeObject:_createDate forKey:kCreateDateKey]; [aCoder encodeObject:_userInfo forKey:kUserInfoKey]; } - (id)initWithCoder:(NSCoder*)aDecoder { self = [super init]; if (self) { _request = [aDecoder decodeObjectForKey:kRequestKey]; _redirectRequest = [aDecoder decodeObjectForKey:kRedirectRequestKey]; _response = [aDecoder decodeObjectForKey:kResponseKey]; _data = [aDecoder decodeObjectForKey:kDataKey]; _error = [aDecoder decodeObjectForKey:kErrorKey]; _createDate = [aDecoder decodeObjectForKey:kCreateDateKey]; _userInfo = [aDecoder decodeObjectForKey:kUserInfoKey]; } return self; } @end ================================================ FILE: Sources/Public/Handler/IMYWebAjaxHandler.h ================================================ // // IMYWebAjaxHandler.h // Pods // // Created by ljh on 2017/4/10. // // #import NS_ASSUME_NONNULL_BEGIN @protocol IMYWebAjaxHandler - (void)startWithMethod:(NSString *)method url:(NSString *)urlString baseURL:(nullable NSURL *)baseURL headers:(nullable NSDictionary *)headers body:(nullable id)body completedBlock:(void (^)(NSInteger httpCode, NSDictionary * _Nullable headers, NSString * _Nullable data))completedBlock; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/Public/Handler/IMYWebCacheHandler.h ================================================ // // IMYWebCacheHandler.h // Pods // // Created by ljh on 2017/2/27. // // #import #import "IMYWebData.h" NS_ASSUME_NONNULL_BEGIN @protocol IMYWebCacheHandler - (NSString *)cacheKeyForRequest:(NSURLRequest *)request; - (nullable IMYWebData *)dataForKey:(NSString *)key; - (void)setData:(nullable IMYWebData *)data forKey:(NSString *)key; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/Public/Handler/IMYWebNetworkHandler.h ================================================ // // IMYWebNetworkHandler.h // Pods // // Created by ljh on 2017/2/28. // // #import #import "IMYWebOperation.h" NS_ASSUME_NONNULL_BEGIN @protocol IMYWebNetworkHandler /// 生成 发起请求的 Request - (NSURLRequest *)requestWithString:(NSString *)urlString; /// 发起网络请求 - (id)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; /// 子线程 - (NSThread *)networkRequestThread; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/Public/Handler/IMYWebPrefetchHandler.h ================================================ // // IMYWebPrefetchHandler.h // Pods // // Created by ljh on 2017/2/28. // // #import #import "IMYWebOperation.h" NS_ASSUME_NONNULL_BEGIN @protocol IMYWebPrefetcherProtocol @property (nonatomic, copy) NSString *webUrl; @property (nonatomic, assign, readonly, getter=isComplated) BOOL complated; @end @protocol IMYWebPrefetchHandler ///一次生命周期内 对同一个 url,只会预加载一次,除非已经被移除了 - (id)prefetchWebUrl:(NSString *)webUrl; ///取消全部预加载操作 - (void)cancelAllPrefetcherLoading; ///移除预加载对象 - (void)removePrefetcherForWebUrl:(NSString *)webUrl; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/Public/Handler/IMYWebRequestHandleManager.h ================================================ // // IMYWebRequestHandleManager.h // MeetYou // // Created by ljh on 2017/2/27. // // #import NS_ASSUME_NONNULL_BEGIN @protocol IMYWebRequestHandler,IMYWebCacheHandler; @protocol IMYWebRequestDelegate @required - (void)request:(id)request wasRedirectedToRequest:(NSURLRequest *)redirectRequest redirectResponse:(nullable NSURLResponse *)redirectResponse; - (void)request:(id)request didReceiveResponse:(NSURLResponse *)response; - (void)request:(id)request didReceiveData:(NSData *)data; - (void)requestDidFinishLoading:(id)request; - (void)request:(id)request didFailWithError:(NSError *)error; @end @protocol IMYWebRequestHandler @required /// 是否要拦截该 request + (BOOL)shouldHookWithRequest:(NSURLRequest *)request; /// 取消该 Request 的拦截,只要有一个 class 返回 YES,则不拦截该请求 + (BOOL)cancelHookWithRequest:(NSURLRequest *)request; /// 根据 Request 返回具体的请求实例, 会使用第一个返回的请求对象 + (nullable id)requestHandlerWithRequest:(NSURLRequest *)request; /// 开始加载 - (void)startLoadingWithDelegate:(id)delegate; /// 停止加载 - (void)stopLoading; @optional /// 实现后 会用返回的缓存控制器 , default:[IMYWebLoader defaultCacheHandler] + (id)cacheHandler; /// 拦截器优先级,默认 0,越大排序越前 + (NSInteger)priority; @end @protocol IMYWebRequestHandleManager - (void)addRequestHandlerClass:(Class)handlerClass; - (void)removeRequestHandlerClass:(Class)handlerClass; - (NSArray> *)requestHandlerClass; ///是否开启 WKWebView Custom Protocol 拦截 http、https。 default:YES @property (nonatomic, assign) BOOL enableWKCustomProtocol; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/Public/Header/IMYWebDefines.h ================================================ // // IMYWebDefines.h // Pods // // Created by ljh on 2017/4/10. // // #ifndef IMYWebDefines_h #define IMYWebDefines_h #import "IMYWebRequestHandleManager.h" #import "IMYWebCacheHandler.h" #import "IMYWebPrefetchHandler.h" #import "IMYWebNetworkHandler.h" #import "IMYWebAjaxHandler.h" #import "WKUserContentController+IMYHookAjax.h" #endif /* IMYWebDefines_h */ ================================================ FILE: Sources/Public/Header/IMYWebOperation.h ================================================ // // IMYWebOperation.h // Pods // // Created by ljh on 2017/2/28. // // #import @protocol IMYWebOperation - (void)cancel; @end ================================================ FILE: Sources/Public/Header/WKUserContentController+IMYHookAjax.h ================================================ // // WKUserContentController+IMYHookAjax.h // IMYViewKit // // Created by ljh on 2017/3/24. // Copyright © 2017年 IMY. All rights reserved. // #import @interface WKUserContentController (IMYHookAjax) /// 当 WebView 释放的时候,必须手动调用 uninstall 来移除该对象, 不然该对象永远不会释放 - (void)imy_installHookAjax; /// 卸载 hook ajax - (void)imy_uninstallHookAjax; @end ================================================ FILE: Sources/Public/IMYWebLoader.h ================================================ // // IMYWebPrefetcher.h // Pods // // Created by ljh on 2017/2/27. // // #import #import "IMYWebDefines.h" NS_ASSUME_NONNULL_BEGIN @interface IMYWebLoader : NSObject + (id)handlerForProtocol:(Protocol *)protocol; + (void)setHandlerClass:(Class)handlerClass forProtocol:(Protocol *)protocol; @end @interface IMYWebLoader (Guest) ///请求拦截控制器 @property (class, readonly, nonatomic) id defaultRequestManager; ///缓存控制器 @property (class, readonly, nonatomic) id defaultCacheHandler; ///预加载控制器 @property (class, readonly, nonatomic) id defaultPrefetchHandler; ///数据请求 @property (class, readonly, nonatomic) id defaultNetworkHandler; /// Ajax 需要手动 执行 imy_installHookAjax,目前需要针对 WKWebView @property (class, readonly, nonatomic) id defaultAjaxHandler; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/Resources/imywk_hookajax.js ================================================ (function() { if (window.imy_realxhr) { return } window.imy_realxhr = XMLHttpRequest; var timestamp = new Date().getTime(); timestamp = parseInt((timestamp / 1000) % 100000); var global_index = timestamp + 1; var global_map = {}; window.imy_realxhr_callback = function(id, message) { var hookAjax = global_map[id]; if (hookAjax) { hookAjax.callbackNative(message) } global_map[id] = null }; function BaseHookAjax() {} BaseHookAjax.prototype = window.imy_realxhr; function hookAjax() {} hookAjax.prototype = BaseHookAjax; hookAjax.prototype.readyState = 0; hookAjax.prototype.responseText = ""; hookAjax.prototype.responseHeaders = {}; hookAjax.prototype.status = 0; hookAjax.prototype.statusText = ""; hookAjax.prototype.onreadystatechange = null; hookAjax.prototype.onload = null; hookAjax.prototype.onerror = null; hookAjax.prototype.onabort = null; hookAjax.prototype.open = function() { this.open_arguments = arguments; this.readyState = 1; if (this.onreadystatechange) { this.onreadystatechange() } }; hookAjax.prototype.setRequestHeader = function(name, value) { if (!this._headers) { this._headers = {} } this._headers[name] = value }; hookAjax.prototype.send = function() { if (arguments.length >= 1 && !!arguments[0]) { this.sendNative(arguments[0]) } else { var xhr = new window.imy_realxhr(); this._xhr = xhr; var that = this; xhr.onreadystatechange = function() { that.readyState = xhr.readyState; if (that.readyState <= 1) { return } if (xhr.readyState >= 3) { that.status = xhr.status; that.statusText = xhr.statusText; that.responseText = xhr.responseText; } that.callbackStateChanged(); }; xhr.open.apply(xhr, this.open_arguments); for (name in this._headers) { xhr.setRequestHeader(name, this._headers[name]) } xhr.send.apply(xhr, arguments) } }; hookAjax.prototype.sendNative = function(data) { this.request_id = global_index; global_map[this.request_id] = this; global_index++; var message = {}; message.id = this.request_id; message.data = data; message.method = this.open_arguments[0]; message.url = this.open_arguments[1]; message.headers = this._headers; window.webkit.messageHandlers.IMYXHR.postMessage(message) }; hookAjax.prototype.callbackNative = function(message) { if (!this.is_abort) { this.status = message.status; this.responseText = (!!message.data) ? message.data : ""; this.responseHeaders = message.headers; this.readyState = 4 } else { this.readyState = 1 } this.callbackStateChanged(); }; hookAjax.prototype.callbackStateChanged = function() { if (this.readyState >= 3) { if (this.status >= 200 && this.status < 300) { this.statusText = "OK" } else { this.statusText = "Fail" } } if (this.onreadystatechange) { this.onreadystatechange() } if (this.readyState == 4) { if (this.statusText == "OK") { this.onload ? this.onload() : "" } else { this.onerror ? this.onerror() : "" } } }; hookAjax.prototype.abort = function() { this.is_abort = true; if (this._xhr) { this._xhr.abort() } if (this.onabort) { this.onabort() } }; hookAjax.prototype.getAllResponseHeaders = function() { if (this._xhr) { return this._xhr.getAllResponseHeaders() } else { return this.responseHeaders } }; hookAjax.prototype.getResponseHeader = function(name) { if (this._xhr) { return this._xhr.getResponseHeader(name) } else { for (key in this.responseHeaders) { if (key.toLowerCase() == name.toLowerCase()) { return this.responseHeaders[key] } } return null } }; XMLHttpRequest = hookAjax; window.imy_hookAjax = function() { XMLHttpRequest = hookAjax }; window.imy_unhookAjax = function() { XMLHttpRequest = window.imy_realxhr } })();