master bb563a0fd4e5 cached
35 files
77.5 KB
22.1k tokens
1 symbols
1 requests
Download .txt
Repository: dequan1331/WKWebViewExtension
Branch: master
Commit: bb563a0fd4e5
Files: 35
Total size: 77.5 KB

Directory structure:
gitextract_t3xquul0/

├── .gitignore
├── LICENSE
├── README.md
├── README_CN.md
├── WKWebViewExtension/
│   ├── WKWebViewExtension/
│   │   ├── AppDelegate.h
│   │   ├── AppDelegate.m
│   │   ├── Example/
│   │   │   ├── ViewController.h
│   │   │   ├── ViewController.m
│   │   │   ├── WebView.h
│   │   │   └── WebView.m
│   │   ├── Images.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── LaunchImage.launchimage/
│   │   │       └── Contents.json
│   │   ├── Info.plist
│   │   ├── Source/
│   │   │   ├── WKWebView + DeleteMenuItems.h
│   │   │   ├── WKWebView + DeleteMenuItems.m
│   │   │   ├── WKWebView + ExternalNavigationDelegates.h
│   │   │   ├── WKWebView + ExternalNavigationDelegates.m
│   │   │   ├── WKWebView + SafeClearCache.h
│   │   │   ├── WKWebView + SafeClearCache.m
│   │   │   ├── WKWebView + SafeCookies.h
│   │   │   ├── WKWebView + SafeCookies.m
│   │   │   ├── WKWebView + SafeEvaluateJS.h
│   │   │   ├── WKWebView + SafeEvaluateJS.m
│   │   │   ├── WKWebView + SafeScrollTo.h
│   │   │   ├── WKWebView + SafeScrollTo.m
│   │   │   ├── WKWebView + SupportProtocol.h
│   │   │   ├── WKWebView + SupportProtocol.m
│   │   │   ├── WKWebView + SyncConfigUA.h
│   │   │   ├── WKWebView + SyncConfigUA.m
│   │   │   └── WKWebViewExtensionsDef.h
│   │   └── main.m
│   └── WKWebViewExtension.xcodeproj/
│       ├── project.pbxproj
│       └── project.xcworkspace/
│           ├── contents.xcworkspacedata
│           └── xcshareddata/
│               └── IDEWorkspaceChecks.plist
└── WKWebViewExtension.podspec

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================

# Created by https://www.gitignore.io/api/xcode,macos,objective-c

### macOS ###
*.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### Objective-C ###
# 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
*.xccheckout
*.xcscmblueprint

## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM

# CocoaPods - Refactored to standalone file


# Carthage - Refactored to standalone file

# 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://docs.fastlane.tools/best-practices/source-control/#source-control

fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output

# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode

iOSInjectionProject/

### Objective-C Patch ###

### Xcode ###
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## Build generated

## Various settings

## Other

### Xcode Patch ###
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcworkspace/contents.xcworkspacedata
/*.gcno


# End of https://www.gitignore.io/api/xcode,macos,objective-c

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 dequan1331

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
================================================
_**This repo will no longer be updated. The new versions has been moved to [HybridPageKit](https://github.com/dequan1331/HybridPageKit) as a submodule. Integrate ' HybridPageKit/WKWebViewExtension ' subspecs with Cocoapods.**_

***

<br>
<br>


# WKWebViewExtension

[Extended Reading](https://dequan1331.github.io/index-en.html) | [中文](./README_CN.md) | [扩展阅读](https://dequan1331.github.io/)

An extension for WKWebView . 

Providing `WKWebView MenuItems delete` 、 `WKWebView support protocol` 、 `WKWebView clear cache or iOS8` and so on.

> Together with [ReusableNestingScrollview](https://github.com/dequan1331/ReusableNestingScrollview), sub repo of [HybridPageKit](https://github.com/dequan1331/HybridPageKit), which is a general sulotion of news App content page.


## Requirements
iOS 8.0 or later

		
##	Installation

1.	CocoaPods
	
		platform :ios, '8.0'
		pod 'WKWebViewExtension'

2.	Cloning the repository

	```objective-c
	#import <WKWebViewExtensionsDef.h>
	```

## Features

1.	DeleteMenuItems  `iOS11 this issue has been fixed `

	
		WKWebView Support Delete System MenuItems
   		Delete System Items Without cut/copy/paste/delete
   		

2.	SupportProtocol

		WKWebView Support Protocol Like UIWebView

3.	SafeClearCache

		WKWebView Support iOS8 Clear All Cache
		
4.	SafeScrollTo

		WKWebView Safe ScrollTo Specific Offset Without Blank Screen by Runloop
		
5.	SafeEvaluateJS

		Safe Evaluate JS And Retainify Webview For CallBack, and Make Sure CallBack IS NOT null
		
6.	ExternalNavigationDelegates

		WKWebView Support Internal And Extenal Delegates

7.	SyncConfigUA

		Sync Config UA Without WKWebView
		
## Licenses

All source code is licensed under the [MIT License](https://github.com/dequan1331/WKWebViewExtension/blob/master/LICENSE).

================================================
FILE: README_CN.md
================================================
_**暂停更新. 相关功能作为Submodule调整到 [HybridPageKit](https://github.com/dequan1331/HybridPageKit) 项目中. 后续使用Cocoapods,集成HybridPageKit的subspecs ——'HybridPageKit/WKWebViewExtension'**_

***

<br>
<br>


# WKWebViewExtension

[英文](./README.md) | [扩展阅读](https://dequan1331.github.io/) | [Extended Reading](https://dequan1331.github.io/index-en.html)


一系列WKWebView的扩展 .

提供自定义长按MenuItems Bug修复、支持NSURLProtocol、清理iOS 8浏览器缓存等功能。
 
> 与[ReusableNestingScrollview](https://github.com/dequan1331/ReusableNestingScrollview)一起,组件服务于[HybridPageKit](https://github.com/dequan1331/HybridPageKit),一个资讯类内容底层页完善的通用组件。

## 配置

iOS 8.0 or later

		
##	安装

1.	CocoaPods
	
		platform :ios, '8.0'
		pod 'WKWebViewExtension'

2.	下载repo并引入头文件

	```objective-c
	#import <WKWebViewExtensionsDef.h>
	```

## 特点

1.	自定义长按MenuItems Bug修复  `iOS11系统已修复`

	
		自定义长按MenuItems Bug修复,iOS11前部分Item无法删除
   		

2.	支持NSURLProtocol

		支持NSURLProtocol

3.	清理浏览器缓存

		支持iOS 8 删除全部浏览器缓存
		
4.	安全滚动

		通过Runloop检测WebView的ContentSize是否大于滚动距离,自动滚动或等待重试
		
5.	安全执行JS

		防止WebView异步执行JS回调时,WebView释放导致Crash,容错JS执行回调null对象
		
6.	扩展Navigation Delegate

		通过代理分发,扩展Navigation Delegate,支持业务层级外部Delegate以及内部服务于JS Bridge的Delegate

7.	同步配置WebView UA

		扩展通过UIWebView同步配置UA,防止异步执行产生时序问题。
		
## 证书

All source code is licensed under the [MIT License](https://github.com/dequan1331/WKWebViewExtension/blob/master/LICENSE).

================================================
FILE: WKWebViewExtension/WKWebViewExtension/AppDelegate.h
================================================
//
//  WKWebView + DeleteMenuItems.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;


@end



================================================
FILE: WKWebViewExtension/WKWebViewExtension/AppDelegate.m
================================================
//
//  WKWebView + DeleteMenuItems.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "AppDelegate.h"
#import "ViewController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.rootViewController = [[ViewController alloc]init];
    [self.window makeKeyAndVisible];
    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: WKWebViewExtension/WKWebViewExtension/Example/ViewController.h
================================================
//
//  WKWebView + DeleteMenuItems.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@end



================================================
FILE: WKWebViewExtension/WKWebViewExtension/Example/ViewController.m
================================================
//
//  WKWebView + DeleteMenuItems.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "ViewController.h"
#import "WebView.h"
@interface DelegateHandler:NSObject <WKNavigationDelegate>
@end
@implementation DelegateHandler
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
    NSLog(@"External delegate");
}
@end

@interface ViewController ()<WKNavigationDelegate>
@property(nonatomic,strong,readwrite)WKWebView *webView;
@property(nonatomic,strong,readwrite)DelegateHandler *externalDelegate;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _externalDelegate = _externalDelegate = [[DelegateHandler alloc]init];
    
    [self.view addSubview:({
        _webView = [[WebView alloc]initWithFrame:self.view.bounds];
        [_webView useExternalNavigationDelegate];
        [_webView setMainNavigationDelegate:self];
        [_webView addExternalNavigationDelegate:_externalDelegate];
        [_webView loadHTMLString:[self _getHtmlString] baseURL:nil];
        _webView;
    })];
}

- (NSString *)_getHtmlString{
    NSMutableString *htmlString = @"<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"initial-scale=1.0, width=device-width, user-scalable=no,viewport-fit=cover\"/></head><body><br><br>".mutableCopy;
    for (int i = 0; i<3; i++) {
        [htmlString appendString:@"<h1 align=\"center\" style=\"color:rgb(28,135,219)\">HybridPageKit</h1><h4 align=\"center\">WKWebViewExtension</h4>"];
    }
    [htmlString appendString:@"<br><h3 align=\"center\" style=\"color:rgb(28,135,219)\">Long Press here - Test MenuItems</h3></a><br>"];
    [htmlString appendString:@"<a style=\"text-decoration:none;color:rgb(28,135,219);width:100%;text-align:center \" href= \"https://github.com/dequan1331/HybridPageKit\"><h3>Click here - Test Protocol with Log</h3></a><br>"];
    [htmlString appendString:@"<a style=\"text-decoration:none;color:rgb(28,135,219);width:100%;text-align:center \" href= \"testUA\"><h3>Click here - Test UA with Log</h3></a><br>"];
    [htmlString appendString:@"<a style=\"text-decoration:none;color:rgb(28,135,219);width:100%;text-align:center \" href= \"testScroll\"><h3>Click here - Test Scroll</h3></a><br>"];
    
    for (int i = 0; i<3; i++) {
        [htmlString appendString:@"<h1 align=\"center\" style=\"color:rgb(28,135,219)\">HybridPageKit</h1><h4 align=\"center\">WKWebViewExtension</h4>"];
    }
    [htmlString appendString:@"</body></html>"];
    return htmlString.copy;
}

#pragma mark -
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
 
    
    if ([navigationAction.request.URL.absoluteString isEqualToString:@"testUA"]) {
        decisionHandler(WKNavigationActionPolicyCancel);
        [self.webView safeAsyncEvaluateJavaScriptString:@"navigator.userAgent" completionBlock:^(NSObject *result) {
            NSLog(@"navigator.userAgent : %@",result);
        }];
        return;
    }
    
    if ([navigationAction.request.URL.absoluteString isEqualToString:@"testScroll"]) {
        decisionHandler(WKNavigationActionPolicyCancel);
        [self.webView scrollToOffset:50.f maxRunloops:50 completionBlock:^(BOOL success, NSInteger loopTimes) {
            NSLog(@"safe scroll with %@ loops", @(loopTimes));
        }];
        return;
    }

    decisionHandler(WKNavigationActionPolicyAllow);
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
    NSLog(@"Main delegate");
}
@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Example/WebView.h
================================================
//
//  WebView.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebViewExtensionsDef.h"

@interface WebView : WKWebView

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Example/WebView.m
================================================
//
//  WebView.m
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WebView.h"

@interface WebViewProtocol : NSURLProtocol
@end
@implementation WebViewProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request{
    return YES;
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    return request;
}
- (void)startLoading{
    NSLog(@"WebViewProtocol start loading");
}
- (void)stopLoading{
    NSLog(@"WebViewProtocol stop loading");
}
@end

@implementation WebView

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        [NSURLProtocol registerClass:[WebViewProtocol class]];
        
        [WKWebView fixWKWebViewMenuItems];
        [WKWebView supportProtocolWithHTTP:YES customSchemeArray:nil];
        [WKWebView configCustomUAWithType:kConfigUATypeAppend UAString:@"HybridPageKit"];
    }
    return self;
}

#pragma mark - UIResponder

- (BOOL)canBecomeFirstResponder {
    return YES;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if (action == @selector(cut:) || action == @selector(copy:) || action == @selector(paste:) ||
               action == @selector(delete:)) {
        return [super canPerformAction:action withSender:sender];
    }
    return NO;
}

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "size" : "20x20",
      "idiom" : "iphone",
      "filename" : "Icon-40@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "20x20",
      "idiom" : "iphone",
      "filename" : "Icon-60@3x.png",
      "scale" : "3x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "Icon-58@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "Icon-87@3x.png",
      "scale" : "3x"
    },
    {
      "size" : "40x40",
      "idiom" : "iphone",
      "filename" : "Icon-80@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "40x40",
      "idiom" : "iphone",
      "filename" : "Icon-120@3x.png",
      "scale" : "3x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "Icon-120@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "Icon-180@3x.png",
      "scale" : "3x"
    },
    {
      "size" : "1024x1024",
      "idiom" : "ios-marketing",
      "filename" : "icon-1024.png",
      "scale" : "1x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: WKWebViewExtension/WKWebViewExtension/Images.xcassets/LaunchImage.launchimage/Contents.json
================================================
{
  "images" : [
    {
      "extent" : "full-screen",
      "idiom" : "iphone",
      "subtype" : "2436h",
      "filename" : "375x812pt@3x.png",
      "minimum-system-version" : "11.0",
      "orientation" : "portrait",
      "scale" : "3x"
    },
    {
      "extent" : "full-screen",
      "idiom" : "iphone",
      "subtype" : "736h",
      "filename" : "414x736pt@3x.png",
      "minimum-system-version" : "8.0",
      "orientation" : "portrait",
      "scale" : "3x"
    },
    {
      "extent" : "full-screen",
      "idiom" : "iphone",
      "subtype" : "667h",
      "filename" : "375x667pt@2x.png",
      "minimum-system-version" : "8.0",
      "orientation" : "portrait",
      "scale" : "2x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "iphone",
      "filename" : "320x480pt@2x.png",
      "extent" : "full-screen",
      "minimum-system-version" : "7.0",
      "scale" : "2x"
    },
    {
      "extent" : "full-screen",
      "idiom" : "iphone",
      "subtype" : "retina4",
      "filename" : "320x568pt@2x.png",
      "minimum-system-version" : "7.0",
      "orientation" : "portrait",
      "scale" : "2x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: WKWebViewExtension/WKWebViewExtension/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleDisplayName</key>
	<string>WKWebViewExtension</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIcons</key>
	<dict/>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>0.0.1</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
	</array>
	<key>UIRequiresFullScreen</key>
	<true/>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
	</array>
</dict>
</plist>


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + DeleteMenuItems.h
================================================
//
//  WKWebView + DeleteMenuItems.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WKWebView (DeleteMenuItems)
/**
 *  Fix WKWebView MenuItems
 *  Delete System Items Without cut/copy/paste/delete
 */
