Skip to content

Using WKWebView instead of UIWebView #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ios/Classes/FlutterWebviewPlugin.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#import <Flutter/Flutter.h>
#import <WebKit/WebKit.h>

static FlutterMethodChannel *channel;

@interface FlutterWebviewPlugin : NSObject<FlutterPlugin>
@property (nonatomic, retain) UIViewController *viewController;
@property (nonatomic, retain) UIWebView *webview;
@property (nonatomic, retain) WKWebView *webview;
@end
127 changes: 72 additions & 55 deletions ios/Classes/FlutterWebviewPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
static NSString *const CHANNEL_NAME = @"flutter_webview_plugin";

// UIWebViewDelegate
@interface FlutterWebviewPlugin() <UIWebViewDelegate> {
@interface FlutterWebviewPlugin() <WKNavigationDelegate, UIScrollViewDelegate> {
BOOL _enableAppScheme;
BOOL _enableZoom;
}
@end

Expand Down Expand Up @@ -39,7 +40,9 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
[self closeWebView];
result(nil);
} else if ([@"eval" isEqualToString:call.method]) {
result([self evalJavascript:call]);
[self evalJavascript:call completionHandler:^(NSString * response) {
result(response);
}];
} else if ([@"resize" isEqualToString:call.method]) {
[self resize:call];
result(nil);
Expand All @@ -49,7 +52,6 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
}

- (void)initWebview:(FlutterMethodCall*)call {
// NSNumber *withJavascript = call.arguments[@"withJavascript"];
NSNumber *clearCache = call.arguments[@"clearCache"];
NSNumber *clearCookies = call.arguments[@"clearCookies"];
NSNumber *hidden = call.arguments[@"hidden"];
Expand All @@ -58,7 +60,6 @@ - (void)initWebview:(FlutterMethodCall*)call {
NSString *userAgent = call.arguments[@"userAgent"];
NSNumber *withZoom = call.arguments[@"withZoom"];

//
if (clearCache != (id)[NSNull null] && [clearCache boolValue]) {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
Expand All @@ -79,18 +80,15 @@ - (void)initWebview:(FlutterMethodCall*)call {
rc = self.viewController.view.bounds;
}

self.webview = [[UIWebView alloc] initWithFrame:rc];
self.webview.delegate = self;

if (withZoom != (id)[NSNull null] && [withZoom boolValue]) {
self.webview.scalesPageToFit = YES;
}

if (hidden != (id)[NSNull null] && [hidden boolValue]) {
self.webview.hidden = YES;
}
self.webview = [[WKWebView alloc] initWithFrame:rc];
self.webview.navigationDelegate = self;
self.webview.scrollView.delegate = self;
self.webview.hidden = [hidden boolValue];

_enableZoom = [withZoom boolValue];

[self.viewController.view addSubview:self.webview];

[self navigate:call];
}

Expand All @@ -102,73 +100,92 @@ - (CGRect)parseRect:(NSDictionary *)rect {
}

- (void)navigate:(FlutterMethodCall*)call {
NSString *url = call.arguments[@"url"];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[self.webview loadRequest:request];
if (self.webview != nil) {
NSString *url = call.arguments[@"url"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[self.webview loadRequest:request];
}
}

- (NSString *)evalJavascript:(FlutterMethodCall*)call {
NSString *code = call.arguments[@"code"];

NSString *result = [self.webview stringByEvaluatingJavaScriptFromString:code];
return result;
- (void)evalJavascript:(FlutterMethodCall*)call
completionHandler:(void (^_Nullable)(NSString * response))completionHandler {
if (self.webview != nil) {
NSString *code = call.arguments[@"code"];
[self.webview evaluateJavaScript:code
completionHandler:^(id _Nullable response, NSError * _Nullable error) {
completionHandler([NSString stringWithFormat:@"%@", response]);
}];
} else {
completionHandler(nil);
}
}

- (void)resize:(FlutterMethodCall*)call {
NSDictionary *rect = call.arguments[@"rect"];
CGRect rc = [self parseRect:rect];
self.webview.frame = rc;
if (self.webview != nil) {
NSDictionary *rect = call.arguments[@"rect"];
CGRect rc = [self parseRect:rect];
self.webview.frame = rc;
}
}

- (void)closeWebView {
[self.webview stopLoading];
[self.webview removeFromSuperview];
self.webview.delegate = nil;
self.webview = nil;

// manually trigger onDestroy
[channel invokeMethod:@"onDestroy" arguments:nil];
if (self.webview != nil) {
[self.webview stopLoading];
[self.webview removeFromSuperview];
self.webview.navigationDelegate = nil;
self.webview = nil;

// manually trigger onDestroy
[channel invokeMethod:@"onDestroy" arguments:nil];
}
}

#pragma mark -- WkWebView Delegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

#pragma mark -- WebView Delegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
id data = @{@"url": request.URL.absoluteString,
id data = @{@"url": navigationAction.request.URL.absoluteString,
@"type": @"shouldStart",
@"navigationType": [NSNumber numberWithInt:navigationType]};
@"navigationType": [NSNumber numberWithInt:navigationAction.navigationType]};
[channel invokeMethod:@"onState" arguments:data];
if (navigationType == UIWebViewNavigationTypeBackForward)

if (navigationAction.navigationType == WKNavigationTypeBackForward) {
[channel invokeMethod:@"onBackPressed" arguments:nil];
else {
id data = @{@"url": request.URL.absoluteString};
} else {
id data = @{@"url": navigationAction.request.URL.absoluteString};
[channel invokeMethod:@"onUrlChanged" arguments:data];
}

if (_enableAppScheme)
return YES;

// disable some scheme
return [request.URL.scheme isEqualToString:@"http"] ||
[request.URL.scheme isEqualToString:@"https"] ||
[request.URL.scheme isEqualToString:@"about"];
if (_enableAppScheme ||
([webView.URL.scheme isEqualToString:@"http"] ||
[webView.URL.scheme isEqualToString:@"https"] ||
[webView.URL.scheme isEqualToString:@"about"])) {
decisionHandler(WKNavigationActionPolicyAllow);
} else {
decisionHandler(WKNavigationActionPolicyCancel);
}
}

-(void)webViewDidStartLoad:(UIWebView *)webView {
[channel invokeMethod:@"onState" arguments:@{@"type": @"startLoad", @"url": webView.request.URL.absoluteString}];
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
[channel invokeMethod:@"onState" arguments:@{@"type": @"startLoad", @"url": webView.URL.absoluteString}];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
[channel invokeMethod:@"onState" arguments:@{@"type": @"finishLoad", @"url": webView.request.URL.absoluteString}];
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[channel invokeMethod:@"onState" arguments:@{@"type": @"finishLoad", @"url": webView.URL.absoluteString}];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
id data = [FlutterError errorWithCode:[NSString stringWithFormat:@"%ld", error.code]
message:error.localizedDescription
details:error.localizedFailureReason];
[channel invokeMethod:@"onError" arguments:data];
}

#pragma mark -- WkWebView Delegate
#pragma mark -- UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if (scrollView.pinchGestureRecognizer.isEnabled != _enableZoom) {
scrollView.pinchGestureRecognizer.enabled = _enableZoom;
}
}

@end