chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// TLWebViewController.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/10.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@interface TLWebViewController : UIViewController <WKNavigationDelegate, WKUIDelegate>
|
||||
|
||||
/// 是否使用网页标题作为nav标题,默认YES
|
||||
@property (nonatomic, assign) BOOL useMPageTitleAsNavTitle;
|
||||
|
||||
/// 是否显示加载进度,默认YES
|
||||
@property (nonatomic, assign) BOOL showLoadingProgress;
|
||||
|
||||
/// 是否禁止历史记录,默认NO
|
||||
@property (nonatomic, assign) BOOL disableBackButton;
|
||||
|
||||
/// 是否显示网页的来源信息,默认YES
|
||||
@property (nonatomic, assign) BOOL showPageInfo;
|
||||
|
||||
@property (nonatomic, strong) NSString *url;
|
||||
|
||||
- (id)initWithUrl:(NSString *)urlString;
|
||||
|
||||
- (id)initWithRequest:(NSURLRequest *)request;
|
||||
|
||||
- (void)loadRequest:(NSURLRequest *)request;
|
||||
|
||||
- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,336 @@
|
||||
//
|
||||
// TLWebViewController.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/10.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLWebViewController.h"
|
||||
#import "UIBarButtonItem+Back.h"
|
||||
#import "WKWebView+Post.h"
|
||||
|
||||
#define WEBVIEW_NAVBAR_ITEMS_FIXED_SPACE 9
|
||||
|
||||
@interface TLWebViewController ()
|
||||
|
||||
@property (nonatomic, strong) WKWebView *webView;
|
||||
|
||||
@property (nonatomic, strong) UIProgressView *progressView;
|
||||
|
||||
@property (nonatomic, strong) UIBarButtonItem *backButtonItem;
|
||||
|
||||
@property (nonatomic, strong) UIBarButtonItem *closeButtonItem;
|
||||
|
||||
@property (nonatomic, strong) UILabel *authLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLWebViewController
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
self.useMPageTitleAsNavTitle = YES;
|
||||
self.showLoadingProgress = YES;
|
||||
self.showPageInfo = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithUrl:(NSString *)urlString
|
||||
{
|
||||
if (self = [self init]) {
|
||||
[self setUrl:urlString];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithRequest:(NSURLRequest *)request
|
||||
{
|
||||
if (self = [super init]) {
|
||||
[self loadRequest:request];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
[self.view addSubview:self.authLabel];
|
||||
[self.view addSubview:self.webView];
|
||||
[self.view addSubview:self.progressView];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self.view setBackgroundColor:RGBAColor(46.0, 49.0, 50.0, 1.0)];
|
||||
[self.webView.scrollView setBackgroundColor:[UIColor clearColor]];
|
||||
for (id vc in self.webView.scrollView.subviews) {
|
||||
NSString *className = NSStringFromClass([vc class]);
|
||||
if ([className isEqualToString:@"WKContentView"]) {
|
||||
[vc setBackgroundColor:[UIColor whiteColor]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
|
||||
[self.webView.scrollView addObserver:self forKeyPath:@"backgroundColor" options:NSKeyValueObservingOptionNew context:NULL];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
|
||||
[self.webView.scrollView removeObserver:self forKeyPath:@"backgroundColor"];
|
||||
#ifdef DEBUG_MEMERY
|
||||
NSLog(@"dealloc WebVC");
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews
|
||||
{
|
||||
[super viewWillLayoutSubviews];
|
||||
|
||||
CGFloat statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
|
||||
CGFloat navBarHeight = self.navigationController.navigationBar.frame.size.height;
|
||||
CGFloat width = self.view.bounds.size.width;
|
||||
[self.progressView setY:statusBarHeight + navBarHeight];
|
||||
[self.authLabel setFrame:CGRectMake(20, statusBarHeight + navBarHeight + 13, width - 40, self.authLabel.frame.size.height)];
|
||||
}
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)setUrl:(NSString *)url
|
||||
{
|
||||
if (_url && url && [_url isEqualToString:url]) {
|
||||
return;
|
||||
}
|
||||
_url = url;
|
||||
[self.progressView setProgress:0.0f];
|
||||
[self.webView loadRequest:[NSURLRequest requestWithURL:TLURL(self.url)]];
|
||||
}
|
||||
|
||||
- (void)setShowLoadingProgress:(BOOL)showLoadingProgress
|
||||
{
|
||||
_showLoadingProgress = showLoadingProgress;
|
||||
[self.progressView setHidden:!showLoadingProgress];
|
||||
}
|
||||
|
||||
- (void)loadRequest:(NSURLRequest *)request
|
||||
{
|
||||
[self.webView loadRequest:request];
|
||||
}
|
||||
|
||||
- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
|
||||
{
|
||||
if (string) {
|
||||
[self.webView loadHTMLString:string baseURL:baseURL];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Delegate
|
||||
//MARK: WKNavigationDelegate
|
||||
// 开始加载页面
|
||||
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
|
||||
{
|
||||
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
|
||||
}
|
||||
|
||||
// 开始返回页面内容
|
||||
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
|
||||
{
|
||||
if (webView.canGoBack) {
|
||||
[self.navigationItem setLeftBarButtonItems:@[[UIBarButtonItem fixItemSpace:-WEBVIEW_NAVBAR_ITEMS_FIXED_SPACE], self.backButtonItem, self.closeButtonItem]];
|
||||
}
|
||||
}
|
||||
|
||||
// 加载完成
|
||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
|
||||
{
|
||||
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
|
||||
if (self.useMPageTitleAsNavTitle) {
|
||||
[self.navigationItem setTitle:webView.title];
|
||||
}
|
||||
if (self.showPageInfo) {
|
||||
if (webView.URL.host.length > 0) {
|
||||
[self.authLabel setText:[NSString stringWithFormat:@"网页由 %@ 提供", webView.URL.host]];
|
||||
}
|
||||
else {
|
||||
[self.authLabel setText:@""];
|
||||
}
|
||||
[self.authLabel setHeight:[self.authLabel sizeThatFits:CGSizeMake(self.authLabel.width, MAXFLOAT)].height];
|
||||
}
|
||||
}
|
||||
|
||||
// 加载失败
|
||||
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
|
||||
{
|
||||
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
|
||||
[TLUIUtility showAlertWithTitle:nil message:[error description]];
|
||||
}
|
||||
|
||||
// 页面跳转处理
|
||||
// 接收到服务器跳转请求之后调用
|
||||
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// 在收到响应后,决定是否跳转
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
|
||||
{
|
||||
decisionHandler(WKNavigationResponsePolicyAllow);
|
||||
}
|
||||
|
||||
// 在发送请求之前,决定是否跳转
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
|
||||
{
|
||||
NSString *urlString = navigationAction.request.URL.absoluteString;
|
||||
if ([urlString hasPrefix:@"itms-apps://itunes.apple.com"]
|
||||
|| [urlString hasPrefix:@"https://itunes.apple.com"]
|
||||
|| [urlString hasPrefix:@"itms-services:"]
|
||||
|| [urlString hasPrefix:@"tel:"]
|
||||
|| [urlString hasPrefix:@"mailto:"]
|
||||
|| [urlString hasPrefix:@"mqqwpa:"]) {
|
||||
[[UIApplication sharedApplication] openURL:navigationAction.request.URL];
|
||||
decisionHandler(WKNavigationActionPolicyCancel);
|
||||
}
|
||||
else {
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: WKUIDelegate
|
||||
// web界面中有弹出警告框
|
||||
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(nonnull NSString *)message initiatedByFrame:(nonnull WKFrameInfo *)frame completionHandler:(nonnull void (^)(void))completionHandler
|
||||
{
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
||||
completionHandler();
|
||||
}]];
|
||||
|
||||
[self presentViewController:alertController animated:YES completion:^{}];
|
||||
}
|
||||
|
||||
// web界面中有确认框
|
||||
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(nonnull NSString *)message initiatedByFrame:(nonnull WKFrameInfo *)frame completionHandler:(nonnull void (^)(BOOL))completionHandler
|
||||
{
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message
|
||||
message:nil
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"确定"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
completionHandler(YES);
|
||||
}]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"取消"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *action){
|
||||
completionHandler(NO);
|
||||
}]];
|
||||
|
||||
[self presentViewController:alertController animated:YES completion:^{}];
|
||||
}
|
||||
|
||||
// web界面中有弹出输入框
|
||||
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(nonnull NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(nonnull WKFrameInfo *)frame completionHandler:(nonnull void (^)(NSString * _Nullable))completionHandler {
|
||||
completionHandler(@"Client Not handler");
|
||||
}
|
||||
|
||||
#pragma mark - # Event Response
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
|
||||
if (self.showLoadingProgress && [keyPath isEqualToString:@"estimatedProgress"] && object == self.webView) {
|
||||
[self.progressView setAlpha:1.0f];
|
||||
[self.progressView setProgress:self.webView.estimatedProgress animated:YES];
|
||||
|
||||
if(self.webView.estimatedProgress >= 1.0f) {
|
||||
[UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
[self.progressView setAlpha:0.0f];
|
||||
} completion:^(BOOL finished) {
|
||||
[self.progressView setProgress:0.0f animated:NO];
|
||||
}];
|
||||
}
|
||||
}
|
||||
else if ([keyPath isEqualToString:@"backgroundColor"] && object == self.webView.scrollView) {
|
||||
UIColor *color = [change objectForKey:@"new"];
|
||||
if (!CGColorEqualToColor(color.CGColor, [UIColor clearColor].CGColor)) {
|
||||
[object setBackgroundColor:[UIColor clearColor]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)navBackButotnDown
|
||||
{
|
||||
if (self.webView.canGoBack) {
|
||||
[self.webView goBack];
|
||||
}
|
||||
else {
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)navCloseButtonDown
|
||||
{
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - # Getters
|
||||
- (WKWebView *)webView
|
||||
{
|
||||
if (_webView == nil) {
|
||||
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, STATUSBAR_HEIGHT + NAVBAR_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - STATUSBAR_HEIGHT - NAVBAR_HEIGHT)];
|
||||
[_webView setAllowsBackForwardNavigationGestures:YES];
|
||||
[_webView setNavigationDelegate:self];
|
||||
[_webView setUIDelegate:self];
|
||||
[_webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
|
||||
}
|
||||
return _webView;
|
||||
}
|
||||
|
||||
- (UIProgressView *)progressView
|
||||
{
|
||||
if (_progressView == nil) {
|
||||
_progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, NAVBAR_HEIGHT + STATUSBAR_HEIGHT, SCREEN_WIDTH, 10.0f)];
|
||||
[_progressView setTransform:CGAffineTransformMakeScale(1.0f, 2.0f)];
|
||||
[_progressView setProgressTintColor:RGBAColor(2.0, 187.0, 0.0, 1.0f)];
|
||||
[_progressView setTrackTintColor:[UIColor clearColor]];
|
||||
[_progressView setProgress:0];
|
||||
}
|
||||
return _progressView;
|
||||
}
|
||||
|
||||
- (UIBarButtonItem *)backButtonItem
|
||||
{
|
||||
if (_backButtonItem == nil) {
|
||||
_backButtonItem = [[UIBarButtonItem alloc] initWithBackTitle:@"返回" target:self action:@selector(navBackButotnDown)];
|
||||
}
|
||||
return _backButtonItem;
|
||||
}
|
||||
|
||||
- (UIBarButtonItem *)closeButtonItem
|
||||
{
|
||||
if (_closeButtonItem == nil) {
|
||||
_closeButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"关闭" style:UIBarButtonItemStylePlain target:self action:@selector(navCloseButtonDown)];
|
||||
}
|
||||
return _closeButtonItem;
|
||||
}
|
||||
|
||||
- (UILabel *)authLabel
|
||||
{
|
||||
if (_authLabel == nil) {
|
||||
_authLabel = [[UILabel alloc] init];
|
||||
[_authLabel setFont:[UIFont systemFontOfSize:12.0f]];
|
||||
[_authLabel setTextAlignment:NSTextAlignmentCenter];
|
||||
[_authLabel setTextColor:[UIColor grayColor]];
|
||||
[_authLabel setNumberOfLines:0];
|
||||
}
|
||||
return _authLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// UIBarButtonItem+Back.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 2017/9/13.
|
||||
// Copyright © 2017年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIBarButtonItem (Back)
|
||||
|
||||
- (id)initWithBackTitle:(NSString *)title target:(id)target action:(SEL)action;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// UIBarButtonItem+Back.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 2017/9/13.
|
||||
// Copyright © 2017年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIBarButtonItem+Back.h"
|
||||
|
||||
@implementation UIBarButtonItem (Back)
|
||||
|
||||
- (id)initWithBackTitle:(NSString *)title target:(id)target action:(SEL)action
|
||||
{
|
||||
UIButton *view = [[UIButton alloc] init];
|
||||
[view addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"nav_back"]];
|
||||
[view addSubview:imageView];
|
||||
|
||||
UILabel *label = [[UILabel alloc] init];
|
||||
[label setText:title];
|
||||
[label setTextColor:[UIColor whiteColor]];
|
||||
[view addSubview:label];
|
||||
|
||||
if (self = [self initWithCustomView:view]) {
|
||||
[imageView setFrame:CGRectMake(0, 0, 17, 34)];
|
||||
CGSize size = [label sizeThatFits:CGSizeMake(MAXFLOAT, MAXFLOAT)];
|
||||
[label setFrame:CGRectMake(17, 0, size.width, 34)];
|
||||
[view setFrame:CGRectMake(0, 0, label.frame.origin.x + label.frame.size.width, 34)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// WKWebView+Post.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 17/9/10.
|
||||
// Copyright © 2017年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@interface WKWebView (Post)
|
||||
|
||||
@end
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// WKWebView+Post.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 17/9/10.
|
||||
// Copyright © 2017年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "WKWebView+Post.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation WKWebView (Post)
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
Class class = [self class];
|
||||
SEL originalSelector = @selector(loadRequest:);
|
||||
SEL swizzledSelector = @selector(post_loadRequest:);
|
||||
Method originalMethod = class_getInstanceMethod(class, originalSelector);
|
||||
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
|
||||
BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
|
||||
if (success) {
|
||||
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
|
||||
}
|
||||
else {
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
}
|
||||
}
|
||||
|
||||
- (WKNavigation *)post_loadRequest:(NSURLRequest *)request
|
||||
{
|
||||
if ([[request.HTTPMethod uppercaseString] isEqualToString:@"POST"]){
|
||||
NSString *url = request.URL.absoluteString;
|
||||
NSString *params = [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
|
||||
if ([params containsString:@"="]) {
|
||||
params = [params stringByReplacingOccurrencesOfString:@"=" withString:@"\":\""];
|
||||
params = [params stringByReplacingOccurrencesOfString:@"&" withString:@"\",\""];
|
||||
params = [NSString stringWithFormat:@"{\"%@\"}", params];
|
||||
}
|
||||
else {
|
||||
params = @"{}";
|
||||
}
|
||||
NSString *postJavaScript = [NSString stringWithFormat:@"\
|
||||
var url = '%@';\
|
||||
var params = %@;\
|
||||
var form = document.createElement('form');\
|
||||
form.setAttribute('method', 'post');\
|
||||
form.setAttribute('action', url);\
|
||||
for(var key in params) {\
|
||||
if(params.hasOwnProperty(key)) {\
|
||||
var hiddenField = document.createElement('input');\
|
||||
hiddenField.setAttribute('type', 'hidden');\
|
||||
hiddenField.setAttribute('name', key);\
|
||||
hiddenField.setAttribute('value', params[key]);\
|
||||
form.appendChild(hiddenField);\
|
||||
}\
|
||||
}\
|
||||
document.body.appendChild(form);\
|
||||
form.submit();", url, params];
|
||||
__weak typeof(self) wself = self;
|
||||
[self evaluateJavaScript:postJavaScript completionHandler:^(id object, NSError * _Nullable error) {
|
||||
if (error && [wself.navigationDelegate respondsToSelector:@selector(webView:didFailProvisionalNavigation:withError:)]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[wself.navigationDelegate webView:wself didFailProvisionalNavigation:nil withError:error];
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
else {
|
||||
return [self post_loadRequest:request];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user