+ (void)fixWKWebViewMenuItems;
@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + DeleteMenuItems.m
================================================
//
//  WKWebView + DeleteMenuItems.m
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebView + DeleteMenuItems.h"
#import <objc/runtime.h>

@implementation WKWebView (DeleteMenuItems)
+ (void)fixWKWebViewMenuItems {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,
                  ^{
                      Class cls = NSClassFromString([NSString stringWithFormat:@"%@%@%@%@", @"W", @"K", @"Content", @"View"]);
                      if (cls) {

                          SEL fixSel = @selector(canPerformAction:withSender:);
                          Method method = class_getInstanceMethod(cls, fixSel);

                          NSCAssert(NULL != method,
                                    @"Selector %@ not found in %@ methods of class %@.",
                                    NSStringFromSelector(fixSel),
                                    class_isMetaClass(cls) ? @"class" : @"instance",
                                    cls);

                          IMP originalIMP = method_getImplementation(class_getInstanceMethod(cls,fixSel));
                          BOOL (*originalImplementation_)(__unsafe_unretained id, SEL, SEL, id);

                          IMP newIMP = imp_implementationWithBlock( ^ BOOL (__unsafe_unretained id self, SEL action, id sender){
                              if (action == @selector(cut:) || action == @selector(copy:) ||
                                  action == @selector(paste:) || action == @selector(delete:)) {
                                  return ((__typeof(originalImplementation_))originalIMP)(self, fixSel,action, sender);
                              } else {
                                  return NO;
                              }
                          });

                          class_replaceMethod(cls, fixSel, newIMP,  method_getTypeEncoding(method));
                      } else {
                          NSLog(@"WKWebView (DeleteMenuItems) can not find valid class");
                      }
                  });
}
@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + ExternalNavigationDelegates.h
================================================
//
//  WKWebView + ExternalNavigationDelegates.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WKWebView (ExternalNavigationDelegates)

- (void) useExternalNavigationDelegate;
- (void) unUseExternalNavigationDelegate;

@property(nonatomic, weak) id<WKNavigationDelegate> mainNavigationDelegate;

- (void)addExternalNavigationDelegate:(id<WKNavigationDelegate>)delegate;
- (void)removeExternalNavigationDelegate:(id<WKNavigationDelegate>)delegate;
- (BOOL)containsExternalNavigationDelegate:(id<WKNavigationDelegate>)delegate;
- (void)clearExternalNavigationDelegates;


@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + ExternalNavigationDelegates.m
================================================
//
//  WKWebView + ExternalNavigationDelegates.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebView + ExternalNavigationDelegates.h"
#import <objc/runtime.h>

@interface _WKWebViewDelegateDispatcher : NSObject<WKNavigationDelegate>

@property(nonatomic, weak, readwrite) id<WKNavigationDelegate> mainNavigationDelegate;
@property(nonatomic, strong, readwrite) NSHashTable *weakNavigationDelegates;

- (void)addNavigationDelegate:(id<WKNavigationDelegate>)delegate;
- (void)removeNavigationDelegate:(id<WKNavigationDelegate>)delegate;
- (BOOL)containNavigationDelegate:(id<WKNavigationDelegate>)delegate;
- (void)removeAllNavigationDelegate;

@end

@implementation _WKWebViewDelegateDispatcher

- (instancetype)init {
    self = [super init];
    if (self) {
        _weakNavigationDelegates = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
    }
    return self;
}

