├── QZBaseWebVC ├── WebViewJavascriptBridge │ ├── WebViewJavascriptBridge_JS.h │ ├── WKWebViewJavascriptBridge.h │ ├── WebViewJavascriptBridge.h │ ├── WebViewJavascriptBridgeBase.h │ ├── WebViewJavascriptBridge_JS.m │ ├── WKWebViewJavascriptBridge.m │ ├── WebViewJavascriptBridge.m │ └── WebViewJavascriptBridgeBase.m ├── NJKWebViewProgress │ ├── NJKWebViewProgressView.h │ ├── NJKWebViewProgress.h │ ├── NJKWebViewProgressView.m │ └── NJKWebViewProgress.m ├── QZBaseWebVC.h └── QZBaseWebVC.m ├── QZBaseWebVCDemo.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── MrYu.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcuserdata │ └── MrYu.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── QZBaseWebVCDemo.xcscheme └── project.pbxproj ├── QZBaseWebVCDemo ├── WebViewVC.h ├── ViewController.h ├── AppDelegate.h ├── main.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── ViewController.m ├── WebViewVC.m ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.storyboard ├── Info.plist └── AppDelegate.m ├── QZBaseWebVCDemoTests ├── Info.plist └── QZBaseWebVCDemoTests.m ├── QZBaseWebVCDemoUITests ├── Info.plist └── QZBaseWebVCDemoUITests.m └── README.md /QZBaseWebVC/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | NSString * WebViewJavascriptBridge_js(); -------------------------------------------------------------------------------- /QZBaseWebVCDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo.xcodeproj/project.xcworkspace/xcuserdata/MrYu.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuqingzhude/QZBaseWebVCDemo/HEAD/QZBaseWebVCDemo.xcodeproj/project.xcworkspace/xcuserdata/MrYu.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /QZBaseWebVCDemo/WebViewVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewVC.h 3 | // QZBaseWebVCDemo 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import "QZBaseWebVC.h" 10 | 11 | @interface WebViewVC : QZBaseWebVC 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // QZBaseWebVCDemo 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // QZBaseWebVCDemo 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // QZBaseWebVCDemo 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo.xcodeproj/xcuserdata/MrYu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /QZBaseWebVC/NJKWebViewProgress/NJKWebViewProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NJKWebViewProgressView.h 3 | // iOS 7 Style WebView Progress Bar 4 | // 5 | // Created by Satoshi Aasano on 11/16/13. 6 | // Copyright (c) 2013 Satoshi Asano. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NJKWebViewProgressView : UIView 12 | @property (nonatomic) float progress; 13 | 14 | @property (nonatomic) UIView *progressBarView; 15 | @property (nonatomic) NSTimeInterval barAnimationDuration; // default 0.1 16 | @property (nonatomic) NSTimeInterval fadeAnimationDuration; // default 0.27 17 | @property (nonatomic) NSTimeInterval fadeOutDelay; // default 0.1 18 | 19 | - (void)setProgress:(float)progress animated:(BOOL)animated; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /QZBaseWebVCDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /QZBaseWebVCDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo.xcodeproj/xcuserdata/MrYu.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | QZBaseWebVCDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 4487F73F1D6C2C2C00C9CC9C 16 | 17 | primary 18 | 19 | 20 | 4487F7581D6C2C2D00C9CC9C 21 | 22 | primary 23 | 24 | 25 | 4487F7631D6C2C2D00C9CC9C 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QZBaseWebVCDemo 2 | 3 | WebView基类,>iOS8使用WKWebView,否则使用UIWebView,都自带进度条 4 | 5 | 6 | /** 7 | * 系统大于ios8 使用wkwebView加载页面 8 | * 否则使用uiwebView加载页面 9 | */ 10 | 11 | @interface QZBaseWebVC : UIViewController 12 | /** 子类类型转换*/ 13 | @property (nonatomic,weak) id webView; 14 | 15 | @property (nonatomic,copy) NSString *url; 16 | 17 | @property (nonatomic,strong) NJKWebViewProgressView *progressView; 18 | 19 | @property (nonatomic,strong) NJKWebViewProgress *progressProxy; 20 | 21 | @property (nonatomic,assign) double timeOut; 22 | /** 23 | * 统一wk ui加载状态代理方法,二合一 24 | */ 25 | @property (nonatomic,copy) void(^startLoadBlock)(id webView); 26 | @property (nonatomic,copy) void(^finishLoadBlock)(id webView); 27 | @property (nonatomic,copy) void(^failLoadBlock)(id webView); 28 | 29 | - (void)hideProgressView; 30 | 31 | - (void)loadRequest:(NSString *)url; 32 | 33 | - (void)scrollToTop; 34 | /** 35 | * 方法内部判断是什么view 36 | * 在外部直接传入js即可 37 | */ 38 | - (void)evaluateJavaScript:(NSString *)javaScript; 39 | -------------------------------------------------------------------------------- /QZBaseWebVCDemoTests/QZBaseWebVCDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // QZBaseWebVCDemoTests.m 3 | // QZBaseWebVCDemoTests 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface QZBaseWebVCDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation QZBaseWebVCDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /QZBaseWebVC/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h: -------------------------------------------------------------------------------- 1 | // 2 | // WKWebViewJavascriptBridge.h 3 | // 4 | // Created by @LokiMeyburg on 10/15/14. 5 | // Copyright (c) 2014 @LokiMeyburg. All rights reserved. 6 | // 7 | 8 | #if (__MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_9 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_1) 9 | #define supportsWKWebKit 10 | #endif 11 | 12 | #if defined(supportsWKWebKit ) 13 | 14 | #import 15 | #import "WebViewJavascriptBridgeBase.h" 16 | #import 17 | 18 | @interface WKWebViewJavascriptBridge : NSObject 19 | 20 | + (instancetype)bridgeForWebView:(WKWebView*)webView; 21 | + (void)enableLogging; 22 | 23 | - (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; 24 | - (void)callHandler:(NSString*)handlerName; 25 | - (void)callHandler:(NSString*)handlerName data:(id)data; 26 | - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; 27 | - (void)reset; 28 | - (void)setWebViewDelegate:(id)webViewDelegate; 29 | - (void)disableJavscriptAlertBoxSafetyTimeout; 30 | 31 | @end 32 | 33 | #endif -------------------------------------------------------------------------------- /QZBaseWebVC/NJKWebViewProgress/NJKWebViewProgress.h: -------------------------------------------------------------------------------- 1 | // 2 | // NJKWebViewProgress.h 3 | // 4 | // Created by Satoshi Aasano on 4/20/13. 5 | // Copyright (c) 2013 Satoshi Asano. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | #undef njk_weak 12 | #if __has_feature(objc_arc_weak) 13 | #define njk_weak weak 14 | #else 15 | #define njk_weak unsafe_unretained 16 | #endif 17 | 18 | extern const float NJKInitialProgressValue; 19 | extern const float NJKInteractiveProgressValue; 20 | extern const float NJKFinalProgressValue; 21 | 22 | typedef void (^NJKWebViewProgressBlock)(float progress); 23 | @protocol NJKWebViewProgressDelegate; 24 | @interface NJKWebViewProgress : NSObject 25 | @property (nonatomic, njk_weak) idprogressDelegate; 26 | @property (nonatomic, njk_weak) idwebViewProxyDelegate; 27 | @property (nonatomic, copy) NJKWebViewProgressBlock progressBlock; 28 | @property (nonatomic, readonly) float progress; // 0.0..1.0 29 | 30 | - (void)reset; 31 | @end 32 | 33 | @protocol NJKWebViewProgressDelegate 34 | - (void)webViewProgress:(NJKWebViewProgress *)webViewProgress updateProgress:(float)progress; 35 | @end 36 | 37 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /QZBaseWebVCDemoUITests/QZBaseWebVCDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // QZBaseWebVCDemoUITests.m 3 | // QZBaseWebVCDemoUITests 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface QZBaseWebVCDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation QZBaseWebVCDemoUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // QZBaseWebVCDemo 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "WebViewVC.h" 11 | #import "QZBaseWebVC.h" 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | self.view.backgroundColor = [UIColor whiteColor]; 21 | 22 | UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; 23 | btn.center = self.view.center; 24 | btn.clipsToBounds = YES; 25 | btn.layer.cornerRadius = 100; 26 | [btn setTitle:@"go" forState:UIControlStateNormal]; 27 | btn.titleLabel.font = [UIFont boldSystemFontOfSize:50]; 28 | btn.backgroundColor = [UIColor redColor]; 29 | [self.view addSubview:btn]; 30 | [btn addTarget:self action:@selector(go) forControlEvents:UIControlEventTouchUpInside]; 31 | } 32 | 33 | - (void)go 34 | { 35 | WebViewVC *vc = [[WebViewVC alloc] init]; 36 | vc.url = @"http://www.baidu.com"; 37 | [self.navigationController pushViewController:vc animated:YES]; 38 | } 39 | 40 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 41 | { 42 | 43 | } 44 | - (void)didReceiveMemoryWarning { 45 | [super didReceiveMemoryWarning]; 46 | // Dispose of any resources that can be recreated. 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/WebViewVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewVC.m 3 | // QZBaseWebVCDemo 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import "WebViewVC.h" 10 | //#import 11 | 12 | @interface WebViewVC () 13 | 14 | @end 15 | 16 | @implementation WebViewVC 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | [self makeSubview]; 21 | [self setStartLoadBlock:^(id webView) { 22 | NSLog(@"block success"); 23 | }]; 24 | [self setFinishLoadBlock:^(id webView) { 25 | NSLog(@"block finish"); 26 | }]; 27 | 28 | // [self addBridge]; 29 | 30 | [self loadUrl]; 31 | } 32 | 33 | 34 | - (void)makeSubview 35 | { 36 | UIButton *btn1 = [[UIButton alloc] init]; 37 | btn1.frame = CGRectMake(self.view.bounds.size.width - 80, self.view.bounds.size.height - 80, 50, 50); 38 | [btn1 setTitle:@"top" forState:UIControlStateNormal]; 39 | btn1.layer.cornerRadius = 25; 40 | btn1.clipsToBounds = YES; 41 | [self.view addSubview:btn1]; 42 | [self.view bringSubviewToFront:btn1]; 43 | btn1.backgroundColor = [UIColor redColor]; 44 | [btn1 addTarget:self action:@selector(gotop) forControlEvents:UIControlEventTouchUpInside]; 45 | } 46 | 47 | 48 | - (void)gotop 49 | { 50 | [self scrollToTop]; 51 | } 52 | 53 | - (void)didReceiveMemoryWarning { 54 | [super didReceiveMemoryWarning]; 55 | // Dispose of any resources that can be recreated. 56 | } 57 | 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /QZBaseWebVC/WebViewJavascriptBridge/WebViewJavascriptBridge.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewJavascriptBridge.h 3 | // ExampleApp-iOS 4 | // 5 | // Created by Marcus Westin on 6/14/13. 6 | // Copyright (c) 2013 Marcus Westin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WebViewJavascriptBridgeBase.h" 11 | 12 | #if defined __MAC_OS_X_VERSION_MAX_ALLOWED 13 | #import 14 | #define WVJB_PLATFORM_OSX 15 | #define WVJB_WEBVIEW_TYPE WebView 16 | #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject 17 | #define WVJB_WEBVIEW_DELEGATE_INTERFACE NSObject 18 | #elif defined __IPHONE_OS_VERSION_MAX_ALLOWED 19 | #import 20 | #define WVJB_PLATFORM_IOS 21 | #define WVJB_WEBVIEW_TYPE UIWebView 22 | #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject 23 | #define WVJB_WEBVIEW_DELEGATE_INTERFACE NSObject 24 | #endif 25 | 26 | @interface WebViewJavascriptBridge : WVJB_WEBVIEW_DELEGATE_INTERFACE 27 | 28 | + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView; 29 | + (void)enableLogging; 30 | + (void)setLogMaxLength:(int)length; 31 | 32 | - (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; 33 | - (void)callHandler:(NSString*)handlerName; 34 | - (void)callHandler:(NSString*)handlerName data:(id)data; 35 | - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; 36 | - (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate; 37 | - (void)disableJavscriptAlertBoxSafetyTimeout; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /QZBaseWebVC/QZBaseWebVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // QZBaseWKWebVC.h 3 | // QZBaseWKWebVCDemo 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "NJKWebViewProgressView.h" 12 | #import "NJKWebViewProgress.h" 13 | #import "WebViewJavascriptBridge.h" 14 | #import "WKWebViewJavascriptBridge.h" 15 | #import "WebViewJavascriptBridgeBase.h" 16 | 17 | /** 18 | * 系统大于ios8 使用wkwebView加载页面 19 | * 否则使用uiwebView加载页面 20 | */ 21 | 22 | @interface QZBaseWebVC : UIViewController 23 | /** 子类类型转换*/ 24 | @property (nonatomic,weak) id webView; 25 | 26 | @property (nonatomic,copy) NSString *url; 27 | 28 | /** request.timeoutInterval*/ 29 | @property (nonatomic,assign) double timeOut; 30 | 31 | @property (nonatomic,strong) NJKWebViewProgressView *progressView; 32 | 33 | @property (nonatomic,strong) NJKWebViewProgress *progressProxy; 34 | 35 | @property (nonatomic,strong) WebViewJavascriptBridge *uiBridge; 36 | 37 | @property (nonatomic,strong) WKWebViewJavascriptBridge *wkBridge; 38 | 39 | @property (nonatomic,strong) WVJBHandler handler; 40 | /** 41 | * 统一wk ui加载状态代理方法,二合一 42 | */ 43 | @property (nonatomic,copy) void(^startLoadBlock)(id webView); 44 | @property (nonatomic,copy) void(^finishLoadBlock)(id webView); 45 | @property (nonatomic,copy) void(^failLoadBlock)(id webView); 46 | 47 | - (void)hideProgressView; 48 | 49 | - (void)loadRequest:(NSString *)url; 50 | 51 | - (void)scrollToTop; 52 | /** 53 | * 方法内部判断是什么view 54 | * 在外部直接传入js即可 55 | */ 56 | - (void)evaluateJavaScript:(NSString *)javaScript; 57 | 58 | //- (void)addBridge; 59 | 60 | - (BOOL)isUIWebView; 61 | - (BOOL)isWKWebView; 62 | 63 | - (void)loadUrl; 64 | 65 | - (void)addBridge; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /QZBaseWebVC/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewJavascriptBridgeBase.h 3 | // 4 | // Created by @LokiMeyburg on 10/15/14. 5 | // Copyright (c) 2014 @LokiMeyburg. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | #define kCustomProtocolScheme @"wvjbscheme" 11 | #define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__" 12 | #define kBridgeLoaded @"__BRIDGE_LOADED__" 13 | 14 | typedef void (^WVJBResponseCallback)(id responseData); 15 | typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); 16 | typedef NSDictionary WVJBMessage; 17 | 18 | @protocol WebViewJavascriptBridgeBaseDelegate 19 | - (NSString*) _evaluateJavascript:(NSString*)javascriptCommand; 20 | @end 21 | 22 | @interface WebViewJavascriptBridgeBase : NSObject 23 | 24 | 25 | @property (weak, nonatomic) id delegate; 26 | @property (strong, nonatomic) NSMutableArray* startupMessageQueue; 27 | @property (strong, nonatomic) NSMutableDictionary* responseCallbacks; 28 | @property (strong, nonatomic) NSMutableDictionary* messageHandlers; 29 | @property (strong, nonatomic) WVJBHandler messageHandler; 30 | 31 | + (void)enableLogging; 32 | + (void)setLogMaxLength:(int)length; 33 | - (void)reset; 34 | - (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName; 35 | - (void)flushMessageQueue:(NSString *)messageQueueString; 36 | - (void)injectJavascriptFile; 37 | - (BOOL)isCorrectProcotocolScheme:(NSURL*)url; 38 | - (BOOL)isQueueMessageURL:(NSURL*)urll; 39 | - (BOOL)isBridgeLoadedURL:(NSURL*)urll; 40 | - (void)logUnkownMessage:(NSURL*)url; 41 | - (NSString *)webViewJavascriptCheckCommand; 42 | - (NSString *)webViewJavascriptFetchQueyCommand; 43 | - (void)disableJavscriptAlertBoxSafetyTimeout; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSApplicationCategoryType 24 | 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | 32 | UILaunchStoryboardName 33 | LaunchScreen 34 | UIMainStoryboardFile 35 | Main 36 | UIRequiredDeviceCapabilities 37 | 38 | armv7 39 | 40 | UISupportedInterfaceOrientations 41 | 42 | UIInterfaceOrientationPortrait 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | UISupportedInterfaceOrientations~ipad 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationPortraitUpsideDown 50 | UIInterfaceOrientationLandscapeLeft 51 | UIInterfaceOrientationLandscapeRight 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // QZBaseWebVCDemo 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | ViewController *vc =[[ViewController alloc] init]; 21 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; 22 | self.window.rootViewController = nav; 23 | [self.window makeKeyAndVisible]; 24 | return YES; 25 | } 26 | 27 | - (void)applicationWillResignActive:(UIApplication *)application { 28 | // 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. 29 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 30 | } 31 | 32 | - (void)applicationDidEnterBackground:(UIApplication *)application { 33 | // 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. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | - (void)applicationWillEnterForeground:(UIApplication *)application { 38 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 39 | } 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | - (void)applicationWillTerminate:(UIApplication *)application { 46 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /QZBaseWebVC/NJKWebViewProgress/NJKWebViewProgressView.m: -------------------------------------------------------------------------------- 1 | // 2 | // NJKWebViewProgressView.m 3 | // 4 | // Created by Satoshi Aasanoon 11/16/13. 5 | // Copyright (c) 2013 Satoshi Asano. All rights reserved. 6 | // 7 | 8 | #import "NJKWebViewProgressView.h" 9 | 10 | @implementation NJKWebViewProgressView 11 | 12 | - (id)initWithFrame:(CGRect)frame 13 | { 14 | self = [super initWithFrame:frame]; 15 | if (self) { 16 | [self configureViews]; 17 | } 18 | return self; 19 | } 20 | 21 | - (void)awakeFromNib 22 | { 23 | [super awakeFromNib]; 24 | [self configureViews]; 25 | } 26 | 27 | -(void)configureViews 28 | { 29 | self.userInteractionEnabled = NO; 30 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth; 31 | _progressBarView = [[UIView alloc] initWithFrame:self.bounds]; 32 | _progressBarView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 33 | UIColor *tintColor = [UIColor colorWithRed:22.f / 255.f green:126.f / 255.f blue:251.f / 255.f alpha:1.0]; // iOS7 Safari bar color 34 | if ([UIApplication.sharedApplication.delegate.window respondsToSelector:@selector(setTintColor:)] && UIApplication.sharedApplication.delegate.window.tintColor) { 35 | tintColor = UIApplication.sharedApplication.delegate.window.tintColor; 36 | } 37 | _progressBarView.backgroundColor = tintColor; 38 | [self addSubview:_progressBarView]; 39 | 40 | _barAnimationDuration = 0.27f; 41 | _fadeAnimationDuration = 0.27f; 42 | _fadeOutDelay = 0.1f; 43 | } 44 | 45 | -(void)setProgress:(float)progress 46 | { 47 | [self setProgress:progress animated:NO]; 48 | } 49 | 50 | - (void)setProgress:(float)progress animated:(BOOL)animated 51 | { 52 | BOOL isGrowing = progress > 0.0; 53 | [UIView animateWithDuration:(isGrowing && animated) ? _barAnimationDuration : 0.0 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 54 | CGRect frame = _progressBarView.frame; 55 | frame.size.width = progress * self.bounds.size.width; 56 | _progressBarView.frame = frame; 57 | } completion:nil]; 58 | 59 | if (progress >= 1.0) { 60 | [UIView animateWithDuration:animated ? _fadeAnimationDuration : 0.0 delay:_fadeOutDelay options:UIViewAnimationOptionCurveEaseInOut animations:^{ 61 | _progressBarView.alpha = 0.0; 62 | } completion:^(BOOL completed){ 63 | CGRect frame = _progressBarView.frame; 64 | frame.size.width = 0; 65 | _progressBarView.frame = frame; 66 | }]; 67 | } 68 | else { 69 | [UIView animateWithDuration:animated ? _fadeAnimationDuration : 0.0 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 70 | _progressBarView.alpha = 1.0; 71 | } completion:nil]; 72 | } 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo.xcodeproj/xcuserdata/MrYu.xcuserdatad/xcschemes/QZBaseWebVCDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /QZBaseWebVC/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m: -------------------------------------------------------------------------------- 1 | // This file contains the source for the Javascript side of the 2 | // WebViewJavascriptBridge. It is plaintext, but converted to an NSString 3 | // via some preprocessor tricks. 4 | // 5 | // Previous implementations of WebViewJavascriptBridge loaded the javascript source 6 | // from a resource. This worked fine for app developers, but library developers who 7 | // included the bridge into their library, awkwardly had to ask consumers of their 8 | // library to include the resource, violating their encapsulation. By including the 9 | // Javascript as a string resource, the encapsulation of the library is maintained. 10 | 11 | #import "WebViewJavascriptBridge_JS.h" 12 | 13 | NSString * WebViewJavascriptBridge_js() { 14 | #define __wvjb_js_func__(x) #x 15 | 16 | // BEGIN preprocessorJSCode 17 | static NSString * preprocessorJSCode = @__wvjb_js_func__( 18 | ;(function() { 19 | if (window.WebViewJavascriptBridge) { 20 | return; 21 | } 22 | 23 | if (!window.onerror) { 24 | window.onerror = function(msg, url, line) { 25 | console.log("WebViewJavascriptBridge: ERROR:" + msg + "@" + url + ":" + line); 26 | } 27 | } 28 | window.WebViewJavascriptBridge = { 29 | registerHandler: registerHandler, 30 | callHandler: callHandler, 31 | disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout, 32 | _fetchQueue: _fetchQueue, 33 | _handleMessageFromObjC: _handleMessageFromObjC 34 | }; 35 | 36 | var messagingIframe; 37 | var sendMessageQueue = []; 38 | var messageHandlers = {}; 39 | 40 | var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme'; 41 | var QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__'; 42 | 43 | var responseCallbacks = {}; 44 | var uniqueId = 1; 45 | var dispatchMessagesWithTimeoutSafety = true; 46 | 47 | function registerHandler(handlerName, handler) { 48 | messageHandlers[handlerName] = handler; 49 | } 50 | 51 | function callHandler(handlerName, data, responseCallback) { 52 | if (arguments.length == 2 && typeof data == 'function') { 53 | responseCallback = data; 54 | data = null; 55 | } 56 | _doSend({ handlerName:handlerName, data:data }, responseCallback); 57 | } 58 | function disableJavscriptAlertBoxSafetyTimeout() { 59 | dispatchMessagesWithTimeoutSafety = false; 60 | } 61 | 62 | function _doSend(message, responseCallback) { 63 | if (responseCallback) { 64 | var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime(); 65 | responseCallbacks[callbackId] = responseCallback; 66 | message['callbackId'] = callbackId; 67 | } 68 | sendMessageQueue.push(message); 69 | messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; 70 | } 71 | 72 | function _fetchQueue() { 73 | var messageQueueString = JSON.stringify(sendMessageQueue); 74 | sendMessageQueue = []; 75 | return messageQueueString; 76 | } 77 | 78 | function _dispatchMessageFromObjC(messageJSON) { 79 | if (dispatchMessagesWithTimeoutSafety) { 80 | setTimeout(_doDispatchMessageFromObjC); 81 | } else { 82 | _doDispatchMessageFromObjC(); 83 | } 84 | 85 | function _doDispatchMessageFromObjC() { 86 | var message = JSON.parse(messageJSON); 87 | var messageHandler; 88 | var responseCallback; 89 | 90 | if (message.responseId) { 91 | responseCallback = responseCallbacks[message.responseId]; 92 | if (!responseCallback) { 93 | return; 94 | } 95 | responseCallback(message.responseData); 96 | delete responseCallbacks[message.responseId]; 97 | } else { 98 | if (message.callbackId) { 99 | var callbackResponseId = message.callbackId; 100 | responseCallback = function(responseData) { 101 | _doSend({ handlerName:message.handlerName, responseId:callbackResponseId, responseData:responseData }); 102 | }; 103 | } 104 | 105 | var handler = messageHandlers[message.handlerName]; 106 | if (!handler) { 107 | console.log("WebViewJavascriptBridge: WARNING: no handler for message from ObjC:", message); 108 | } else { 109 | handler(message.data, responseCallback); 110 | } 111 | } 112 | } 113 | } 114 | 115 | function _handleMessageFromObjC(messageJSON) { 116 | _dispatchMessageFromObjC(messageJSON); 117 | } 118 | 119 | messagingIframe = document.createElement('iframe'); 120 | messagingIframe.style.display = 'none'; 121 | messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; 122 | document.documentElement.appendChild(messagingIframe); 123 | 124 | registerHandler("_disableJavascriptAlertBoxSafetyTimeout", disableJavscriptAlertBoxSafetyTimeout); 125 | 126 | setTimeout(_callWVJBCallbacks, 0); 127 | function _callWVJBCallbacks() { 128 | var callbacks = window.WVJBCallbacks; 129 | delete window.WVJBCallbacks; 130 | for (var i=0; i _webViewDelegate; 16 | long _uniqueId; 17 | WebViewJavascriptBridgeBase *_base; 18 | } 19 | 20 | /* API 21 | *****/ 22 | 23 | + (void)enableLogging { [WebViewJavascriptBridgeBase enableLogging]; } 24 | 25 | + (instancetype)bridgeForWebView:(WKWebView*)webView { 26 | WKWebViewJavascriptBridge* bridge = [[self alloc] init]; 27 | [bridge _setupInstance:webView]; 28 | [bridge reset]; 29 | return bridge; 30 | } 31 | 32 | - (void)send:(id)data { 33 | [self send:data responseCallback:nil]; 34 | } 35 | 36 | - (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback { 37 | [_base sendData:data responseCallback:responseCallback handlerName:nil]; 38 | } 39 | 40 | - (void)callHandler:(NSString *)handlerName { 41 | [self callHandler:handlerName data:nil responseCallback:nil]; 42 | } 43 | 44 | - (void)callHandler:(NSString *)handlerName data:(id)data { 45 | [self callHandler:handlerName data:data responseCallback:nil]; 46 | } 47 | 48 | - (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback { 49 | [_base sendData:data responseCallback:responseCallback handlerName:handlerName]; 50 | } 51 | 52 | - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { 53 | _base.messageHandlers[handlerName] = [handler copy]; 54 | } 55 | 56 | - (void)reset { 57 | [_base reset]; 58 | } 59 | 60 | - (void)setWebViewDelegate:(id)webViewDelegate { 61 | _webViewDelegate = webViewDelegate; 62 | } 63 | 64 | - (void)disableJavscriptAlertBoxSafetyTimeout { 65 | [_base disableJavscriptAlertBoxSafetyTimeout]; 66 | } 67 | 68 | /* Internals 69 | ***********/ 70 | 71 | - (void)dealloc { 72 | _base = nil; 73 | _webView = nil; 74 | _webViewDelegate = nil; 75 | _webView.navigationDelegate = nil; 76 | } 77 | 78 | 79 | /* WKWebView Specific Internals 80 | ******************************/ 81 | 82 | - (void) _setupInstance:(WKWebView*)webView { 83 | _webView = webView; 84 | _webView.navigationDelegate = self; 85 | _base = [[WebViewJavascriptBridgeBase alloc] init]; 86 | _base.delegate = self; 87 | } 88 | 89 | 90 | - (void)WKFlushMessageQueue { 91 | [_webView evaluateJavaScript:[_base webViewJavascriptFetchQueyCommand] completionHandler:^(NSString* result, NSError* error) { 92 | if (error != nil) { 93 | NSLog(@"WebViewJavascriptBridge: WARNING: Error when trying to fetch data from WKWebView: %@", error); 94 | } 95 | [_base flushMessageQueue:result]; 96 | }]; 97 | } 98 | 99 | - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation 100 | { 101 | if (webView != _webView) { return; } 102 | 103 | __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; 104 | if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFinishNavigation:)]) { 105 | [strongDelegate webView:webView didFinishNavigation:navigation]; 106 | } 107 | } 108 | 109 | - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler 110 | { 111 | if (webView != _webView) { return; } 112 | 113 | __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; 114 | if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didReceiveAuthenticationChallenge:completionHandler:)]) { 115 | [strongDelegate webView:webView didReceiveAuthenticationChallenge:challenge completionHandler:completionHandler]; 116 | } 117 | } 118 | 119 | - (void)webView:(WKWebView *)webView 120 | decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction 121 | decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { 122 | if (webView != _webView) { return; } 123 | NSURL *url = navigationAction.request.URL; 124 | __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; 125 | 126 | if ([_base isCorrectProcotocolScheme:url]) { 127 | if ([_base isBridgeLoadedURL:url]) { 128 | [_base injectJavascriptFile]; 129 | } else if ([_base isQueueMessageURL:url]) { 130 | [self WKFlushMessageQueue]; 131 | } else { 132 | [_base logUnkownMessage:url]; 133 | } 134 | decisionHandler(WKNavigationActionPolicyCancel); 135 | } 136 | 137 | if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) { 138 | [_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler]; 139 | } else { 140 | decisionHandler(WKNavigationActionPolicyAllow); 141 | } 142 | } 143 | 144 | - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { 145 | if (webView != _webView) { return; } 146 | 147 | __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; 148 | if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didStartProvisionalNavigation:)]) { 149 | [strongDelegate webView:webView didStartProvisionalNavigation:navigation]; 150 | } 151 | } 152 | 153 | 154 | - (void)webView:(WKWebView *)webView 155 | didFailNavigation:(WKNavigation *)navigation 156 | withError:(NSError *)error { 157 | if (webView != _webView) { return; } 158 | 159 | __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; 160 | if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailNavigation:withError:)]) { 161 | [strongDelegate webView:webView didFailNavigation:navigation withError:error]; 162 | } 163 | } 164 | 165 | - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error { 166 | if (webView != _webView) { return; } 167 | 168 | __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; 169 | if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailProvisionalNavigation:withError:)]) { 170 | [strongDelegate webView:webView didFailProvisionalNavigation:navigation withError:error]; 171 | } 172 | } 173 | 174 | - (NSString*) _evaluateJavascript:(NSString*)javascriptCommand 175 | { 176 | [_webView evaluateJavaScript:javascriptCommand completionHandler:nil]; 177 | return NULL; 178 | } 179 | 180 | 181 | 182 | @end 183 | 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /QZBaseWebVC/WebViewJavascriptBridge/WebViewJavascriptBridge.m: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewJavascriptBridge.m 3 | // ExampleApp-iOS 4 | // 5 | // Created by Marcus Westin on 6/14/13. 6 | // Copyright (c) 2013 Marcus Westin. All rights reserved. 7 | // 8 | 9 | #import "WebViewJavascriptBridge.h" 10 | 11 | #if __has_feature(objc_arc_weak) 12 | #define WVJB_WEAK __weak 13 | #else 14 | #define WVJB_WEAK __unsafe_unretained 15 | #endif 16 | 17 | @implementation WebViewJavascriptBridge { 18 | WVJB_WEAK WVJB_WEBVIEW_TYPE* _webView; 19 | WVJB_WEAK id _webViewDelegate; 20 | long _uniqueId; 21 | WebViewJavascriptBridgeBase *_base; 22 | } 23 | 24 | /* API 25 | *****/ 26 | 27 | + (void)enableLogging { [WebViewJavascriptBridgeBase enableLogging]; } 28 | + (void)setLogMaxLength:(int)length { [WebViewJavascriptBridgeBase setLogMaxLength:length]; } 29 | 30 | + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView { 31 | WebViewJavascriptBridge* bridge = [[self alloc] init]; 32 | [bridge _platformSpecificSetup:webView]; 33 | return bridge; 34 | } 35 | 36 | - (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate { 37 | _webViewDelegate = webViewDelegate; 38 | } 39 | 40 | - (void)send:(id)data { 41 | [self send:data responseCallback:nil]; 42 | } 43 | 44 | - (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback { 45 | [_base sendData:data responseCallback:responseCallback handlerName:nil]; 46 | } 47 | 48 | - (void)callHandler:(NSString *)handlerName { 49 | [self callHandler:handlerName data:nil responseCallback:nil]; 50 | } 51 | 52 | - (void)callHandler:(NSString *)handlerName data:(id)data { 53 | [self callHandler:handlerName data:data responseCallback:nil]; 54 | } 55 | 56 | - (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback { 57 | [_base sendData:data responseCallback:responseCallback handlerName:handlerName]; 58 | } 59 | 60 | - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { 61 | _base.messageHandlers[handlerName] = [handler copy]; 62 | } 63 | 64 | - (void)disableJavscriptAlertBoxSafetyTimeout { 65 | [_base disableJavscriptAlertBoxSafetyTimeout]; 66 | } 67 | 68 | 69 | /* Platform agnostic internals 70 | *****************************/ 71 | 72 | - (void)dealloc { 73 | [self _platformSpecificDealloc]; 74 | _base = nil; 75 | _webView = nil; 76 | _webViewDelegate = nil; 77 | } 78 | 79 | - (NSString*) _evaluateJavascript:(NSString*)javascriptCommand 80 | { 81 | return [_webView stringByEvaluatingJavaScriptFromString:javascriptCommand]; 82 | } 83 | 84 | /* Platform specific internals: OSX 85 | **********************************/ 86 | #if defined WVJB_PLATFORM_OSX 87 | 88 | - (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView { 89 | _webView = webView; 90 | 91 | _webView.policyDelegate = self; 92 | 93 | _base = [[WebViewJavascriptBridgeBase alloc] init]; 94 | _base.delegate = self; 95 | } 96 | 97 | - (void) _platformSpecificDealloc { 98 | _webView.policyDelegate = nil; 99 | } 100 | 101 | - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener 102 | { 103 | if (webView != _webView) { return; } 104 | 105 | NSURL *url = [request URL]; 106 | if ([_base isCorrectProcotocolScheme:url]) { 107 | if ([_base isBridgeLoadedURL:url]) { 108 | [_base injectJavascriptFile]; 109 | } else if ([_base isQueueMessageURL:url]) { 110 | NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]]; 111 | [_base flushMessageQueue:messageQueueString]; 112 | } else { 113 | [_base logUnkownMessage:url]; 114 | } 115 | [listener ignore]; 116 | } else if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { 117 | [_webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; 118 | } else { 119 | [listener use]; 120 | } 121 | } 122 | 123 | 124 | 125 | /* Platform specific internals: iOS 126 | **********************************/ 127 | #elif defined WVJB_PLATFORM_IOS 128 | 129 | - (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView { 130 | _webView = webView; 131 | _webView.delegate = self; 132 | _base = [[WebViewJavascriptBridgeBase alloc] init]; 133 | _base.delegate = self; 134 | } 135 | 136 | - (void) _platformSpecificDealloc { 137 | _webView.delegate = nil; 138 | } 139 | 140 | - (void)webViewDidFinishLoad:(UIWebView *)webView { 141 | if (webView != _webView) { return; } 142 | 143 | __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; 144 | if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { 145 | [strongDelegate webViewDidFinishLoad:webView]; 146 | } 147 | } 148 | 149 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { 150 | if (webView != _webView) { return; } 151 | 152 | __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; 153 | if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { 154 | [strongDelegate webView:webView didFailLoadWithError:error]; 155 | } 156 | } 157 | 158 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 159 | if (webView != _webView) { return YES; } 160 | NSURL *url = [request URL]; 161 | __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; 162 | if ([_base isCorrectProcotocolScheme:url]) { 163 | if ([_base isBridgeLoadedURL:url]) { 164 | [_base injectJavascriptFile]; 165 | } else if ([_base isQueueMessageURL:url]) { 166 | NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]]; 167 | [_base flushMessageQueue:messageQueueString]; 168 | } else { 169 | [_base logUnkownMessage:url]; 170 | } 171 | return NO; 172 | } else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { 173 | return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; 174 | } else { 175 | return YES; 176 | } 177 | } 178 | 179 | - (void)webViewDidStartLoad:(UIWebView *)webView { 180 | if (webView != _webView) { return; } 181 | 182 | __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; 183 | if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) { 184 | [strongDelegate webViewDidStartLoad:webView]; 185 | } 186 | } 187 | 188 | #endif 189 | 190 | @end 191 | -------------------------------------------------------------------------------- /QZBaseWebVC/NJKWebViewProgress/NJKWebViewProgress.m: -------------------------------------------------------------------------------- 1 | // 2 | // NJKWebViewProgress.m 3 | // 4 | // Created by Satoshi Aasano on 4/20/13. 5 | // Copyright (c) 2013 Satoshi Asano. All rights reserved. 6 | // 7 | 8 | #import "NJKWebViewProgress.h" 9 | 10 | NSString *completeRPCURLPath = @"/njkwebviewprogressproxy/complete"; 11 | 12 | const float NJKInitialProgressValue = 0.1f; 13 | const float NJKInteractiveProgressValue = 0.5f; 14 | const float NJKFinalProgressValue = 0.9f; 15 | 16 | @implementation NJKWebViewProgress 17 | { 18 | NSUInteger _loadingCount; 19 | NSUInteger _maxLoadCount; 20 | NSURL *_currentURL; 21 | BOOL _interactive; 22 | } 23 | 24 | - (id)init 25 | { 26 | self = [super init]; 27 | if (self) { 28 | _maxLoadCount = _loadingCount = 0; 29 | _interactive = NO; 30 | } 31 | return self; 32 | } 33 | 34 | - (void)startProgress 35 | { 36 | if (_progress < NJKInitialProgressValue) { 37 | [self setProgress:NJKInitialProgressValue]; 38 | } 39 | } 40 | 41 | - (void)incrementProgress 42 | { 43 | float progress = self.progress; 44 | float maxProgress = _interactive ? NJKFinalProgressValue : NJKInteractiveProgressValue; 45 | float remainPercent = (float)_loadingCount / (float)_maxLoadCount; 46 | float increment = (maxProgress - progress) * remainPercent; 47 | progress += increment; 48 | progress = fmin(progress, maxProgress); 49 | [self setProgress:progress]; 50 | } 51 | 52 | - (void)completeProgress 53 | { 54 | [self setProgress:1.0]; 55 | } 56 | 57 | - (void)setProgress:(float)progress 58 | { 59 | // progress should be incremental only 60 | if (progress > _progress || progress == 0) { 61 | _progress = progress; 62 | if ([_progressDelegate respondsToSelector:@selector(webViewProgress:updateProgress:)]) { 63 | [_progressDelegate webViewProgress:self updateProgress:progress]; 64 | } 65 | if (_progressBlock) { 66 | _progressBlock(progress); 67 | } 68 | } 69 | } 70 | 71 | - (void)reset 72 | { 73 | _maxLoadCount = _loadingCount = 0; 74 | _interactive = NO; 75 | [self setProgress:0.0]; 76 | } 77 | 78 | #pragma mark - 79 | #pragma mark UIWebViewDelegate 80 | 81 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 82 | { 83 | if ([request.URL.path isEqualToString:completeRPCURLPath]) { 84 | [self completeProgress]; 85 | return NO; 86 | } 87 | 88 | BOOL ret = YES; 89 | if ([_webViewProxyDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { 90 | ret = [_webViewProxyDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; 91 | } 92 | 93 | BOOL isFragmentJump = NO; 94 | if (request.URL.fragment) { 95 | NSString *nonFragmentURL = [request.URL.absoluteString stringByReplacingOccurrencesOfString:[@"#" stringByAppendingString:request.URL.fragment] withString:@""]; 96 | isFragmentJump = [nonFragmentURL isEqualToString:webView.request.URL.absoluteString]; 97 | } 98 | 99 | BOOL isTopLevelNavigation = [request.mainDocumentURL isEqual:request.URL]; 100 | 101 | BOOL isHTTPOrLocalFile = [request.URL.scheme isEqualToString:@"http"] || [request.URL.scheme isEqualToString:@"https"] || [request.URL.scheme isEqualToString:@"file"]; 102 | if (ret && !isFragmentJump && isHTTPOrLocalFile && isTopLevelNavigation) { 103 | _currentURL = request.URL; 104 | [self reset]; 105 | } 106 | return ret; 107 | } 108 | 109 | - (void)webViewDidStartLoad:(UIWebView *)webView 110 | { 111 | if ([_webViewProxyDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) { 112 | [_webViewProxyDelegate webViewDidStartLoad:webView]; 113 | } 114 | 115 | _loadingCount++; 116 | _maxLoadCount = fmax(_maxLoadCount, _loadingCount); 117 | 118 | [self startProgress]; 119 | } 120 | 121 | - (void)webViewDidFinishLoad:(UIWebView *)webView 122 | { 123 | if ([_webViewProxyDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { 124 | [_webViewProxyDelegate webViewDidFinishLoad:webView]; 125 | } 126 | 127 | _loadingCount--; 128 | [self incrementProgress]; 129 | 130 | NSString *readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"]; 131 | 132 | BOOL interactive = [readyState isEqualToString:@"interactive"]; 133 | if (interactive) { 134 | _interactive = YES; 135 | NSString *waitForCompleteJS = [NSString stringWithFormat:@"window.addEventListener('load',function() { var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = '%@://%@%@'; document.body.appendChild(iframe); }, false);", webView.request.mainDocumentURL.scheme, webView.request.mainDocumentURL.host, completeRPCURLPath]; 136 | [webView stringByEvaluatingJavaScriptFromString:waitForCompleteJS]; 137 | } 138 | 139 | BOOL isNotRedirect = _currentURL && [_currentURL isEqual:webView.request.mainDocumentURL]; 140 | BOOL complete = [readyState isEqualToString:@"complete"]; 141 | if (complete && isNotRedirect) { 142 | [self completeProgress]; 143 | } 144 | } 145 | 146 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error 147 | { 148 | if ([_webViewProxyDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { 149 | [_webViewProxyDelegate webView:webView didFailLoadWithError:error]; 150 | } 151 | 152 | _loadingCount--; 153 | [self incrementProgress]; 154 | 155 | NSString *readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"]; 156 | 157 | BOOL interactive = [readyState isEqualToString:@"interactive"]; 158 | if (interactive) { 159 | _interactive = YES; 160 | NSString *waitForCompleteJS = [NSString stringWithFormat:@"window.addEventListener('load',function() { var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = '%@://%@%@'; document.body.appendChild(iframe); }, false);", webView.request.mainDocumentURL.scheme, webView.request.mainDocumentURL.host, completeRPCURLPath]; 161 | [webView stringByEvaluatingJavaScriptFromString:waitForCompleteJS]; 162 | } 163 | 164 | BOOL isNotRedirect = _currentURL && [_currentURL isEqual:webView.request.mainDocumentURL]; 165 | BOOL complete = [readyState isEqualToString:@"complete"]; 166 | if ((complete && isNotRedirect) || error) { 167 | [self completeProgress]; 168 | } 169 | } 170 | 171 | #pragma mark - 172 | #pragma mark Method Forwarding 173 | // for future UIWebViewDelegate impl 174 | 175 | - (BOOL)respondsToSelector:(SEL)aSelector 176 | { 177 | if ( [super respondsToSelector:aSelector] ) 178 | return YES; 179 | 180 | if ([self.webViewProxyDelegate respondsToSelector:aSelector]) 181 | return YES; 182 | 183 | return NO; 184 | } 185 | 186 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector 187 | { 188 | NSMethodSignature *signature = [super methodSignatureForSelector:selector]; 189 | if(!signature) { 190 | if([_webViewProxyDelegate respondsToSelector:selector]) { 191 | return [(NSObject *)_webViewProxyDelegate methodSignatureForSelector:selector]; 192 | } 193 | } 194 | return signature; 195 | } 196 | 197 | - (void)forwardInvocation:(NSInvocation*)invocation 198 | { 199 | if ([_webViewProxyDelegate respondsToSelector:[invocation selector]]) { 200 | [invocation invokeWithTarget:_webViewProxyDelegate]; 201 | } 202 | } 203 | 204 | @end 205 | -------------------------------------------------------------------------------- /QZBaseWebVC/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewJavascriptBridgeBase.m 3 | // 4 | // Created by @LokiMeyburg on 10/15/14. 5 | // Copyright (c) 2014 @LokiMeyburg. All rights reserved. 6 | // 7 | 8 | #import 9 | #import "WebViewJavascriptBridgeBase.h" 10 | #import "WebViewJavascriptBridge_JS.h" 11 | 12 | @implementation WebViewJavascriptBridgeBase { 13 | __weak id _webViewDelegate; 14 | long _uniqueId; 15 | } 16 | 17 | static bool logging = false; 18 | static int logMaxLength = 500; 19 | 20 | + (void)enableLogging { logging = true; } 21 | + (void)setLogMaxLength:(int)length { logMaxLength = length;} 22 | 23 | -(id)init { 24 | self = [super init]; 25 | self.messageHandlers = [NSMutableDictionary dictionary]; 26 | self.startupMessageQueue = [NSMutableArray array]; 27 | self.responseCallbacks = [NSMutableDictionary dictionary]; 28 | _uniqueId = 0; 29 | return(self); 30 | } 31 | 32 | - (void)dealloc { 33 | self.startupMessageQueue = nil; 34 | self.responseCallbacks = nil; 35 | self.messageHandlers = nil; 36 | } 37 | 38 | - (void)reset { 39 | self.startupMessageQueue = [NSMutableArray array]; 40 | self.responseCallbacks = [NSMutableDictionary dictionary]; 41 | _uniqueId = 0; 42 | } 43 | 44 | - (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { 45 | NSMutableDictionary* message = [NSMutableDictionary dictionary]; 46 | 47 | if (data) { 48 | message[@"data"] = data; 49 | } 50 | 51 | if (responseCallback) { 52 | NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++_uniqueId]; 53 | self.responseCallbacks[callbackId] = [responseCallback copy]; 54 | message[@"callbackId"] = callbackId; 55 | } 56 | 57 | if (handlerName) { 58 | message[@"handlerName"] = handlerName; 59 | } 60 | [self _queueMessage:message]; 61 | } 62 | 63 | - (void)flushMessageQueue:(NSString *)messageQueueString{ 64 | if (messageQueueString == nil || messageQueueString.length == 0) { 65 | NSLog(@"WebViewJavascriptBridge: WARNING: ObjC got nil while fetching the message queue JSON from webview. This can happen if the WebViewJavascriptBridge JS is not currently present in the webview, e.g if the webview just loaded a new page."); 66 | return; 67 | } 68 | 69 | id messages = [self _deserializeMessageJSON:messageQueueString]; 70 | for (WVJBMessage* message in messages) { 71 | if (![message isKindOfClass:[WVJBMessage class]]) { 72 | NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [message class], message); 73 | continue; 74 | } 75 | [self _log:@"RCVD" json:message]; 76 | 77 | NSString* responseId = message[@"responseId"]; 78 | if (responseId) { 79 | WVJBResponseCallback responseCallback = _responseCallbacks[responseId]; 80 | responseCallback(message[@"responseData"]); 81 | [self.responseCallbacks removeObjectForKey:responseId]; 82 | } else { 83 | WVJBResponseCallback responseCallback = NULL; 84 | NSString* callbackId = message[@"callbackId"]; 85 | if (callbackId) { 86 | responseCallback = ^(id responseData) { 87 | if (responseData == nil) { 88 | responseData = [NSNull null]; 89 | } 90 | 91 | WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData }; 92 | [self _queueMessage:msg]; 93 | }; 94 | } else { 95 | responseCallback = ^(id ignoreResponseData) { 96 | // Do nothing 97 | }; 98 | } 99 | 100 | WVJBHandler handler = self.messageHandlers[message[@"handlerName"]]; 101 | 102 | if (!handler) { 103 | NSLog(@"WVJBNoHandlerException, No handler for message from JS: %@", message); 104 | continue; 105 | } 106 | 107 | handler(message[@"data"], responseCallback); 108 | } 109 | } 110 | } 111 | 112 | - (void)injectJavascriptFile { 113 | NSString *js = WebViewJavascriptBridge_js(); 114 | [self _evaluateJavascript:js]; 115 | if (self.startupMessageQueue) { 116 | NSArray* queue = self.startupMessageQueue; 117 | self.startupMessageQueue = nil; 118 | for (id queuedMessage in queue) { 119 | [self _dispatchMessage:queuedMessage]; 120 | } 121 | } 122 | } 123 | 124 | -(BOOL)isCorrectProcotocolScheme:(NSURL*)url { 125 | if([[url scheme] isEqualToString:kCustomProtocolScheme]){ 126 | return YES; 127 | } else { 128 | return NO; 129 | } 130 | } 131 | 132 | -(BOOL)isQueueMessageURL:(NSURL*)url { 133 | if([[url host] isEqualToString:kQueueHasMessage]){ 134 | return YES; 135 | } else { 136 | return NO; 137 | } 138 | } 139 | 140 | -(BOOL)isBridgeLoadedURL:(NSURL*)url { 141 | return ([[url scheme] isEqualToString:kCustomProtocolScheme] && [[url host] isEqualToString:kBridgeLoaded]); 142 | } 143 | 144 | -(void)logUnkownMessage:(NSURL*)url { 145 | NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); 146 | } 147 | 148 | -(NSString *)webViewJavascriptCheckCommand { 149 | return @"typeof WebViewJavascriptBridge == \'object\';"; 150 | } 151 | 152 | -(NSString *)webViewJavascriptFetchQueyCommand { 153 | return @"WebViewJavascriptBridge._fetchQueue();"; 154 | } 155 | 156 | - (void)disableJavscriptAlertBoxSafetyTimeout { 157 | [self sendData:nil responseCallback:nil handlerName:@"_disableJavascriptAlertBoxSafetyTimeout"]; 158 | } 159 | 160 | // Private 161 | // ------------------------------------------- 162 | 163 | - (void) _evaluateJavascript:(NSString *)javascriptCommand { 164 | [self.delegate _evaluateJavascript:javascriptCommand]; 165 | } 166 | 167 | - (void)_queueMessage:(WVJBMessage*)message { 168 | if (self.startupMessageQueue) { 169 | [self.startupMessageQueue addObject:message]; 170 | } else { 171 | [self _dispatchMessage:message]; 172 | } 173 | } 174 | 175 | - (void)_dispatchMessage:(WVJBMessage*)message { 176 | NSString *messageJSON = [self _serializeMessage:message pretty:NO]; 177 | [self _log:@"SEND" json:messageJSON]; 178 | messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; 179 | messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; 180 | messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"]; 181 | messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; 182 | messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"]; 183 | messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"]; 184 | messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"]; 185 | messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"]; 186 | 187 | NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]; 188 | if ([[NSThread currentThread] isMainThread]) { 189 | [self _evaluateJavascript:javascriptCommand]; 190 | 191 | } else { 192 | dispatch_sync(dispatch_get_main_queue(), ^{ 193 | [self _evaluateJavascript:javascriptCommand]; 194 | }); 195 | } 196 | } 197 | 198 | - (NSString *)_serializeMessage:(id)message pretty:(BOOL)pretty{ 199 | return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:(NSJSONWritingOptions)(pretty ? NSJSONWritingPrettyPrinted : 0) error:nil] encoding:NSUTF8StringEncoding]; 200 | } 201 | 202 | - (NSArray*)_deserializeMessageJSON:(NSString *)messageJSON { 203 | return [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil]; 204 | } 205 | 206 | - (void)_log:(NSString *)action json:(id)json { 207 | if (!logging) { return; } 208 | if (![json isKindOfClass:[NSString class]]) { 209 | json = [self _serializeMessage:json pretty:YES]; 210 | } 211 | if ([json length] > logMaxLength) { 212 | NSLog(@"WVJB %@: %@ [...]", action, [json substringToIndex:logMaxLength]); 213 | } else { 214 | NSLog(@"WVJB %@: %@", action, json); 215 | } 216 | } 217 | 218 | @end 219 | -------------------------------------------------------------------------------- /QZBaseWebVC/QZBaseWebVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // QZBaseWKWebVC.m 3 | // QZBaseWKWebVCDemo 4 | // 5 | // Created by MrYu on 16/8/23. 6 | // Copyright © 2016年 yu qingzhu. All rights reserved. 7 | // 8 | 9 | #import "QZBaseWebVC.h" 10 | #define progressBarHeight 2.f 11 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 12 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height 13 | #define Version [[UIDevice currentDevice].systemVersion floatValue] 14 | 15 | @interface QZBaseWebVC () 16 | { 17 | WKWebView *_wkWebView; 18 | UIWebView *_uiWebView; 19 | } 20 | @end 21 | 22 | @implementation QZBaseWebVC 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | self.view.backgroundColor = [UIColor whiteColor]; 27 | self.timeOut = 30; 28 | 29 | if (Version >= 8.0) { 30 | [self createWKWeb]; 31 | self.webView = _wkWebView; 32 | NSLog(@"use WKWebView"); 33 | }else{ 34 | [self createUIWeb]; 35 | self.webView = _uiWebView; 36 | NSLog(@"use UIWebView"); 37 | } 38 | 39 | [self addProgressView]; 40 | 41 | } 42 | 43 | #pragma mark - create WK OR UI web 44 | - (void)createWKWeb 45 | { 46 | WKWebViewConfiguration *configuration=[[WKWebViewConfiguration alloc] init]; 47 | // Webview的偏好设置 48 | configuration.preferences.minimumFontSize = 10; 49 | configuration.preferences.javaScriptEnabled = YES; 50 | // 默认是不能通过JS自动打开窗口的,必须通过用户交互才能打开 51 | configuration.preferences.javaScriptCanOpenWindowsAutomatically = YES; 52 | WKUserContentController *ucController = [[WKUserContentController alloc] init]; 53 | WKProcessPool *processPool = [[WKProcessPool alloc] init]; 54 | configuration.processPool = processPool; 55 | configuration.userContentController = ucController; 56 | 57 | for (NSHTTPCookie* cookie in [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies) 58 | { 59 | NSString *javascript = [NSString stringWithFormat:@"document.cookie = '%@=%@';", [cookie name], [cookie value]]; 60 | [ucController addUserScript:[[WKUserScript alloc] initWithSource:javascript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]]; 61 | } 62 | 63 | _wkWebView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration]; 64 | _wkWebView.navigationDelegate = self; 65 | _wkWebView.allowsBackForwardNavigationGestures = YES; 66 | _wkWebView.scrollView.delegate = self; 67 | [_wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; 68 | [self.view addSubview:_wkWebView]; 69 | } 70 | 71 | - (void)createUIWeb 72 | { 73 | _uiWebView = [[UIWebView alloc] initWithFrame:self.view.frame]; 74 | _uiWebView.scrollView.delegate = self; 75 | [self.view addSubview:_uiWebView]; 76 | _uiWebView.delegate = self.progressProxy; 77 | self.progressProxy.webViewProxyDelegate = self; 78 | self.progressProxy.progressDelegate = self; 79 | self.progressView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; 80 | } 81 | #pragma mark - 添加progressView 82 | - (void)addProgressView 83 | { 84 | [self.view addSubview:self.progressView]; 85 | } 86 | - (void)hideProgressView 87 | { 88 | [self.progressView removeFromSuperview]; 89 | } 90 | #pragma mark - 加载url 91 | - (void)loadUrl 92 | { 93 | NSMutableURLRequest *mRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.url]]; 94 | mRequest.timeoutInterval = self.timeOut; 95 | NSLog(@"%@",self.url); 96 | if (_wkWebView) { 97 | [_wkWebView loadRequest:mRequest]; 98 | }else{ 99 | [_uiWebView loadRequest:mRequest]; 100 | } 101 | 102 | } 103 | 104 | - (void)loadRequest:(NSString *)url 105 | { 106 | self.url = url; 107 | [self loadUrl]; 108 | } 109 | 110 | #pragma mark - 清除缓存&Cookie 111 | - (void)cleanCacheAndCookie 112 | { 113 | //清除cookies 114 | NSHTTPCookie *cookie; 115 | NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 116 | for (cookie in [storage cookies]){ 117 | [storage deleteCookie:cookie]; 118 | } 119 | //清除UIWebView的缓存 120 | [[NSURLCache sharedURLCache] removeAllCachedResponses]; 121 | NSURLCache * cache = [NSURLCache sharedURLCache]; 122 | [cache removeAllCachedResponses]; 123 | [cache setDiskCapacity:0]; 124 | [cache setMemoryCapacity:0]; 125 | } 126 | 127 | #pragma mark - js 128 | - (void)evaluateJavaScript:(NSString *)javaScript 129 | { 130 | if (_wkWebView) { 131 | [_wkWebView evaluateJavaScript:javaScript completionHandler:^(id result, NSError * _Nullable error) { 132 | NSLog(@"%@",error); 133 | }]; 134 | }else{ 135 | [_uiWebView stringByEvaluatingJavaScriptFromString:javaScript]; 136 | } 137 | } 138 | #pragma mark - 返回顶端 139 | - (void)scrollToTop 140 | { 141 | UIScrollView *scrollView; 142 | if (_wkWebView) { 143 | scrollView = (UIScrollView *)[[_wkWebView subviews] objectAtIndex:0]; 144 | }else{ 145 | scrollView = (UIScrollView *)[[_uiWebView subviews] objectAtIndex:0]; 146 | } 147 | [scrollView setContentOffset:CGPointMake(0, -64) animated:YES]; 148 | } 149 | #pragma mark - 监听mk progress 150 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 151 | { 152 | if ([keyPath isEqualToString:@"estimatedProgress"]) { 153 | [_progressView setProgress:_wkWebView.estimatedProgress animated:YES]; 154 | self.progressView.hidden = _wkWebView.estimatedProgress == 1.0; 155 | } 156 | } 157 | 158 | #pragma mark - NJKWebViewProgressDelegate 159 | -(void)webViewProgress:(NJKWebViewProgress *)webViewProgress updateProgress:(float)progress 160 | { 161 | [_progressView setProgress:progress animated:YES]; 162 | self.progressView.hidden = _wkWebView.estimatedProgress == 1.0; 163 | } 164 | 165 | #pragma mark - WKNavigationDelegate 166 | - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation 167 | { 168 | if (self.startLoadBlock) { 169 | self.startLoadBlock(webView); 170 | } 171 | } 172 | - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigatio 173 | { 174 | if (self.finishLoadBlock) { 175 | self.finishLoadBlock(webView); 176 | } 177 | } 178 | - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error 179 | { 180 | NSLog(@"%@",error); 181 | if (self.failLoadBlock) { 182 | self.failLoadBlock(webView); 183 | } 184 | } 185 | 186 | - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation 187 | { 188 | 189 | } 190 | #pragma mark - UIWebViewDelegate 191 | - (void)webViewDidStartLoad:(UIWebView *)webView 192 | { 193 | if (self.startLoadBlock) { 194 | self.startLoadBlock(webView); 195 | } 196 | } 197 | - (void)webViewDidFinishLoad:(UIWebView *)webView 198 | { 199 | // CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue]; 200 | // ((UIScrollView *)[[webView subviews] firstObject]).contentSize=CGSizeMake(SCREEN_WIDTH, height); 201 | // self.title=[webView stringByEvaluatingJavaScriptFromString:@"document.title"]; 202 | 203 | if (self.finishLoadBlock) { 204 | self.finishLoadBlock(webView); 205 | } 206 | } 207 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error 208 | { 209 | NSLog(@"%@",error); 210 | if (self.failLoadBlock) { 211 | self.failLoadBlock(webView); 212 | } 213 | } 214 | #pragma mark - 返回是什么类型的web 215 | - (BOOL)isWKWebView 216 | { 217 | if (_wkWebView) { 218 | return YES; 219 | } 220 | return NO; 221 | } 222 | 223 | - (BOOL)isUIWebView 224 | { 225 | return ![self isWKWebView]; 226 | } 227 | 228 | #pragma mark - 添加Bridge 229 | 230 | - (void)addBridge 231 | { 232 | // if (_wkWebView) { 233 | // [WKWebViewJavascriptBridge enableLogging]; 234 | // self.wkBridge = [WKWebViewJavascriptBridge bridgeForWebView:_wkWebView]; 235 | // [self.wkBridge setWebViewDelegate:self]; 236 | // 237 | // [self.wkBridge registerHandler:@"handler" handler:^(id data, WVJBResponseCallback responseCallback) { 238 | // NSLog(@"data = %@",data); 239 | // }]; 240 | // 241 | // 242 | // }else{ 243 | // 244 | // [WebViewJavascriptBridge enableLogging]; 245 | // self.uiBridge = [WebViewJavascriptBridge bridgeForWebView:_uiWebView]; 246 | // [self.uiBridge setWebViewDelegate:self]; 247 | // 248 | // [self.uiBridge registerHandler:@"handler" handler:^(id data, WVJBResponseCallback responseCallback) { 249 | // NSLog(@"data = %@",data); 250 | // }]; 251 | // 252 | // } 253 | 254 | } 255 | #pragma mark - lazyload 256 | - (NJKWebViewProgressView*)progressView 257 | { 258 | if (!_progressView) { 259 | _progressView=[[NJKWebViewProgressView alloc] init]; 260 | CGRect navigationBarBounds = self.navigationController.navigationBar.bounds; 261 | _progressView.frame = CGRectMake(0, 64, navigationBarBounds.size.width, progressBarHeight); 262 | } 263 | return _progressView; 264 | } 265 | 266 | - (NJKWebViewProgress*)progressProxy 267 | { 268 | if (!_progressProxy) { 269 | NJKWebViewProgress *progressProxy=[[NJKWebViewProgress alloc] init]; 270 | _progressProxy = progressProxy; 271 | } 272 | return _progressProxy; 273 | } 274 | 275 | - (WebViewJavascriptBridge *)uiBridge 276 | { 277 | if (!_uiBridge) { 278 | // 设置能够进行桥接 279 | [WebViewJavascriptBridge enableLogging]; 280 | _uiBridge = [WebViewJavascriptBridge bridgeForWebView:_uiWebView]; 281 | [_uiBridge setWebViewDelegate:self]; 282 | } 283 | return _uiBridge; 284 | } 285 | 286 | - (WKWebViewJavascriptBridge *)wkBridge 287 | { 288 | if (!_wkBridge) { 289 | [WKWebViewJavascriptBridge enableLogging]; 290 | _wkBridge=[WKWebViewJavascriptBridge bridgeForWebView:_wkWebView]; 291 | [_wkBridge setWebViewDelegate:self]; 292 | } 293 | return _wkBridge; 294 | } 295 | #pragma mark - otherMethod 296 | -(void)viewWillDisappear:(BOOL)animated 297 | { 298 | [super viewWillDisappear:animated]; 299 | [self.progressView removeFromSuperview]; 300 | } 301 | - (void)didReceiveMemoryWarning { 302 | [super didReceiveMemoryWarning]; 303 | [[NSURLCache sharedURLCache] removeAllCachedResponses]; 304 | } 305 | 306 | - (void)dealloc 307 | { 308 | if (_wkWebView) { 309 | [_wkWebView removeObserver:self forKeyPath:@"estimatedProgress"]; 310 | _wkWebView.scrollView.delegate = nil; 311 | }else{ 312 | [[NSURLCache sharedURLCache] removeAllCachedResponses]; 313 | [_uiWebView loadHTMLString:@"" baseURL:nil]; 314 | [_uiWebView stopLoading]; 315 | _uiWebView.delegate=nil; 316 | _uiWebView.scrollView.delegate = nil; 317 | [_uiWebView removeFromSuperview]; 318 | _uiWebView=nil; 319 | } 320 | } 321 | @end 322 | -------------------------------------------------------------------------------- /QZBaseWebVCDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4413C6271D7037A3005D570A /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 4413C6201D7037A3005D570A /* WebViewJavascriptBridge.m */; }; 11 | 4413C6281D7037A3005D570A /* WebViewJavascriptBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 4413C6221D7037A3005D570A /* WebViewJavascriptBridge_JS.m */; }; 12 | 4413C6291D7037A3005D570A /* WebViewJavascriptBridgeBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4413C6241D7037A3005D570A /* WebViewJavascriptBridgeBase.m */; }; 13 | 4413C62A1D7037A3005D570A /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 4413C6261D7037A3005D570A /* WKWebViewJavascriptBridge.m */; }; 14 | 4487F7451D6C2C2C00C9CC9C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4487F7441D6C2C2C00C9CC9C /* main.m */; }; 15 | 4487F7481D6C2C2C00C9CC9C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4487F7471D6C2C2C00C9CC9C /* AppDelegate.m */; }; 16 | 4487F74B1D6C2C2C00C9CC9C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4487F74A1D6C2C2C00C9CC9C /* ViewController.m */; }; 17 | 4487F74E1D6C2C2C00C9CC9C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4487F74C1D6C2C2C00C9CC9C /* Main.storyboard */; }; 18 | 4487F7501D6C2C2C00C9CC9C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4487F74F1D6C2C2C00C9CC9C /* Assets.xcassets */; }; 19 | 4487F7531D6C2C2C00C9CC9C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4487F7511D6C2C2C00C9CC9C /* LaunchScreen.storyboard */; }; 20 | 4487F75E1D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4487F75D1D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests.m */; }; 21 | 4487F7691D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4487F7681D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests.m */; }; 22 | 4487F77E1D6C2C4200C9CC9C /* NJKWebViewProgress.m in Sources */ = {isa = PBXBuildFile; fileRef = 4487F7791D6C2C4200C9CC9C /* NJKWebViewProgress.m */; }; 23 | 4487F77F1D6C2C4200C9CC9C /* NJKWebViewProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4487F77B1D6C2C4200C9CC9C /* NJKWebViewProgressView.m */; }; 24 | 4487F7801D6C2C4200C9CC9C /* QZBaseWebVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4487F77D1D6C2C4200C9CC9C /* QZBaseWebVC.m */; }; 25 | 4487F7831D6C2CC600C9CC9C /* WebViewVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4487F7821D6C2CC600C9CC9C /* WebViewVC.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 4487F75A1D6C2C2D00C9CC9C /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 4487F7381D6C2C2C00C9CC9C /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 4487F73F1D6C2C2C00C9CC9C; 34 | remoteInfo = QZBaseWebVCDemo; 35 | }; 36 | 4487F7651D6C2C2D00C9CC9C /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 4487F7381D6C2C2C00C9CC9C /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 4487F73F1D6C2C2C00C9CC9C; 41 | remoteInfo = QZBaseWebVCDemo; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 4413C61F1D7037A3005D570A /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; 47 | 4413C6201D7037A3005D570A /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; 48 | 4413C6211D7037A3005D570A /* WebViewJavascriptBridge_JS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_JS.h; sourceTree = ""; }; 49 | 4413C6221D7037A3005D570A /* WebViewJavascriptBridge_JS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_JS.m; sourceTree = ""; }; 50 | 4413C6231D7037A3005D570A /* WebViewJavascriptBridgeBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeBase.h; sourceTree = ""; }; 51 | 4413C6241D7037A3005D570A /* WebViewJavascriptBridgeBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeBase.m; sourceTree = ""; }; 52 | 4413C6251D7037A3005D570A /* WKWebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewJavascriptBridge.h; sourceTree = ""; }; 53 | 4413C6261D7037A3005D570A /* WKWebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewJavascriptBridge.m; sourceTree = ""; }; 54 | 4487F7401D6C2C2C00C9CC9C /* QZBaseWebVCDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QZBaseWebVCDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 4487F7441D6C2C2C00C9CC9C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 56 | 4487F7461D6C2C2C00C9CC9C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 57 | 4487F7471D6C2C2C00C9CC9C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 58 | 4487F7491D6C2C2C00C9CC9C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 59 | 4487F74A1D6C2C2C00C9CC9C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 60 | 4487F74D1D6C2C2C00C9CC9C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 61 | 4487F74F1D6C2C2C00C9CC9C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 62 | 4487F7521D6C2C2C00C9CC9C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 63 | 4487F7541D6C2C2C00C9CC9C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 64 | 4487F7591D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QZBaseWebVCDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 4487F75D1D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QZBaseWebVCDemoTests.m; sourceTree = ""; }; 66 | 4487F75F1D6C2C2D00C9CC9C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 67 | 4487F7641D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QZBaseWebVCDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | 4487F7681D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QZBaseWebVCDemoUITests.m; sourceTree = ""; }; 69 | 4487F76A1D6C2C2D00C9CC9C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 70 | 4487F7781D6C2C4200C9CC9C /* NJKWebViewProgress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NJKWebViewProgress.h; sourceTree = ""; }; 71 | 4487F7791D6C2C4200C9CC9C /* NJKWebViewProgress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NJKWebViewProgress.m; sourceTree = ""; }; 72 | 4487F77A1D6C2C4200C9CC9C /* NJKWebViewProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NJKWebViewProgressView.h; sourceTree = ""; }; 73 | 4487F77B1D6C2C4200C9CC9C /* NJKWebViewProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NJKWebViewProgressView.m; sourceTree = ""; }; 74 | 4487F77C1D6C2C4200C9CC9C /* QZBaseWebVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QZBaseWebVC.h; sourceTree = ""; }; 75 | 4487F77D1D6C2C4200C9CC9C /* QZBaseWebVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QZBaseWebVC.m; sourceTree = ""; }; 76 | 4487F7811D6C2CC600C9CC9C /* WebViewVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewVC.h; sourceTree = ""; }; 77 | 4487F7821D6C2CC600C9CC9C /* WebViewVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewVC.m; sourceTree = ""; }; 78 | /* End PBXFileReference section */ 79 | 80 | /* Begin PBXFrameworksBuildPhase section */ 81 | 4487F73D1D6C2C2C00C9CC9C /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | 4487F7561D6C2C2D00C9CC9C /* Frameworks */ = { 89 | isa = PBXFrameworksBuildPhase; 90 | buildActionMask = 2147483647; 91 | files = ( 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | 4487F7611D6C2C2D00C9CC9C /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | /* End PBXFrameworksBuildPhase section */ 103 | 104 | /* Begin PBXGroup section */ 105 | 4413C61E1D7037A3005D570A /* WebViewJavascriptBridge */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 4413C61F1D7037A3005D570A /* WebViewJavascriptBridge.h */, 109 | 4413C6201D7037A3005D570A /* WebViewJavascriptBridge.m */, 110 | 4413C6211D7037A3005D570A /* WebViewJavascriptBridge_JS.h */, 111 | 4413C6221D7037A3005D570A /* WebViewJavascriptBridge_JS.m */, 112 | 4413C6231D7037A3005D570A /* WebViewJavascriptBridgeBase.h */, 113 | 4413C6241D7037A3005D570A /* WebViewJavascriptBridgeBase.m */, 114 | 4413C6251D7037A3005D570A /* WKWebViewJavascriptBridge.h */, 115 | 4413C6261D7037A3005D570A /* WKWebViewJavascriptBridge.m */, 116 | ); 117 | path = WebViewJavascriptBridge; 118 | sourceTree = ""; 119 | }; 120 | 4487F7371D6C2C2C00C9CC9C = { 121 | isa = PBXGroup; 122 | children = ( 123 | 4487F7761D6C2C4200C9CC9C /* QZBaseWebVC */, 124 | 4487F7421D6C2C2C00C9CC9C /* QZBaseWebVCDemo */, 125 | 4487F75C1D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests */, 126 | 4487F7671D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests */, 127 | 4487F7411D6C2C2C00C9CC9C /* Products */, 128 | ); 129 | sourceTree = ""; 130 | }; 131 | 4487F7411D6C2C2C00C9CC9C /* Products */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 4487F7401D6C2C2C00C9CC9C /* QZBaseWebVCDemo.app */, 135 | 4487F7591D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests.xctest */, 136 | 4487F7641D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests.xctest */, 137 | ); 138 | name = Products; 139 | sourceTree = ""; 140 | }; 141 | 4487F7421D6C2C2C00C9CC9C /* QZBaseWebVCDemo */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 4487F7811D6C2CC600C9CC9C /* WebViewVC.h */, 145 | 4487F7821D6C2CC600C9CC9C /* WebViewVC.m */, 146 | 4487F7461D6C2C2C00C9CC9C /* AppDelegate.h */, 147 | 4487F7471D6C2C2C00C9CC9C /* AppDelegate.m */, 148 | 4487F7491D6C2C2C00C9CC9C /* ViewController.h */, 149 | 4487F74A1D6C2C2C00C9CC9C /* ViewController.m */, 150 | 4487F74C1D6C2C2C00C9CC9C /* Main.storyboard */, 151 | 4487F74F1D6C2C2C00C9CC9C /* Assets.xcassets */, 152 | 4487F7511D6C2C2C00C9CC9C /* LaunchScreen.storyboard */, 153 | 4487F7541D6C2C2C00C9CC9C /* Info.plist */, 154 | 4487F7431D6C2C2C00C9CC9C /* Supporting Files */, 155 | ); 156 | path = QZBaseWebVCDemo; 157 | sourceTree = ""; 158 | }; 159 | 4487F7431D6C2C2C00C9CC9C /* Supporting Files */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 4487F7441D6C2C2C00C9CC9C /* main.m */, 163 | ); 164 | name = "Supporting Files"; 165 | sourceTree = ""; 166 | }; 167 | 4487F75C1D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 4487F75D1D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests.m */, 171 | 4487F75F1D6C2C2D00C9CC9C /* Info.plist */, 172 | ); 173 | path = QZBaseWebVCDemoTests; 174 | sourceTree = ""; 175 | }; 176 | 4487F7671D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 4487F7681D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests.m */, 180 | 4487F76A1D6C2C2D00C9CC9C /* Info.plist */, 181 | ); 182 | path = QZBaseWebVCDemoUITests; 183 | sourceTree = ""; 184 | }; 185 | 4487F7761D6C2C4200C9CC9C /* QZBaseWebVC */ = { 186 | isa = PBXGroup; 187 | children = ( 188 | 4413C61E1D7037A3005D570A /* WebViewJavascriptBridge */, 189 | 4487F7771D6C2C4200C9CC9C /* NJKWebViewProgress */, 190 | 4487F77C1D6C2C4200C9CC9C /* QZBaseWebVC.h */, 191 | 4487F77D1D6C2C4200C9CC9C /* QZBaseWebVC.m */, 192 | ); 193 | path = QZBaseWebVC; 194 | sourceTree = ""; 195 | }; 196 | 4487F7771D6C2C4200C9CC9C /* NJKWebViewProgress */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | 4487F7781D6C2C4200C9CC9C /* NJKWebViewProgress.h */, 200 | 4487F7791D6C2C4200C9CC9C /* NJKWebViewProgress.m */, 201 | 4487F77A1D6C2C4200C9CC9C /* NJKWebViewProgressView.h */, 202 | 4487F77B1D6C2C4200C9CC9C /* NJKWebViewProgressView.m */, 203 | ); 204 | path = NJKWebViewProgress; 205 | sourceTree = ""; 206 | }; 207 | /* End PBXGroup section */ 208 | 209 | /* Begin PBXNativeTarget section */ 210 | 4487F73F1D6C2C2C00C9CC9C /* QZBaseWebVCDemo */ = { 211 | isa = PBXNativeTarget; 212 | buildConfigurationList = 4487F76D1D6C2C2D00C9CC9C /* Build configuration list for PBXNativeTarget "QZBaseWebVCDemo" */; 213 | buildPhases = ( 214 | 4487F73C1D6C2C2C00C9CC9C /* Sources */, 215 | 4487F73D1D6C2C2C00C9CC9C /* Frameworks */, 216 | 4487F73E1D6C2C2C00C9CC9C /* Resources */, 217 | ); 218 | buildRules = ( 219 | ); 220 | dependencies = ( 221 | ); 222 | name = QZBaseWebVCDemo; 223 | productName = QZBaseWebVCDemo; 224 | productReference = 4487F7401D6C2C2C00C9CC9C /* QZBaseWebVCDemo.app */; 225 | productType = "com.apple.product-type.application"; 226 | }; 227 | 4487F7581D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests */ = { 228 | isa = PBXNativeTarget; 229 | buildConfigurationList = 4487F7701D6C2C2D00C9CC9C /* Build configuration list for PBXNativeTarget "QZBaseWebVCDemoTests" */; 230 | buildPhases = ( 231 | 4487F7551D6C2C2D00C9CC9C /* Sources */, 232 | 4487F7561D6C2C2D00C9CC9C /* Frameworks */, 233 | 4487F7571D6C2C2D00C9CC9C /* Resources */, 234 | ); 235 | buildRules = ( 236 | ); 237 | dependencies = ( 238 | 4487F75B1D6C2C2D00C9CC9C /* PBXTargetDependency */, 239 | ); 240 | name = QZBaseWebVCDemoTests; 241 | productName = QZBaseWebVCDemoTests; 242 | productReference = 4487F7591D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests.xctest */; 243 | productType = "com.apple.product-type.bundle.unit-test"; 244 | }; 245 | 4487F7631D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests */ = { 246 | isa = PBXNativeTarget; 247 | buildConfigurationList = 4487F7731D6C2C2D00C9CC9C /* Build configuration list for PBXNativeTarget "QZBaseWebVCDemoUITests" */; 248 | buildPhases = ( 249 | 4487F7601D6C2C2D00C9CC9C /* Sources */, 250 | 4487F7611D6C2C2D00C9CC9C /* Frameworks */, 251 | 4487F7621D6C2C2D00C9CC9C /* Resources */, 252 | ); 253 | buildRules = ( 254 | ); 255 | dependencies = ( 256 | 4487F7661D6C2C2D00C9CC9C /* PBXTargetDependency */, 257 | ); 258 | name = QZBaseWebVCDemoUITests; 259 | productName = QZBaseWebVCDemoUITests; 260 | productReference = 4487F7641D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests.xctest */; 261 | productType = "com.apple.product-type.bundle.ui-testing"; 262 | }; 263 | /* End PBXNativeTarget section */ 264 | 265 | /* Begin PBXProject section */ 266 | 4487F7381D6C2C2C00C9CC9C /* Project object */ = { 267 | isa = PBXProject; 268 | attributes = { 269 | LastUpgradeCheck = 0730; 270 | ORGANIZATIONNAME = "yu qingzhu"; 271 | TargetAttributes = { 272 | 4487F73F1D6C2C2C00C9CC9C = { 273 | CreatedOnToolsVersion = 7.3.1; 274 | }; 275 | 4487F7581D6C2C2D00C9CC9C = { 276 | CreatedOnToolsVersion = 7.3.1; 277 | TestTargetID = 4487F73F1D6C2C2C00C9CC9C; 278 | }; 279 | 4487F7631D6C2C2D00C9CC9C = { 280 | CreatedOnToolsVersion = 7.3.1; 281 | TestTargetID = 4487F73F1D6C2C2C00C9CC9C; 282 | }; 283 | }; 284 | }; 285 | buildConfigurationList = 4487F73B1D6C2C2C00C9CC9C /* Build configuration list for PBXProject "QZBaseWebVCDemo" */; 286 | compatibilityVersion = "Xcode 3.2"; 287 | developmentRegion = English; 288 | hasScannedForEncodings = 0; 289 | knownRegions = ( 290 | en, 291 | Base, 292 | ); 293 | mainGroup = 4487F7371D6C2C2C00C9CC9C; 294 | productRefGroup = 4487F7411D6C2C2C00C9CC9C /* Products */; 295 | projectDirPath = ""; 296 | projectRoot = ""; 297 | targets = ( 298 | 4487F73F1D6C2C2C00C9CC9C /* QZBaseWebVCDemo */, 299 | 4487F7581D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests */, 300 | 4487F7631D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests */, 301 | ); 302 | }; 303 | /* End PBXProject section */ 304 | 305 | /* Begin PBXResourcesBuildPhase section */ 306 | 4487F73E1D6C2C2C00C9CC9C /* Resources */ = { 307 | isa = PBXResourcesBuildPhase; 308 | buildActionMask = 2147483647; 309 | files = ( 310 | 4487F7531D6C2C2C00C9CC9C /* LaunchScreen.storyboard in Resources */, 311 | 4487F7501D6C2C2C00C9CC9C /* Assets.xcassets in Resources */, 312 | 4487F74E1D6C2C2C00C9CC9C /* Main.storyboard in Resources */, 313 | ); 314 | runOnlyForDeploymentPostprocessing = 0; 315 | }; 316 | 4487F7571D6C2C2D00C9CC9C /* Resources */ = { 317 | isa = PBXResourcesBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | 4487F7621D6C2C2D00C9CC9C /* Resources */ = { 324 | isa = PBXResourcesBuildPhase; 325 | buildActionMask = 2147483647; 326 | files = ( 327 | ); 328 | runOnlyForDeploymentPostprocessing = 0; 329 | }; 330 | /* End PBXResourcesBuildPhase section */ 331 | 332 | /* Begin PBXSourcesBuildPhase section */ 333 | 4487F73C1D6C2C2C00C9CC9C /* Sources */ = { 334 | isa = PBXSourcesBuildPhase; 335 | buildActionMask = 2147483647; 336 | files = ( 337 | 4487F77E1D6C2C4200C9CC9C /* NJKWebViewProgress.m in Sources */, 338 | 4413C6271D7037A3005D570A /* WebViewJavascriptBridge.m in Sources */, 339 | 4487F77F1D6C2C4200C9CC9C /* NJKWebViewProgressView.m in Sources */, 340 | 4487F74B1D6C2C2C00C9CC9C /* ViewController.m in Sources */, 341 | 4413C62A1D7037A3005D570A /* WKWebViewJavascriptBridge.m in Sources */, 342 | 4413C6291D7037A3005D570A /* WebViewJavascriptBridgeBase.m in Sources */, 343 | 4487F7801D6C2C4200C9CC9C /* QZBaseWebVC.m in Sources */, 344 | 4413C6281D7037A3005D570A /* WebViewJavascriptBridge_JS.m in Sources */, 345 | 4487F7831D6C2CC600C9CC9C /* WebViewVC.m in Sources */, 346 | 4487F7481D6C2C2C00C9CC9C /* AppDelegate.m in Sources */, 347 | 4487F7451D6C2C2C00C9CC9C /* main.m in Sources */, 348 | ); 349 | runOnlyForDeploymentPostprocessing = 0; 350 | }; 351 | 4487F7551D6C2C2D00C9CC9C /* Sources */ = { 352 | isa = PBXSourcesBuildPhase; 353 | buildActionMask = 2147483647; 354 | files = ( 355 | 4487F75E1D6C2C2D00C9CC9C /* QZBaseWebVCDemoTests.m in Sources */, 356 | ); 357 | runOnlyForDeploymentPostprocessing = 0; 358 | }; 359 | 4487F7601D6C2C2D00C9CC9C /* Sources */ = { 360 | isa = PBXSourcesBuildPhase; 361 | buildActionMask = 2147483647; 362 | files = ( 363 | 4487F7691D6C2C2D00C9CC9C /* QZBaseWebVCDemoUITests.m in Sources */, 364 | ); 365 | runOnlyForDeploymentPostprocessing = 0; 366 | }; 367 | /* End PBXSourcesBuildPhase section */ 368 | 369 | /* Begin PBXTargetDependency section */ 370 | 4487F75B1D6C2C2D00C9CC9C /* PBXTargetDependency */ = { 371 | isa = PBXTargetDependency; 372 | target = 4487F73F1D6C2C2C00C9CC9C /* QZBaseWebVCDemo */; 373 | targetProxy = 4487F75A1D6C2C2D00C9CC9C /* PBXContainerItemProxy */; 374 | }; 375 | 4487F7661D6C2C2D00C9CC9C /* PBXTargetDependency */ = { 376 | isa = PBXTargetDependency; 377 | target = 4487F73F1D6C2C2C00C9CC9C /* QZBaseWebVCDemo */; 378 | targetProxy = 4487F7651D6C2C2D00C9CC9C /* PBXContainerItemProxy */; 379 | }; 380 | /* End PBXTargetDependency section */ 381 | 382 | /* Begin PBXVariantGroup section */ 383 | 4487F74C1D6C2C2C00C9CC9C /* Main.storyboard */ = { 384 | isa = PBXVariantGroup; 385 | children = ( 386 | 4487F74D1D6C2C2C00C9CC9C /* Base */, 387 | ); 388 | name = Main.storyboard; 389 | sourceTree = ""; 390 | }; 391 | 4487F7511D6C2C2C00C9CC9C /* LaunchScreen.storyboard */ = { 392 | isa = PBXVariantGroup; 393 | children = ( 394 | 4487F7521D6C2C2C00C9CC9C /* Base */, 395 | ); 396 | name = LaunchScreen.storyboard; 397 | sourceTree = ""; 398 | }; 399 | /* End PBXVariantGroup section */ 400 | 401 | /* Begin XCBuildConfiguration section */ 402 | 4487F76B1D6C2C2D00C9CC9C /* Debug */ = { 403 | isa = XCBuildConfiguration; 404 | buildSettings = { 405 | ALWAYS_SEARCH_USER_PATHS = NO; 406 | CLANG_ANALYZER_NONNULL = YES; 407 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 408 | CLANG_CXX_LIBRARY = "libc++"; 409 | CLANG_ENABLE_MODULES = YES; 410 | CLANG_ENABLE_OBJC_ARC = YES; 411 | CLANG_WARN_BOOL_CONVERSION = YES; 412 | CLANG_WARN_CONSTANT_CONVERSION = YES; 413 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 414 | CLANG_WARN_EMPTY_BODY = YES; 415 | CLANG_WARN_ENUM_CONVERSION = YES; 416 | CLANG_WARN_INT_CONVERSION = YES; 417 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 418 | CLANG_WARN_UNREACHABLE_CODE = YES; 419 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 420 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 421 | COPY_PHASE_STRIP = NO; 422 | DEBUG_INFORMATION_FORMAT = dwarf; 423 | ENABLE_STRICT_OBJC_MSGSEND = YES; 424 | ENABLE_TESTABILITY = YES; 425 | GCC_C_LANGUAGE_STANDARD = gnu99; 426 | GCC_DYNAMIC_NO_PIC = NO; 427 | GCC_NO_COMMON_BLOCKS = YES; 428 | GCC_OPTIMIZATION_LEVEL = 0; 429 | GCC_PREPROCESSOR_DEFINITIONS = ( 430 | "DEBUG=1", 431 | "$(inherited)", 432 | ); 433 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 434 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 435 | GCC_WARN_UNDECLARED_SELECTOR = YES; 436 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 437 | GCC_WARN_UNUSED_FUNCTION = YES; 438 | GCC_WARN_UNUSED_VARIABLE = YES; 439 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 440 | MTL_ENABLE_DEBUG_INFO = YES; 441 | ONLY_ACTIVE_ARCH = YES; 442 | SDKROOT = iphoneos; 443 | TARGETED_DEVICE_FAMILY = "1,2"; 444 | }; 445 | name = Debug; 446 | }; 447 | 4487F76C1D6C2C2D00C9CC9C /* Release */ = { 448 | isa = XCBuildConfiguration; 449 | buildSettings = { 450 | ALWAYS_SEARCH_USER_PATHS = NO; 451 | CLANG_ANALYZER_NONNULL = YES; 452 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 453 | CLANG_CXX_LIBRARY = "libc++"; 454 | CLANG_ENABLE_MODULES = YES; 455 | CLANG_ENABLE_OBJC_ARC = YES; 456 | CLANG_WARN_BOOL_CONVERSION = YES; 457 | CLANG_WARN_CONSTANT_CONVERSION = YES; 458 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 459 | CLANG_WARN_EMPTY_BODY = YES; 460 | CLANG_WARN_ENUM_CONVERSION = YES; 461 | CLANG_WARN_INT_CONVERSION = YES; 462 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 463 | CLANG_WARN_UNREACHABLE_CODE = YES; 464 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 465 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 466 | COPY_PHASE_STRIP = NO; 467 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 468 | ENABLE_NS_ASSERTIONS = NO; 469 | ENABLE_STRICT_OBJC_MSGSEND = YES; 470 | GCC_C_LANGUAGE_STANDARD = gnu99; 471 | GCC_NO_COMMON_BLOCKS = YES; 472 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 473 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 474 | GCC_WARN_UNDECLARED_SELECTOR = YES; 475 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 476 | GCC_WARN_UNUSED_FUNCTION = YES; 477 | GCC_WARN_UNUSED_VARIABLE = YES; 478 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 479 | MTL_ENABLE_DEBUG_INFO = NO; 480 | SDKROOT = iphoneos; 481 | TARGETED_DEVICE_FAMILY = "1,2"; 482 | VALIDATE_PRODUCT = YES; 483 | }; 484 | name = Release; 485 | }; 486 | 4487F76E1D6C2C2D00C9CC9C /* Debug */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 490 | INFOPLIST_FILE = QZBaseWebVCDemo/Info.plist; 491 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 492 | PRODUCT_BUNDLE_IDENTIFIER = com.qz.QZBaseWebVCDemo; 493 | PRODUCT_NAME = "$(TARGET_NAME)"; 494 | }; 495 | name = Debug; 496 | }; 497 | 4487F76F1D6C2C2D00C9CC9C /* Release */ = { 498 | isa = XCBuildConfiguration; 499 | buildSettings = { 500 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 501 | INFOPLIST_FILE = QZBaseWebVCDemo/Info.plist; 502 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 503 | PRODUCT_BUNDLE_IDENTIFIER = com.qz.QZBaseWebVCDemo; 504 | PRODUCT_NAME = "$(TARGET_NAME)"; 505 | }; 506 | name = Release; 507 | }; 508 | 4487F7711D6C2C2D00C9CC9C /* Debug */ = { 509 | isa = XCBuildConfiguration; 510 | buildSettings = { 511 | BUNDLE_LOADER = "$(TEST_HOST)"; 512 | INFOPLIST_FILE = QZBaseWebVCDemoTests/Info.plist; 513 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 514 | PRODUCT_BUNDLE_IDENTIFIER = com.qz.QZBaseWebVCDemoTests; 515 | PRODUCT_NAME = "$(TARGET_NAME)"; 516 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/QZBaseWebVCDemo.app/QZBaseWebVCDemo"; 517 | }; 518 | name = Debug; 519 | }; 520 | 4487F7721D6C2C2D00C9CC9C /* Release */ = { 521 | isa = XCBuildConfiguration; 522 | buildSettings = { 523 | BUNDLE_LOADER = "$(TEST_HOST)"; 524 | INFOPLIST_FILE = QZBaseWebVCDemoTests/Info.plist; 525 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 526 | PRODUCT_BUNDLE_IDENTIFIER = com.qz.QZBaseWebVCDemoTests; 527 | PRODUCT_NAME = "$(TARGET_NAME)"; 528 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/QZBaseWebVCDemo.app/QZBaseWebVCDemo"; 529 | }; 530 | name = Release; 531 | }; 532 | 4487F7741D6C2C2D00C9CC9C /* Debug */ = { 533 | isa = XCBuildConfiguration; 534 | buildSettings = { 535 | INFOPLIST_FILE = QZBaseWebVCDemoUITests/Info.plist; 536 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 537 | PRODUCT_BUNDLE_IDENTIFIER = com.qz.QZBaseWebVCDemoUITests; 538 | PRODUCT_NAME = "$(TARGET_NAME)"; 539 | TEST_TARGET_NAME = QZBaseWebVCDemo; 540 | }; 541 | name = Debug; 542 | }; 543 | 4487F7751D6C2C2D00C9CC9C /* Release */ = { 544 | isa = XCBuildConfiguration; 545 | buildSettings = { 546 | INFOPLIST_FILE = QZBaseWebVCDemoUITests/Info.plist; 547 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 548 | PRODUCT_BUNDLE_IDENTIFIER = com.qz.QZBaseWebVCDemoUITests; 549 | PRODUCT_NAME = "$(TARGET_NAME)"; 550 | TEST_TARGET_NAME = QZBaseWebVCDemo; 551 | }; 552 | name = Release; 553 | }; 554 | /* End XCBuildConfiguration section */ 555 | 556 | /* Begin XCConfigurationList section */ 557 | 4487F73B1D6C2C2C00C9CC9C /* Build configuration list for PBXProject "QZBaseWebVCDemo" */ = { 558 | isa = XCConfigurationList; 559 | buildConfigurations = ( 560 | 4487F76B1D6C2C2D00C9CC9C /* Debug */, 561 | 4487F76C1D6C2C2D00C9CC9C /* Release */, 562 | ); 563 | defaultConfigurationIsVisible = 0; 564 | defaultConfigurationName = Release; 565 | }; 566 | 4487F76D1D6C2C2D00C9CC9C /* Build configuration list for PBXNativeTarget "QZBaseWebVCDemo" */ = { 567 | isa = XCConfigurationList; 568 | buildConfigurations = ( 569 | 4487F76E1D6C2C2D00C9CC9C /* Debug */, 570 | 4487F76F1D6C2C2D00C9CC9C /* Release */, 571 | ); 572 | defaultConfigurationIsVisible = 0; 573 | defaultConfigurationName = Release; 574 | }; 575 | 4487F7701D6C2C2D00C9CC9C /* Build configuration list for PBXNativeTarget "QZBaseWebVCDemoTests" */ = { 576 | isa = XCConfigurationList; 577 | buildConfigurations = ( 578 | 4487F7711D6C2C2D00C9CC9C /* Debug */, 579 | 4487F7721D6C2C2D00C9CC9C /* Release */, 580 | ); 581 | defaultConfigurationIsVisible = 0; 582 | defaultConfigurationName = Release; 583 | }; 584 | 4487F7731D6C2C2D00C9CC9C /* Build configuration list for PBXNativeTarget "QZBaseWebVCDemoUITests" */ = { 585 | isa = XCConfigurationList; 586 | buildConfigurations = ( 587 | 4487F7741D6C2C2D00C9CC9C /* Debug */, 588 | 4487F7751D6C2C2D00C9CC9C /* Release */, 589 | ); 590 | defaultConfigurationIsVisible = 0; 591 | defaultConfigurationName = Release; 592 | }; 593 | /* End XCConfigurationList section */ 594 | }; 595 | rootObject = 4487F7381D6C2C2C00C9CC9C /* Project object */; 596 | } 597 | --------------------------------------------------------------------------------