#pragma mark -
- (void)addNavigationDelegate:(id<WKNavigationDelegate>)delegate {
    if (delegate && ![self.weakNavigationDelegates.allObjects containsObject:delegate]) {
        [_weakNavigationDelegates addObject:delegate];
    }
}
- (void)removeNavigationDelegate:(id<WKNavigationDelegate>)delegate {
    if (delegate) {
        [_weakNavigationDelegates removeObject:delegate];
    }
}
- (BOOL)containNavigationDelegate:(id<WKNavigationDelegate>)delegate {
    return delegate ? [_weakNavigationDelegates.allObjects containsObject:delegate] : NO;
}
- (void)removeAllNavigationDelegate {
    for (id<WKNavigationDelegate> delegate in _weakNavigationDelegates) {
        [_weakNavigationDelegates removeObject:delegate];
    }
}


#pragma mark -

- (void)webView:(WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    
    __block BOOL isResponse = NO;
    
    id<WKNavigationDelegate> mainDelegate = self.mainNavigationDelegate;
    
    if ([mainDelegate respondsToSelector:_cmd]) {
        [mainDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];
        isResponse = YES;
    } else {
        for (id delegate in self.weakNavigationDelegates.allObjects) {
            if ([delegate respondsToSelector:_cmd]) {
                [delegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];
                isResponse = YES;
            }
        };
    }
    
    if (!isResponse) {
        // for webview reuse
        decisionHandler(WKNavigationActionPolicyAllow);
    }
}

- (void)webView:(WKWebView *)webView
decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
    decisionHandler(WKNavigationResponsePolicyAllow);
}

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    
    id<WKNavigationDelegate> mainDelegate = self.mainNavigationDelegate;
    
    if ([mainDelegate respondsToSelector:_cmd]) {
        [mainDelegate webView:webView didCommitNavigation:navigation];
    }
    
    for (id delegate in self.weakNavigationDelegates.allObjects) {
        if ([delegate respondsToSelector:_cmd]) {
            [delegate webView:webView didCommitNavigation:navigation];
        }
    };
}

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
    
    id<WKNavigationDelegate> mainDelegate = self.mainNavigationDelegate;
    
    if ([mainDelegate respondsToSelector:_cmd]) {
        [mainDelegate webView:webView didStartProvisionalNavigation:navigation];
    }
    
    for (id delegate in self.weakNavigationDelegates.allObjects) {
        if ([delegate respondsToSelector:_cmd]) {
            [delegate webView:webView didStartProvisionalNavigation:navigation];
        }
    };
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    
    id<WKNavigationDelegate> mainDelegate = self.mainNavigationDelegate;
    
    if ([mainDelegate respondsToSelector:_cmd]) {
        [mainDelegate webView:webView didFinishNavigation:navigation];
    }
    
    for (id delegate in self.weakNavigationDelegates.allObjects) {
        if ([delegate respondsToSelector:_cmd]) {
            [delegate webView:webView didFinishNavigation:navigation];
        }
    };
}

- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    
    id<WKNavigationDelegate> mainDelegate = self.mainNavigationDelegate;
    
    if ([mainDelegate respondsToSelector:_cmd]) {
        [mainDelegate webView:webView didFailNavigation:navigation withError:error];
    }
    
    for (id delegate in self.weakNavigationDelegates.allObjects) {
        if ([delegate respondsToSelector:_cmd]) {
            [delegate webView:webView didFailNavigation:navigation withError:error];
        }
    };
}

- (void)webView:(WKWebView *)webView
didFailProvisionalNavigation:(WKNavigation *)navigation
      withError:(NSError *)error {
    
    id<WKNavigationDelegate> mainDelegate = self.mainNavigationDelegate;
    
    if ([mainDelegate respondsToSelector:_cmd]) {
        [mainDelegate webView:webView didFailProvisionalNavigation:navigation withError:error];
    }
    
    for (id delegate in self.weakNavigationDelegates.allObjects) {
        if ([delegate respondsToSelector:_cmd]) {
            [delegate webView:webView didFailProvisionalNavigation:navigation withError:error];
        }
    };
}

- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
    if (@available(iOS 9.0, *)) {
        id<WKNavigationDelegate> mainDelegate = self.mainNavigationDelegate;
        
        if ([mainDelegate respondsToSelector:_cmd]) {
            [mainDelegate webViewWebContentProcessDidTerminate:webView];
        }
        
        for (id delegate in self.weakNavigationDelegates.allObjects) {
            if ([delegate respondsToSelector:_cmd]) {
                [delegate webViewWebContentProcessDidTerminate:webView];
            }
        };
    }
#endif
}

- (void)webView:(WKWebView *)webView
didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
    
    id<WKNavigationDelegate> mainDelegate = self.mainNavigationDelegate;
    
    if ([mainDelegate respondsToSelector:_cmd]) {
        [mainDelegate webView:webView didReceiveServerRedirectForProvisionalNavigation:navigation];
    }
    
    for (id delegate in self.weakNavigationDelegates.allObjects) {
        if ([delegate respondsToSelector:_cmd]) {
            [delegate webView:webView didReceiveServerRedirectForProvisionalNavigation:navigation];
        }
    };
}

@end

#pragma mark -
#pragma mark -

@interface WKWebView()
@property(nonatomic, assign, readwrite) BOOL isUseExternalDelegate;
@property(nonatomic, strong, readwrite) _WKWebViewDelegateDispatcher *delegateDispatcher;
@property(nonatomic, strong, readwrite) id<WKNavigationDelegate> originalNavigationDelegate;
@end

@implementation WKWebView (ExternalNavigationDelegates)

- (void)setIsUseExternalDelegate:(BOOL)isUseExternalDelegate{
    objc_setAssociatedObject(self, @"isUseExternalDelegate", @(isUseExternalDelegate), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)isUseExternalDelegate{
    NSNumber *isUseExternalDelegate = objc_getAssociatedObject(self, @"isUseExternalDelegate");
    return isUseExternalDelegate.boolValue;
}

- (void)setDelegateDispatcher:(_WKWebViewDelegateDispatcher *)delegateDispatcher{
    objc_setAssociatedObject(self, @"delegateDispatcher", delegateDispatcher, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (_WKWebViewDelegateDispatcher *)delegateDispatcher{
    return objc_getAssociatedObject(self, @"delegateDispatcher");
}

- (void)setOriginalNavigationDelegate:(id<WKNavigationDelegate>)originalNavigationDelegate{
    objc_setAssociatedObject(self, @"originalNavigationDelegate", originalNavigationDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id<WKNavigationDelegate>)originalNavigationDelegate{
    return objc_getAssociatedObject(self, @"originalNavigationDelegate");
}

- (void)useExternalNavigationDelegate{
    
    if ([self isUseExternalDelegate] && [self delegateDispatcher]) {
        return;
    }
    
    [self setDelegateDispatcher:[[_WKWebViewDelegateDispatcher alloc] init]];
    [self setOriginalNavigationDelegate:self.navigationDelegate];
    
    [self setNavigationDelegate:[self delegateDispatcher]];
    [[self delegateDispatcher] addNavigationDelegate:[self originalNavigationDelegate]];
    
    [self setIsUseExternalDelegate:YES];
}
- (void)unUseExternalNavigationDelegate{
    
    [self setNavigationDelegate:[self originalNavigationDelegate]];
    
    [self setDelegateDispatcher:nil];
    [self setIsUseExternalDelegate:NO];
}
- (void)setMainNavigationDelegate:(id<WKNavigationDelegate>)mainDelegate {
    [self delegateDispatcher].mainNavigationDelegate = mainDelegate;
}
- (id<WKNavigationDelegate>)mainNavigationDelegate {
    return [self delegateDispatcher].mainNavigationDelegate;
}
- (void)addExternalNavigationDelegate:(id<WKNavigationDelegate>)delegate {
    [[self delegateDispatcher] addNavigationDelegate:delegate];
}
- (void)removeExternalNavigationDelegate:(id<WKNavigationDelegate>)delegate {
    [[self delegateDispatcher] removeNavigationDelegate:delegate];
}
- (BOOL)containsExternalNavigationDelegate:(id<WKNavigationDelegate>)delegate {
    return [[self delegateDispatcher] containNavigationDelegate:delegate];
}
- (void)clearExternalNavigationDelegates {
    [[self delegateDispatcher] removeAllNavigationDelegate];
}

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeClearCache.h
================================================
//
//  WKWebView + SafeClearCache.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WKWebView (SafeClearCache)
/**
 *  WKWebView Clear All Cache Include iOS8
 */
+ (void)safeClearAllCache;

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeClearCache.m
================================================
//
//  WKWebView + SafeClearCache.m
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebView + SafeClearCache.h"

@implementation WKWebView (SafeClearCache)

+ (void)safeClearAllCache {
    
    if ([[NSProcessInfo processInfo] operatingSystemVersion].majorVersion > 9){
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
        if (@available(iOS 9.0, *)) {
            NSSet *websiteDataTypes = [NSSet setWithArray:@[
                                                            WKWebsiteDataTypeMemoryCache,
                                                            WKWebsiteDataTypeSessionStorage,
                                                            WKWebsiteDataTypeDiskCache,
                                                            WKWebsiteDataTypeOfflineWebApplicationCache,
                                                            WKWebsiteDataTypeCookies,
                                                            WKWebsiteDataTypeLocalStorage,
                                                            WKWebsiteDataTypeIndexedDBDatabases,
                                                            WKWebsiteDataTypeWebSQLDatabases
                                                            ]];
            
            NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
            [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes
                                                       modifiedSince:dateFrom
                                                   completionHandler:^{
                                                       NSLog(@"WKWebView (SafeClearCache) Clear All Cache Done");
                                          }];
        }
#endif
    } else {
        // iOS8
        NSSet *websiteDataTypes = [NSSet setWithArray:@[
                                                        @"WKWebsiteDataTypeCookies",
                                                        @"WKWebsiteDataTypeLocalStorage",
                                                        @"WKWebsiteDataTypeIndexedDBDatabases",
                                                        @"WKWebsiteDataTypeWebSQLDatabases"
                                                        ]];
        for (NSString *type in websiteDataTypes) {
            clearWebViewCacheFolderByType(type);
        }
    }
}

static inline void clearWebViewCacheFolderByType(NSString *cacheType) {
    
    static dispatch_once_t once;
    static NSDictionary *cachePathMap = nil;

    dispatch_once(&once,
                  ^{
                      NSString *bundleId = [NSBundle mainBundle].infoDictionary[(NSString *)kCFBundleIdentifierKey];
                      NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
                      NSString *storageFileBasePath = [libraryPath stringByAppendingPathComponent:
                                                       [NSString stringWithFormat:@"WebKit/%@/WebsiteData/", bundleId]];
                      
                      cachePathMap = @{@"WKWebsiteDataTypeCookies":
                                       [libraryPath stringByAppendingPathComponent:@"Cookies/Cookies.binarycookies"],
                                       @"WKWebsiteDataTypeLocalStorage":
                                       [storageFileBasePath stringByAppendingPathComponent:@"LocalStorage"],
                                       @"WKWebsiteDataTypeIndexedDBDatabases":
                                       [storageFileBasePath stringByAppendingPathComponent:@"IndexedDB"],
                                       @"WKWebsiteDataTypeWebSQLDatabases":
                                       [storageFileBasePath stringByAppendingPathComponent:@"WebSQL"]
                                       };
                  });
    
    NSString *filePath = cachePathMap[cacheType];
    if (filePath && filePath.length > 0) {
        if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
            NSError *error = nil;
            [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
            if (error) {
                NSLog(@"removed file fail: %@ ,error %@", [filePath lastPathComponent], error);
            }
        }
    }
}

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeCookies.h
================================================
//
//  WKWebView + SafeCookies.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WKWebView (SafeCookies)

- (void)setCookieWithName:(NSString *)name
                    value:(NSString *)value
                   domain:(NSString *)domain
                     path:(NSString *)path
              expiresDate:(NSDate *)expiresDate;

- (void)deleteCookiesWithName:(NSString *)name;

- (NSSet<NSString *> *)getAllCustomCookiesName;
- (void)deleteAllCustomCookies;

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeCookies.m
================================================
//
//  WKWebView + SafeCookies.m
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebView + SafeCookies.h"
#import "WKWebView + SafeEvaluateJS.h"
#import <objc/runtime.h>

@interface WKWebView()
@property(nonatomic,strong,readwrite)NSMutableDictionary<NSString *, NSString *> *HPKCookieDic;
@end

@implementation WKWebView (SafeCookies)

- (void)setHPKCookieDic:(NSMutableDictionary *)HPKCookieDic{
    objc_setAssociatedObject(self, @"HPKCookieDic", HPKCookieDic, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSMutableDictionary *)HPKCookieDic{
    NSMutableDictionary *HPKCookieDic = objc_getAssociatedObject(self, @"HPKCookieDic");
    if (!HPKCookieDic) {
        HPKCookieDic = @{}.mutableCopy;
    }
    return HPKCookieDic;
}

- (void)setCookieWithName:(NSString *)name
                    value:(NSString *)value
                   domain:(NSString *)domain
                     path:(NSString *)path
              expiresDate:(NSDate *)expiresDate{
    if(!name || name.length <=0){
        return;
    }
    
    NSMutableString *cookieScript = [[NSMutableString alloc] init];
    [cookieScript appendFormat:@"document.cookie='%@=%@;",name,value];
    if(domain || domain.length > 0){
        [cookieScript appendFormat:@"domain=%@;",domain];
    }
    if(path || path.length > 0){
        [cookieScript appendFormat:@"path=%@;",path];
    }
    
    [[self HPKCookieDic] setValue:cookieScript.copy forKey:name];
    
    if([expiresDate timeIntervalSince1970] != 0){
        [cookieScript appendFormat:@"expires='+(new Date(%@).toUTCString());", @(([expiresDate timeIntervalSince1970]) * 1000)];
    }
    [cookieScript appendFormat:@"\n"];

    [self safeAsyncEvaluateJavaScriptString:cookieScript.copy];
}

- (void)deleteCookiesWithName:(NSString *)name{
    if(!name || name.length <=0){
        return;
    }
    
    if (![[[self HPKCookieDic] allKeys] containsObject:name]) {
        return;
    }

    NSMutableString *cookieScript = [[NSMutableString alloc] init];
    
    [cookieScript appendString:[[self HPKCookieDic] objectForKey:name]];
    [cookieScript appendFormat:@"expires='+(new Date(%@).toUTCString());\n",@(0)];
    
    [[self HPKCookieDic] removeObjectForKey:name];
    [self safeAsyncEvaluateJavaScriptString:cookieScript.copy];
}

- (NSSet<NSString *> *)getAllCustomCookiesName{
    return [[self HPKCookieDic] allKeys].copy;
}
- (void)deleteAllCustomCookies{
    for (NSString *cookieName in [[self HPKCookieDic] allKeys]) {
        [self deleteCookiesWithName:cookieName];
    }
}

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeEvaluateJS.h
================================================
//
//  WKWebView + SafeEvaluateJS.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

typedef void (^SafeEvaluateJSCompletion)(NSObject *result);

@interface WKWebView (SafeEvaluateJS)
/**
 *  Safe Evaluate JS And Retainify Webview For CallBack
 */
- (void)safeAsyncEvaluateJavaScriptString:(NSString *)script;

/**
 *  Safe Evaluate JS And Retainify Webview For CallBack
 *  Make Sure CallBack IS NSString
 */
- (void)safeAsyncEvaluateJavaScriptString:(NSString *)script completionBlock:(SafeEvaluateJSCompletion)block;

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeEvaluateJS.m
================================================
//
//  WKWebView + SafeEvaluateJS.m
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebView + SafeEvaluateJS.h"

@implementation WKWebView (SafeEvaluateJS)

- (void)safeAsyncEvaluateJavaScriptString:(NSString *)script{
    [self safeAsyncEvaluateJavaScriptString:script completionBlock:nil];
}
- (void)safeAsyncEvaluateJavaScriptString:(NSString *)script completionBlock:(SafeEvaluateJSCompletion)block{
    if (!script) {
        return;
    }
    [self evaluateJavaScript:script
            completionHandler:^(id result, NSError *_Nullable error) {
                // retainify self
                __unused __attribute__((objc_ownership(strong))) __typeof__(self) self_retain_ = self;
                
                if (!error) {
                    if (block) {
                        if (!result || [result isKindOfClass:[NSNull class]]) {
                            block(@"");
                        } else if ([result isKindOfClass:[NSObject class]]) {
                            block((NSObject *)result);
                        }  else {
                            NSAssert(NO,@"WKWebView (SafeEvaluateJS) evaluate js return type:%@,js:%@",
                                      NSStringFromClass([result class]),
                                      script);
                        }
                    }
                } else {
                    NSLog(@"WKWebView evaluate js Error : %@ %@", error.description, script);
                    if (block) {
                        block(@"");
                    }
                }
            }];
}

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeScrollTo.h
================================================
//
//  WKWebView + SafeScrollTo.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

typedef void (^SafeScrollToCompletionBlock)(BOOL success , NSInteger loopTimes);

@interface WKWebView (SafeScrollTo)
/**
 *  WKWebView Safe ScrollTo Specific Offset Without Blank Screen
 *
 *  @param offset               webView Offset
 *  @param maxRunloops          max wait runloops
 *  @param completionBlock      complete block
 */
- (void)scrollToOffset:(CGFloat)offset
           maxRunloops:(NSUInteger)maxRunloops
       completionBlock:(SafeScrollToCompletionBlock)completionBlock;

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeScrollTo.m
================================================
//
//  WKWebView + SafeScrollTo.m
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebView + SafeScrollTo.h"

typedef BOOL (^RunloopUtilsConditionBlock)(void);
typedef void (^RunloopUtilsSuccessBlock)(NSInteger loopTimes);
typedef void (^RunloopUtilsFailBlock)(NSInteger loopTimes);

@interface RunloopUtils : NSObject

@property(nonatomic, assign, readwrite) CFRunLoopObserverRef observer;
@property(nonatomic, assign, readwrite) CFRunLoopRef runLoop;

@property(nonatomic, copy, readwrite) RunloopUtilsConditionBlock conditionBlock;
@property(nonatomic, copy, readwrite) RunloopUtilsSuccessBlock successBlock;
@property(nonatomic, copy, readwrite) RunloopUtilsFailBlock failBlock;

@property(nonatomic, weak, readwrite) id holder;
@property(nonatomic, assign, readwrite) NSInteger maxLoopTimes;
@property(nonatomic, assign, readwrite) NSInteger currentLoopNum;

+ (instancetype)sharedInstance;

- (void)startRunloopCheckWithHolder:(id)holder
                       MaxLoopTimes:(NSInteger)maxLoopTimes
                          condition:(RunloopUtilsConditionBlock)conditionBlock
                       successBlock:(RunloopUtilsSuccessBlock)successBlock
                          failBlock:(RunloopUtilsFailBlock)failedBlock;

- (void)stopRunloopCheckWithHolder:(id)holder;

@end

@implementation RunloopUtils

+ (instancetype)sharedInstance{
    static RunloopUtils *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[RunloopUtils alloc]init];
    });
    return sharedInstance;
}

- (void)dealloc {
    if (CFRunLoopContainsObserver(CFRunLoopGetMain(), _observer, kCFRunLoopDefaultMode)) {
        CFRunLoopRemoveObserver(CFRunLoopGetMain(), _observer, kCFRunLoopDefaultMode);
    }
    if (CFRunLoopObserverIsValid(_observer)) {
        CFRunLoopObserverInvalidate(_observer);
    }
    if (_observer != NULL) {
        CFRelease(_observer);
        _observer = NULL;
    }
    if (_runLoop != NULL) {
        CFRelease(_runLoop);
        _runLoop = NULL;
    }
    _conditionBlock = nil;
    _successBlock = nil;
    _failBlock = nil;
    _holder = nil;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        
        _runLoop = (CFRunLoopRef)CFRetain(CFRunLoopGetMain());
        
        __weak typeof(self) weakSelf = self;
        _observer = CFRunLoopObserverCreateWithHandler(
                                                       NULL,
                                                       kCFRunLoopAllActivities,
                                                       YES,
                                                       0,
                                                       ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
                                                           switch (activity) {
                                                               case kCFRunLoopBeforeWaiting:
                                                                   if (weakSelf.currentLoopNum > weakSelf.maxLoopTimes) {
                                                                       if (self.failBlock) {
                                                                           self.failBlock(self.currentLoopNum);
                                                                       }
                                                                       [weakSelf _stopRetryFunction];
                                                                   } else {
                                                                       if (weakSelf.conditionBlock()) {
                                                                           if (self.successBlock) {
                                                                               self.successBlock(self.currentLoopNum);
                                                                           }
                                                                           [weakSelf _stopRetryFunction];
                                                                       } else {
                                                                           weakSelf.currentLoopNum++;
                                                                       }
                                                                   }
                                                                   break;
                                                               case kCFRunLoopExit:
                                                                   // main runloop never exit
                                                                   if (self.failBlock) {
                                                                       self.failBlock(self.currentLoopNum);
                                                                   }
                                                                   [weakSelf _stopRetryFunction];
                                                                   break;
                                                               default:
                                                                   break;
                                                           }
                                                       });
    }
    return self;
}

- (void)startRunloopCheckWithHolder:(id)holder
                       MaxLoopTimes:(NSInteger)maxLoopTimes
                          condition:(RunloopUtilsConditionBlock)conditionBlock
                       successBlock:(RunloopUtilsSuccessBlock)successBlock
                          failBlock:(RunloopUtilsFailBlock)failBlock{
    
    if (_observer == NULL || _runLoop == NULL) {
        return;
    }
    
    if (CFRunLoopContainsObserver(_runLoop, _observer, kCFRunLoopDefaultMode)) {
        CFRunLoopRemoveObserver(_runLoop, _observer, kCFRunLoopDefaultMode);
        if (self.failBlock) {
            self.failBlock(self.currentLoopNum);
        }
    }
    
    NSParameterAssert(conditionBlock != NULL);
    NSParameterAssert(successBlock != NULL);
    NSParameterAssert(failBlock != NULL);
    NSParameterAssert(holder != nil);
    
    _maxLoopTimes = maxLoopTimes;
    _conditionBlock = [conditionBlock copy];
    _successBlock = [successBlock copy];
    _failBlock = [failBlock copy];
    _currentLoopNum = 1;
    _holder = holder;
    
    [self _beginRetryFunction];
    
}

- (void)stopRunloopCheckWithHolder:(id)holder{
    if (CFRunLoopContainsObserver(CFRunLoopGetMain(), _observer, kCFRunLoopDefaultMode)) {
        if (holder == _holder) {
            [self _stopRetryFunction];
        } else {
        }
    }
}

#pragma mark - private method

- (void)_beginRetryFunction {
    
    if (CFRunLoopContainsObserver(_runLoop, _observer, kCFRunLoopDefaultMode)) {
        CFRunLoopRemoveObserver(_runLoop, _observer, kCFRunLoopDefaultMode);
    }
    
    CFRunLoopAddObserver(_runLoop, _observer, kCFRunLoopDefaultMode);
}

- (void)_stopRetryFunction {
    
    if (CFRunLoopContainsObserver(CFRunLoopGetMain(), _observer, kCFRunLoopDefaultMode)) {
        CFRunLoopRemoveObserver(CFRunLoopGetMain(), _observer, kCFRunLoopDefaultMode);
    }
    
    _maxLoopTimes = 0;
    _conditionBlock = nil;
    _successBlock = nil;
    _failBlock = nil;
    _currentLoopNum = 1;
    _holder = nil;
}

@end


@implementation WKWebView (SafeScrollTo)

- (void)scrollToOffset:(CGFloat)offset
           maxRunloops:(NSUInteger)maxRunloops
       completionBlock:(SafeScrollToCompletionBlock)completionBlock{
    
    
    if(offset < 0 || maxRunloops <= 0){
        NSLog(@"WKWebView can not scroll to with invalid paras");
        return;
    }
    
    [[RunloopUtils sharedInstance] stopRunloopCheckWithHolder:self];
    
    [[RunloopUtils sharedInstance] startRunloopCheckWithHolder:self MaxLoopTimes:maxRunloops condition:^BOOL{
        return self.scrollView.contentSize.height >= offset;
    } successBlock:^(NSInteger loopTimes) {
        [self.scrollView setContentOffset:CGPointMake(0, offset) animated:YES];
        if(completionBlock){
            completionBlock(YES,loopTimes);
        }
    } failBlock:^(NSInteger loopTimes) {
        if(completionBlock){
            completionBlock(NO,loopTimes);
        }
    }];
}

@end





================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SupportProtocol.h
================================================
//
//  WKWebView + SupportProtocol.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WKWebView (SupportProtocol)
/**
 *  WKWebView Support Protocol Like UIWebView
 *
 *  @param supportHTTP         support protocol for HTTP & HTTPS
 *  @param customSchemeArray   support protocol fro custom scheme
 */
+ (void) supportProtocolWithHTTP:(BOOL)supportHTTP
               customSchemeArray:(NSArray<NSString *> *)customSchemeArray;

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SupportProtocol.m
================================================
//
//  WKWebView + SupportProtocol.m
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebView + SupportProtocol.h"

@implementation WKWebView (SupportProtocol)

+ (void) supportProtocolWithHTTP:(BOOL)supportHTTP
               customSchemeArray:(NSArray<NSString *> *)customSchemeArray{

    if (!supportHTTP && [customSchemeArray count] <= 0) {
        return;
    }
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,
                  ^{
                      Class cls = NSClassFromString([NSString stringWithFormat:@"%@%@%@%@%@", @"W", @"K", @"Browsing", @"Context", @"Controller"]);
                      SEL sel = NSSelectorFromString([NSString stringWithFormat:@"%@%@%@%@%@", @"register", @"SchemeFor", @"Custom", @"Protocol", @":"]);
                      
                      if (!cls || !sel || ![cls respondsToSelector:sel]) {
                          NSLog(@"WKWebView (SupportProtocol) has invalid cls or sel");
                          return;
                      }
                      
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
                      if (supportHTTP) {
                          [cls performSelector:sel withObject:@"http"];
                          [cls performSelector:sel withObject:@"https"];
                      }
                      
                      for (NSString *scheme in customSchemeArray) {
                          [cls performSelector:sel withObject:scheme];
                      }
#pragma clang diagnostic pop
                  });
}


@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SyncConfigUA.h
================================================
//
//  WKWebView + SyncConfigUA.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

typedef NS_ENUM (NSInteger, ConfigUAType){
    kConfigUATypeReplace,     //replace all UA string
    kConfigUATypeAppend,      //append to original UA string
};

@interface WKWebView (SyncConfigUA)
/**
 *  Sync Config UA Without WKWebView
 *
 *  @param type            replace or append original UA
 *  @param customString    custom UA string
 */
+ (void)configCustomUAWithType:(ConfigUAType)type
                      UAString:(NSString *)customString;

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SyncConfigUA.m
================================================
//
//  WKWebView + SyncConfigUA.m
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebView + SyncConfigUA.h"

@implementation WKWebView (SyncConfigUA)

+ (void)configCustomUAWithType:(ConfigUAType)type
                      UAString:(NSString *)customString{
    
    if (!customString || customString.length <= 0) {
        NSLog(@"WKWebView (SyncConfigUA) config with invalid string");
        return;
    }
    
    if(type == kConfigUATypeReplace){
        NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:customString, @"UserAgent", nil];
        [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
    }else if (type == kConfigUATypeAppend){
        UIWebView *webView = [[UIWebView alloc] init];
        NSString *originalUserAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
        NSString *appUserAgent =
        [NSString stringWithFormat:@"%@-%@", originalUserAgent, customString];
        NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:appUserAgent, @"UserAgent", nil];
        [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
    }else{
        NSLog(@"WKWebView (SyncConfigUA) config with invalid type :%@", @(type));
    }
}

@end


================================================
FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebViewExtensionsDef.h
================================================
//
//  WKWebViewExtensionsDef.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import "WKWebView + DeleteMenuItems.h"
#import "WKWebView + SupportProtocol.h"
#import "WKWebView + SafeClearCache.h"
#import "WKWebView + SafeScrollTo.h"
#import "WKWebView + SafeEvaluateJS.h"
#import "WKWebView + ExternalNavigationDelegates.h"
#import "WKWebView + SyncConfigUA.h"
#import "WKWebView + SafeCookies.h"



================================================
FILE: WKWebViewExtension/WKWebViewExtension/main.m
================================================
//
//  WKWebView + DeleteMenuItems.h
//  WKWebViewExtension
//
//  Created by dequanzhu.
//  Copyright © 2018 HybridPageKit. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}


================================================
FILE: WKWebViewExtension/WKWebViewExtension.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 48;
	objects = {

/* Begin PBXBuildFile section */
		5E7A05D0205EB999006CA1E9 /* WKWebView + DeleteMenuItems.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7A05CF205EB999006CA1E9 /* WKWebView + DeleteMenuItems.m */; };
		5E7A05D6205EB9F8006CA1E9 /* WKWebView + SyncConfigUA.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7A05D5205EB9F8006CA1E9 /* WKWebView + SyncConfigUA.m */; };
		5E7A05DC205EC434006CA1E9 /* WKWebView + ExternalNavigationDelegates.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7A05DB205EC434006CA1E9 /* WKWebView + ExternalNavigationDelegates.m */; };
		5EAAADBD205CB80000D8EE75 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAAADBC205CB80000D8EE75 /* AppDelegate.m */; };
		5EAAADC0205CB80000D8EE75 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAAADBF205CB80000D8EE75 /* ViewController.m */; };
		5EAAADCB205CB80000D8EE75 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAAADCA205CB80000D8EE75 /* main.m */; };
		5EAAADF1205CBB5200D8EE75 /* WKWebView + SafeEvaluateJS.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAAADE0205CBB5100D8EE75 /* WKWebView + SafeEvaluateJS.m */; };
		5EAAADF2205CBB5200D8EE75 /* WKWebView + SafeScrollTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAAADE2205CBB5100D8EE75 /* WKWebView + SafeScrollTo.m */; };
		5EAAADF5205CBB5200D8EE75 /* WKWebView + SafeClearCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAAADEA205CBB5200D8EE75 /* WKWebView + SafeClearCache.m */; };
		5EAAADF8205CBB5200D8EE75 /* WKWebView + SupportProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAAADF0205CBB5200D8EE75 /* WKWebView + SupportProtocol.m */; };
		5EC64FE3206BA5CD0079B197 /* WKWebView + SafeCookies.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EC64FE2206BA5CD0079B197 /* WKWebView + SafeCookies.m */; };
		B944DC35206A353000BD0F06 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B944DC34206A353000BD0F06 /* Images.xcassets */; };
		B94ECF5F206A55CA0023245F /* WebView.m in Sources */ = {isa = PBXBuildFile; fileRef = B94ECF5E206A55CA0023245F /* WebView.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
		5EAAADD1205CB80000D8EE75 /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = 5EAAADB0205CB80000D8EE75 /* Project object */;
			proxyType = 1;
			remoteGlobalIDString = 5EAAADB7205CB80000D8EE75;
			remoteInfo = WKWebViewExtension;
		};
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
		5E7A05CE205EB999006CA1E9 /* WKWebView + DeleteMenuItems.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WKWebView + DeleteMenuItems.h"; sourceTree = "<group>"; };
		5E7A05CF205EB999006CA1E9 /* WKWebView + DeleteMenuItems.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "WKWebView + DeleteMenuItems.m"; sourceTree = "<group>"; };
		5E7A05D4205EB9F8006CA1E9 /* WKWebView + SyncConfigUA.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WKWebView + SyncConfigUA.h"; sourceTree = "<group>"; };
		5E7A05D5205EB9F8006CA1E9 /* WKWebView + SyncConfigUA.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "WKWebView + SyncConfigUA.m"; sourceTree = "<group>"; };
		5E7A05DA205EC434006CA1E9 /* WKWebView + ExternalNavigationDelegates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WKWebView + ExternalNavigationDelegates.h"; sourceTree = "<group>"; };
		5E7A05DB205EC434006CA1E9 /* WKWebView + ExternalNavigationDelegates.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "WKWebView + ExternalNavigationDelegates.m"; sourceTree = "<group>"; };
		5EAAADB8205CB80000D8EE75 /* WKWebViewExtension.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WKWebViewExtension.app; sourceTree = BUILT_PRODUCTS_DIR; };
		5EAAADBB205CB80000D8EE75 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
		5EAAADBC205CB80000D8EE75 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
		5EAAADBE205CB80000D8EE75 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
		5EAAADBF205CB80000D8EE75 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
		5EAAADC9205CB80000D8EE75 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		5EAAADCA205CB80000D8EE75 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
		5EAAADD0205CB80000D8EE75 /* WKWebViewExtensionTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WKWebViewExtensionTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
		5EAAADE0205CBB5100D8EE75 /* WKWebView + SafeEvaluateJS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WKWebView + SafeEvaluateJS.m"; sourceTree = "<group>"; };
		5EAAADE1205CBB5100D8EE75 /* WKWebView + SafeClearCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WKWebView + SafeClearCache.h"; sourceTree = "<group>"; };
		5EAAADE2205CBB5100D8EE75 /* WKWebView + SafeScrollTo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WKWebView + SafeScrollTo.m"; sourceTree = "<group>"; };
		5EAAADE6205CBB5200D8EE75 /* WKWebView + SafeEvaluateJS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WKWebView + SafeEvaluateJS.h"; sourceTree = "<group>"; };
		5EAAADE7205CBB5200D8EE75 /* WKWebView + SupportProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WKWebView + SupportProtocol.h"; sourceTree = "<group>"; };
		5EAAADEA205CBB5200D8EE75 /* WKWebView + SafeClearCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WKWebView + SafeClearCache.m"; sourceTree = "<group>"; };
		5EAAADEB205CBB5200D8EE75 /* WKWebView + SafeScrollTo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WKWebView + SafeScrollTo.h"; sourceTree = "<group>"; };
		5EAAADED205CBB5200D8EE75 /* WKWebViewExtensionsDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewExtensionsDef.h; sourceTree = "<group>"; };
		5EAAADF0205CBB5200D8EE75 /* WKWebView + SupportProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WKWebView + SupportProtocol.m"; sourceTree = "<group>"; };
		5EC64FE1206BA5CD0079B197 /* WKWebView + SafeCookies.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WKWebView + SafeCookies.h"; sourceTree = "<group>"; };
		5EC64FE2206BA5CD0079B197 /* WKWebView + SafeCookies.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "WKWebView + SafeCookies.m"; sourceTree = "<group>"; };
		B944DC34206A353000BD0F06 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
		B94ECF5D206A55CA0023245F /* WebView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebView.h; sourceTree = "<group>"; };
		B94ECF5E206A55CA0023245F /* WebView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebView.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		5EAAADB5205CB80000D8EE75 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		5EAAADCD205CB80000D8EE75 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		5EAAADAF205CB80000D8EE75 = {
			isa = PBXGroup;
			children = (
				5EAAADBA205CB80000D8EE75 /* WKWebViewExtension */,
				5EAAADB9205CB80000D8EE75 /* Products */,
			);
			sourceTree = "<group>";
		};
		5EAAADB9205CB80000D8EE75 /* Products */ = {
			isa = PBXGroup;
			children = (
				5EAAADB8205CB80000D8EE75 /* WKWebViewExtension.app */,
				5EAAADD0205CB80000D8EE75 /* WKWebViewExtensionTests.xctest */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		5EAAADBA205CB80000D8EE75 /* WKWebViewExtension */ = {
			isa = PBXGroup;
			children = (
				5EE6AFA2206A8A5A004B7A5B /* Example */,
				5EAAADDF205CBAD800D8EE75 /* Source */,
				5EAAADBB205CB80000D8EE75 /* AppDelegate.h */,
				5EAAADBC205CB80000D8EE75 /* AppDelegate.m */,
				5EAAADC9205CB80000D8EE75 /* Info.plist */,
				5EAAADCA205CB80000D8EE75 /* main.m */,
				B944DC34206A353000BD0F06 /* Images.xcassets */,
			);
			path = WKWebViewExtension;
			sourceTree = "<group>";
		};
		5EAAADDF205CBAD800D8EE75 /* Source */ = {
			isa = PBXGroup;
			children = (
				5E7A05CE205EB999006CA1E9 /* WKWebView + DeleteMenuItems.h */,
				5E7A05CF205EB999006CA1E9 /* WKWebView + DeleteMenuItems.m */,
				5EAAADE7205CBB5200D8EE75 /* WKWebView + SupportProtocol.h */,
				5EAAADF0205CBB5200D8EE75 /* WKWebView + SupportProtocol.m */,
				5EAAADE1205CBB5100D8EE75 /* WKWebView + SafeClearCache.h */,
				5EAAADEA205CBB5200D8EE75 /* WKWebView + SafeClearCache.m */,
				5EAAADEB205CBB5200D8EE75 /* WKWebView + SafeScrollTo.h */,
				5EAAADE2205CBB5100D8EE75 /* WKWebView + SafeScrollTo.m */,
				5EAAADE6205CBB5200D8EE75 /* WKWebView + SafeEvaluateJS.h */,
				5EAAADE0205CBB5100D8EE75 /* WKWebView + SafeEvaluateJS.m */,
				5E7A05DA205EC434006CA1E9 /* WKWebView + ExternalNavigationDelegates.h */,
				5E7A05DB205EC434006CA1E9 /* WKWebView + ExternalNavigationDelegates.m */,
				5E7A05D4205EB9F8006CA1E9 /* WKWebView + SyncConfigUA.h */,
				5E7A05D5205EB9F8006CA1E9 /* WKWebView + SyncConfigUA.m */,
				5EC64FE1206BA5CD0079B197 /* WKWebView + SafeCookies.h */,
				5EC64FE2206BA5CD0079B197 /* WKWebView + SafeCookies.m */,
				5EAAADED205CBB5200D8EE75 /* WKWebViewExtensionsDef.h */,
			);
			path = Source;
			sourceTree = "<group>";
		};
		5EE6AFA2206A8A5A004B7A5B /* Example */ = {
			isa = PBXGroup;
			children = (
				5EAAADBE205CB80000D8EE75 /* ViewController.h */,
				5EAAADBF205CB80000D8EE75 /* ViewController.m */,
				B94ECF5D206A55CA0023245F /* WebView.h */,
				B94ECF5E206A55CA0023245F /* WebView.m */,
			);
			path = Example;
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
		5EAAADB7205CB80000D8EE75 /* WKWebViewExtension */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 5EAAADD9205CB80000D8EE75 /* Build configuration list for PBXNativeTarget "WKWebViewExtension" */;
			buildPhases = (
				5EAAADB4205CB80000D8EE75 /* Sources */,
				5EAAADB5205CB80000D8EE75 /* Frameworks */,
				5EAAADB6205CB80000D8EE75 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = WKWebViewExtension;
			productName = WKWebViewExtension;
			productReference = 5EAAADB8205CB80000D8EE75 /* WKWebViewExtension.app */;
			productType = "com.apple.product-type.application";
		};
		5EAAADCF205CB80000D8EE75 /* WKWebViewExtensionTests */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 5EAAADDC205CB80000D8EE75 /* Build configuration list for PBXNativeTarget "WKWebViewExtensionTests" */;
			buildPhases = (
				5EAAADCC205CB80000D8EE75 /* Sources */,
				5EAAADCD205CB80000D8EE75 /* Frameworks */,
				5EAAADCE205CB80000D8EE75 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
				5EAAADD2205CB80000D8EE75 /* PBXTargetDependency */,
			);
			name = WKWebViewExtensionTests;
			productName = WKWebViewExtensionTests;
			productReference = 5EAAADD0205CB80000D8EE75 /* WKWebViewExtensionTests.xctest */;
			productType = "com.apple.product-type.bundle.unit-test";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		5EAAADB0205CB80000D8EE75 /* Project object */ = {
			isa = PBXProject;
			attributes = {
				LastUpgradeCheck = 0910;
				ORGANIZATIONNAME = HybridPageKit;
				TargetAttributes = {
					5EAAADB7205CB80000D8EE75 = {
						CreatedOnToolsVersion = 9.1;
						ProvisioningStyle = Manual;
					};
					5EAAADCF205CB80000D8EE75 = {
						CreatedOnToolsVersion = 9.1;
						ProvisioningStyle = Automatic;
						TestTargetID = 5EAAADB7205CB80000D8EE75;
					};
				};
			};
			buildConfigurationList = 5EAAADB3205CB80000D8EE75 /* Build configuration list for PBXProject "WKWebViewExtension" */;
			compatibilityVersion = "Xcode 8.0";
			developmentRegion = en;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
				Base,
			);
			mainGroup = 5EAAADAF205CB80000D8EE75;
			productRefGroup = 5EAAADB9205CB80000D8EE75 /* Products */;
			projectDirPath = "";
			projectRoot = "";
			targets = (
				5EAAADB7205CB80000D8EE75 /* WKWebViewExtension */,
				5EAAADCF205CB80000D8EE75 /* WKWebViewExtensionTests */,
			);
		};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
		5EAAADB6205CB80000D8EE75 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B944DC35206A353000BD0F06 /* Images.xcassets in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		5EAAADCE205CB80000D8EE75 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		5EAAADB4205CB80000D8EE75 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				5EAAADF8205CBB5200D8EE75 /* WKWebView + SupportProtocol.m in Sources */,
				5EAAADF1205CBB5200D8EE75 /* WKWebView + SafeEvaluateJS.m in Sources */,
				5EAAADC0205CB80000D8EE75 /* ViewController.m in Sources */,
				5EAAADCB205CB80000D8EE75 /* main.m in Sources */,
				5EAAADF2205CBB5200D8EE75 /* WKWebView + SafeScrollTo.m in Sources */,
				5EAAADBD205CB80000D8EE75 /* AppDelegate.m in Sources */,
				5E7A05DC205EC434006CA1E9 /* WKWebView + ExternalNavigationDelegates.m in Sources */,
				5E7A05D0205EB999006CA1E9 /* WKWebView + DeleteMenuItems.m in Sources */,
				B94ECF5F206A55CA0023245F /* WebView.m in Sources */,
				5E7A05D6205EB9F8006CA1E9 /* WKWebView + SyncConfigUA.m in Sources */,
				5EC64FE3206BA5CD0079B197 /* WKWebView + SafeCookies.m in Sources */,
				5EAAADF5205CBB5200D8EE75 /* WKWebView + SafeClearCache.m in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		5EAAADCC205CB80000D8EE75 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
		5EAAADD2205CB80000D8EE75 /* PBXTargetDependency */ = {
			isa = PBXTargetDependency;
			target = 5EAAADB7205CB80000D8EE75 /* WKWebViewExtension */;
			targetProxy = 5EAAADD1205CB80000D8EE75 /* PBXContainerItemProxy */;
		};
/* End PBXTargetDependency section */

/* Begin XCBuildConfiguration section */
		5EAAADD7205CB80000D8EE75 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = 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_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				CODE_SIGN_IDENTITY = "iPhone Developer";
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = dwarf;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_TESTABILITY = YES;
				GCC_C_LANGUAGE_STANDARD = gnu11;
				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 = 11.1;
				MTL_ENABLE_DEBUG_INFO = YES;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = iphoneos;
			};
			name = Debug;
		};
		5EAAADD8205CB80000D8EE75 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = 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_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				CODE_SIGN_IDENTITY = "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 = gnu11;
				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 = 11.1;
				MTL_ENABLE_DEBUG_INFO = NO;
				SDKROOT = iphoneos;
				VALIDATE_PRODUCT = YES;
			};
			name = Release;
		};
		5EAAADDA205CB80000D8EE75 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				CODE_SIGN_STYLE = Manual;
				DEVELOPMENT_TEAM = "";
				INFOPLIST_FILE = WKWebViewExtension/Info.plist;
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				PRODUCT_BUNDLE_IDENTIFIER = com.HybridPageKit.WKWebViewExtension;
				PRODUCT_NAME = "$(TARGET_NAME)";
				PROVISIONING_PROFILE = "";
				PROVISIONING_PROFILE_SPECIFIER = "";
				TARGETED_DEVICE_FAMILY = 1;
			};
			name = Debug;
		};
		5EAAADDB205CB80000D8EE75 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				CODE_SIGN_STYLE = Manual;
				DEVELOPMENT_TEAM = "";
				INFOPLIST_FILE = WKWebViewExtension/Info.plist;
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				PRODUCT_BUNDLE_IDENTIFIER = com.HybridPageKit.WKWebViewExtension;
				PRODUCT_NAME = "$(TARGET_NAME)";
				PROVISIONING_PROFILE_SPECIFIER = "";
				TARGETED_DEVICE_FAMILY = 1;
			};
			name = Release;
		};
		5EAAADDD205CB80000D8EE75 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				BUNDLE_LOADER = "$(TEST_HOST)";
				CODE_SIGN_STYLE = Automatic;
				INFOPLIST_FILE = WKWebViewExtensionTests/Info.plist;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
				PRODUCT_BUNDLE_IDENTIFIER = com.HybridPageKit.WKWebViewExtension.WKWebViewExtensionTests;
				PRODUCT_NAME = "$(TARGET_NAME)";
				TARGETED_DEVICE_FAMILY = "1,2";
				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WKWebViewExtension.app/WKWebViewExtension";
			};
			name = Debug;
		};
		5EAAADDE205CB80000D8EE75 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				BUNDLE_LOADER = "$(TEST_HOST)";
				CODE_SIGN_STYLE = Automatic;
				INFOPLIST_FILE = WKWebViewExtensionTests/Info.plist;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
				PRODUCT_BUNDLE_IDENTIFIER = com.HybridPageKit.WKWebViewExtension.WKWebViewExtensionTests;
				PRODUCT_NAME = "$(TARGET_NAME)";
				TARGETED_DEVICE_FAMILY = "1,2";
				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WKWebViewExtension.app/WKWebViewExtension";
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		5EAAADB3205CB80000D8EE75 /* Build configuration list for PBXProject "WKWebViewExtension" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				5EAAADD7205CB80000D8EE75 /* Debug */,
				5EAAADD8205CB80000D8EE75 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		5EAAADD9205CB80000D8EE75 /* Build configuration list for PBXNativeTarget "WKWebViewExtension" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				5EAAADDA205CB80000D8EE75 /* Debug */,
				5EAAADDB205CB80000D8EE75 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		5EAAADDC205CB80000D8EE75 /* Build configuration list for PBXNativeTarget "WKWebViewExtensionTests" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				5EAAADDD205CB80000D8EE75 /* Debug */,
				5EAAADDE205CB80000D8EE75 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */
	};
	rootObject = 5EAAADB0205CB80000D8EE75 /* Project object */;
}


================================================
FILE: WKWebViewExtension/WKWebViewExtension.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:WKWebViewExtension.xcodeproj">
   </FileRef>
</Workspace>


================================================
FILE: WKWebViewExtension/WKWebViewExtension.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>IDEDidComputeMac32BitWarning</key>
	<true/>
</dict>
</plist>


================================================
FILE: WKWebViewExtension.podspec
================================================

Pod::Spec.new do |s|
  s.name         = "WKWebViewExtension"
  s.version      = "0.1"
  s.summary      = "An extension for WKWebView. Providing menuItems delete 、support protocol 、clear cache of iOS8 and so on."
  s.homepage     = "https://github.com/dequan1331/WKWebViewExtension"
  s.license      = "MIT"
  s.author       = "dequanzhu"
  s.platform     = :ios, "8.0"
  s.source       = { :git => "https://github.com/dequan1331/WKWebViewExtension.git", :tag => "0.1" }
  s.source_files = "WKWebViewExtension/WKWebViewExtension/Source", "WKWebViewExtension/WKWebViewExtension/Source/**/*.{h,m}"
  s.frameworks = "UIKit", "WebKit"
end
Download .txt
gitextract_t3xquul0/

├── .gitignore
├── LICENSE
├── README.md
├── README_CN.md
├── WKWebViewExtension/
│   ├── WKWebViewExtension/
│   │   ├── AppDelegate.h
│   │   ├── AppDelegate.m
│   │   ├── Example/
│   │   │   ├── ViewController.h
│   │   │   ├── ViewController.m
│   │   │   ├── WebView.h
│   │   │   └── WebView.m
│   │   ├── Images.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── LaunchImage.launchimage/
│   │   │       └── Contents.json
│   │   ├── Info.plist
│   │   ├── Source/
│   │   │   ├── WKWebView + DeleteMenuItems.h
│   │   │   ├── WKWebView + DeleteMenuItems.m
│   │   │   ├── WKWebView + ExternalNavigationDelegates.h
│   │   │   ├── WKWebView + ExternalNavigationDelegates.m
│   │   │   ├── WKWebView + SafeClearCache.h
│   │   │   ├── WKWebView + SafeClearCache.m
│   │   │   ├── WKWebView + SafeCookies.h
│   │   │   ├── WKWebView + SafeCookies.m
│   │   │   ├── WKWebView + SafeEvaluateJS.h
│   │   │   ├── WKWebView + SafeEvaluateJS.m
│   │   │   ├── WKWebView + SafeScrollTo.h
│   │   │   ├── WKWebView + SafeScrollTo.m
│   │   │   ├── WKWebView + SupportProtocol.h
│   │   │   ├── WKWebView + SupportProtocol.m
│   │   │   ├── WKWebView + SyncConfigUA.h
│   │   │   ├── WKWebView + SyncConfigUA.m
│   │   │   └── WKWebViewExtensionsDef.h
│   │   └── main.m
│   └── WKWebViewExtension.xcodeproj/
│       ├── project.pbxproj
│       └── project.xcworkspace/
│           ├── contents.xcworkspacedata
│           └── xcshareddata/
│               └── IDEWorkspaceChecks.plist
└── WKWebViewExtension.podspec
Download .txt
SYMBOL INDEX (1 symbols across 1 files)

FILE: WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SyncConfigUA.h
  type kConfigUATypeReplace (line 12) | typedef NS_ENUM (NSInteger, ConfigUAType){
Condensed preview — 35 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (88K chars).
[
  {
    "path": ".gitignore",
    "chars": 1973,
    "preview": "\n# Created by https://www.gitignore.io/api/xcode,macos,objective-c\n\n### macOS ###\n*.DS_Store\n.AppleDouble\n.LSOverride\n\n#"
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2018 dequan1331\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README.md",
    "chars": 1763,
    "preview": "_**This repo will no longer be updated. The new versions has been moved to [HybridPageKit](https://github.com/dequan1331"
  },
  {
    "path": "README_CN.md",
    "chars": 1353,
    "preview": "_**暂停更新. 相关功能作为Submodule调整到 [HybridPageKit](https://github.com/dequan1331/HybridPageKit) 项目中. 后续使用Cocoapods,集成HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/AppDelegate.h",
    "chars": 293,
    "preview": "//\n//  WKWebView + DeleteMenuItems.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/AppDelegate.m",
    "chars": 2203,
    "preview": "//\n//  WKWebView + DeleteMenuItems.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Example/ViewController.h",
    "chars": 226,
    "preview": "//\n//  WKWebView + DeleteMenuItems.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Example/ViewController.m",
    "chars": 3689,
    "preview": "//\n//  WKWebView + DeleteMenuItems.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Example/WebView.h",
    "chars": 203,
    "preview": "//\n//  WebView.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageKit. All rights rese"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Example/WebView.m",
    "chars": 1346,
    "preview": "//\n//  WebView.m\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageKit. All rights rese"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Images.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 1183,
    "preview": "{\n  \"images\" : [\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-40@2x.png\",\n      \"sca"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Images.xcassets/LaunchImage.launchimage/Contents.json",
    "chars": 1215,
    "preview": "{\n  \"images\" : [\n    {\n      \"extent\" : \"full-screen\",\n      \"idiom\" : \"iphone\",\n      \"subtype\" : \"2436h\",\n      \"filen"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Info.plist",
    "chars": 1207,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + DeleteMenuItems.h",
    "chars": 376,
    "preview": "//\n//  WKWebView + DeleteMenuItems.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + DeleteMenuItems.m",
    "chars": 2109,
    "preview": "//\n//  WKWebView + DeleteMenuItems.m\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + ExternalNavigationDelegates.h",
    "chars": 714,
    "preview": "//\n//  WKWebView + ExternalNavigationDelegates.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 201"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + ExternalNavigationDelegates.m",
    "chars": 9791,
    "preview": "//\n//  WKWebView + ExternalNavigationDelegates.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 201"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeClearCache.h",
    "chars": 332,
    "preview": "//\n//  WKWebView + SafeClearCache.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageK"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeClearCache.m",
    "chars": 4372,
    "preview": "//\n//  WKWebView + SafeClearCache.m\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageK"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeCookies.h",
    "chars": 603,
    "preview": "//\n//  WKWebView + SafeCookies.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageKit."
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeCookies.m",
    "chars": 2597,
    "preview": "//\n//  WKWebView + SafeCookies.m\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageKit."
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeEvaluateJS.h",
    "chars": 651,
    "preview": "//\n//  WKWebView + SafeEvaluateJS.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageK"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeEvaluateJS.m",
    "chars": 1656,
    "preview": "//\n//  WKWebView + SafeEvaluateJS.m\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageK"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeScrollTo.h",
    "chars": 707,
    "preview": "//\n//  WKWebView + SafeScrollTo.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageKit"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SafeScrollTo.m",
    "chars": 8350,
    "preview": "//\n//  WKWebView + SafeScrollTo.m\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageKit"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SupportProtocol.h",
    "chars": 570,
    "preview": "//\n//  WKWebView + SupportProtocol.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SupportProtocol.m",
    "chars": 1655,
    "preview": "//\n//  WKWebView + SupportProtocol.m\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SyncConfigUA.h",
    "chars": 668,
    "preview": "//\n//  WKWebView + SyncConfigUA.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageKit"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebView + SyncConfigUA.m",
    "chars": 1339,
    "preview": "//\n//  WKWebView + SyncConfigUA.m\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageKit"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/Source/WKWebViewExtensionsDef.h",
    "chars": 466,
    "preview": "//\n//  WKWebViewExtensionsDef.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPageKit. "
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension/main.m",
    "chars": 357,
    "preview": "//\n//  WKWebView + DeleteMenuItems.h\n//  WKWebViewExtension\n//\n//  Created by dequanzhu.\n//  Copyright © 2018 HybridPage"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension.xcodeproj/project.pbxproj",
    "chars": 23255,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 48;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 163,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:WKWebViewExtens"
  },
  {
    "path": "WKWebViewExtension/WKWebViewExtension.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "chars": 238,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "WKWebViewExtension.podspec",
    "chars": 635,
    "preview": "\nPod::Spec.new do |s|\n  s.name         = \"WKWebViewExtension\"\n  s.version      = \"0.1\"\n  s.summary      = \"An extension "
  }
]

About this extraction

This page contains the full source code of the dequan1331/WKWebViewExtension GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 35 files (77.5 KB), approximately 22.1k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!