Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[webview_flutter] Support for loading progress tracking #2151

Merged
merged 39 commits into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2375fa7
Added support for loading progress tracking (iOS & Android)
jeremie-movify Oct 4, 2019
704cc75
Updated changelog, bumped plugin version & fixed Dart analyzer
jeremie-movify Oct 4, 2019
90b47c1
Fixed formatting
jeremie-movify Oct 4, 2019
a795c90
Fixed formatting for FlutterWebView & FlutterWebViewClient
jeremie-movify Oct 4, 2019
a618831
One more formatting pass
jeremie-movify Oct 4, 2019
e201d3c
One more formatting pass
jeremie-movify Oct 4, 2019
1fe7ef4
Merge branch 'master' into progress-tracking
jeremie-movify Nov 4, 2019
03a6307
Merge branch 'master' into progress-tracking
jeremie-movify Nov 22, 2019
b1052b4
Merge branch 'master' into progress-tracking
jeremie-movify Jan 28, 2020
5cd61b2
Update FLTWKNavigationDelegate.h
jeremie-movify Jan 28, 2020
f153499
Update pubspec.yaml
jeremie-movify Jan 28, 2020
19d697e
Added missing null return
jeremie-movify Mar 2, 2020
9ceea3c
Merge branch 'master' into progress-tracking
jeremie-movify Mar 2, 2020
a5906b3
Merge branch 'master' into progress-tracking
jeremie-movify Mar 19, 2020
a357555
Merge branch 'flutter-origin-master' into progress-tracking
jeremie-movify Apr 6, 2020
eb809fc
Merge branch 'master' into progress-tracking
jeremie-movify Apr 10, 2020
636ad6f
Merge branch 'master' into progress-tracking
jeremie-movify Apr 28, 2020
677bad9
Trigger checks
jeremie-movify May 6, 2020
25af806
Merge branch 'master' into progress-tracking
jeremie-movify May 29, 2020
a020da2
Merge branch 'master' into progress-tracking
jeremie-movify Aug 27, 2020
07ab322
Improvements based on @cyanglaz's feedback
jeremie-movify Sep 10, 2020
f3de98b
Only observe newValues on webView's 'estimatedProgress' keyPath
jeremie-movify Sep 10, 2020
76e2d76
Fixed formatting
jeremie-movify Sep 11, 2020
a778bf3
Updated keyPath constant name to FLTWKEstimatedProgressKeyPath
jeremie-movify Sep 14, 2020
0090288
Fixed formatting
jeremie-movify Sep 14, 2020
a6f2b53
Merge branch 'flutter-origin-master' into progress-tracking
jeremie-movify Sep 22, 2020
a706d3e
Fixed formatting
jeremie-movify Sep 22, 2020
2897586
Merge branch 'flutter-origin-master' into progress-tracking
jeremie-movify Nov 16, 2020
24c77c2
Merge branch 'flutter-origin-master' into progress-tracking
jeremie-movify Jan 12, 2021
069af29
Fixed hasProgressTracking nullability
jeremie-movify Jan 12, 2021
6fa576d
Nullability fixes
jeremie-movify Jan 12, 2021
7d7c400
One more
jeremie-movify Jan 12, 2021
11e6ade
Fixed imports
jeremie-movify Jan 14, 2021
1747608
Merge branch 'flutter-origin-master' into progress-tracking
jeremie-movify Jan 14, 2021
16c7d33
Trigger checks
jeremie-movify Jan 15, 2021
73d09be
Imported androidx.annotation.NonNull to fix apk build on cirrus
jeremie-movify Jan 18, 2021
a9bcf56
Merge branch 'master' into progress-tracking
jeremie-movify Feb 16, 2021
d9438f1
Merge branch 'flutter-origin-master' into progress-tracking
jeremie-movify Feb 17, 2021
6cc00fc
PR remarks: Android: improved progress tracking setup & reused existi…
jeremie-movify Feb 17, 2021
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
5 changes: 5 additions & 0 deletions packages/webview_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.3.22+3

* Added support for progress tracking.

## 0.3.22+2

* Update package:e2e reference to use the local version in the flutter/plugins
Expand Down Expand Up @@ -36,6 +40,7 @@

* Remove example app's iOS workspace settings.


jeremie-movify marked this conversation as resolved.
Show resolved Hide resolved
## 0.3.19+8

* Make the pedantic dev_dependency explicit.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import android.os.Build;
import android.os.Handler;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
Expand Down Expand Up @@ -306,12 +308,23 @@ private void applySettings(Map<String, Object> settings) {
flutterWebViewClient.createWebViewClient(hasNavigationDelegate);

webView.setWebViewClient(webViewClient);

jeremie-movify marked this conversation as resolved.
Show resolved Hide resolved
break;
case "debuggingEnabled":
final boolean debuggingEnabled = (boolean) settings.get(key);

webView.setWebContentsDebuggingEnabled(debuggingEnabled);
break;
case "hasProgressTracking":
final boolean progressTrackingEnabled = (boolean) settings.get(key);
if (progressTrackingEnabled) {
webView.setWebChromeClient(
new WebChromeClient() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we refactor the WebChromeClient out to somewhere else? Maybe an instance var? We likely will add more to the WebChromeClient in the future and it would be cleaner to have it somewhere stand alone.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have another PR which is going to add a WebChromeClient to the webview: #2991. There will be conflicts once the other PR lands.
Maybe let's wait for the other PR to land and rebase?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we refactor this code into FlutterWebChromeClient instead of creating a new WebChromeClient

public void onProgressChanged(WebView view, int progress) {
flutterWebViewClient.onLoadingProgress(progress);
}
});
}
case "gestureNavigationEnabled":
break;
case "userAgent":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class FlutterWebViewClient {
private static final String TAG = "FlutterWebViewClient";
private final MethodChannel methodChannel;
private boolean hasNavigationDelegate;
private boolean hasProgressTracking;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, this flag wasn't used properly. I've updated the PR so that progress changes are sent to the method channel only if hasProgressTracking is true.


FlutterWebViewClient(MethodChannel methodChannel) {
this.methodChannel = methodChannel;
Expand Down Expand Up @@ -125,6 +126,12 @@ private void onPageFinished(WebView view, String url) {
methodChannel.invokeMethod("onPageFinished", args);
}

void onLoadingProgress(int progress) {
Map<String, Object> args = new HashMap<>();
args.put("progress", progress);
methodChannel.invokeMethod("onProgress", args);
}

private void onWebResourceError(
final int errorCode, final String description, final String failingUrl) {
final Map<String, Object> args = new HashMap<>();
Expand Down
3 changes: 3 additions & 0 deletions packages/webview_flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class _WebViewExampleState extends State<WebViewExample> {
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
onProgress: (int progress) {
print("WebView is loading (progress : $progress%)");
},
// TODO(iskakaushik): Remove this when collection literals makes it to stable.
// ignore: prefer_collection_literals
javascriptChannels: <JavascriptChannel>[
Expand Down
22 changes: 22 additions & 0 deletions packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
jeremie-movify marked this conversation as resolved.
Show resolved Hide resolved
// FLTWKProgressionDelegate.h
// webview_flutter
//
// Created by Jérémie Vincke on 03/10/2019.
//

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

NS_ASSUME_NONNULL_BEGIN

@interface FLTWKProgressionDelegate : NSObject

- (instancetype)initWithWebView:(WKWebView *)webView channel:(FlutterMethodChannel *)channel;

- (void)stopObservingProgress:(WKWebView *)webView;

@end

NS_ASSUME_NONNULL_END
45 changes: 45 additions & 0 deletions packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// FLTWKProgressionDelegate.m
// webview_flutter
//
// Created by Jérémie Vincke on 03/10/2019.
//

#import "FLTWKProgressionDelegate.h"

NSString *const keyPath = @"estimatedProgress";
jeremie-movify marked this conversation as resolved.
Show resolved Hide resolved

@implementation FLTWKProgressionDelegate {
FlutterMethodChannel *_methodChannel;
}

- (instancetype)initWithWebView:(WKWebView *)webView channel:(FlutterMethodChannel *)channel {
self = [super init];
if (self) {
_methodChannel = channel;
[webView addObserver:self
forKeyPath:keyPath
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
jeremie-movify marked this conversation as resolved.
Show resolved Hide resolved
context:nil];
}
return self;
}

- (void)stopObservingProgress:(WKWebView *)webView {
[webView removeObserver:self forKeyPath:keyPath];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
context:(void *)context {
if ([keyPath isEqualToString:keyPath]) {
NSNumber *newValue =
change[NSKeyValueChangeNewKey] ?: 0; // newValue is anywhere between 0.0 and 1.0
int newValueAsInt = [newValue floatValue] * 100; // Anywhere between 0 and 100
[_methodChannel invokeMethod:@"onProgress"
arguments:@{@"progress" : [NSNumber numberWithInt:newValueAsInt]}];
}
}

@end
15 changes: 15 additions & 0 deletions packages/webview_flutter/ios/Classes/FlutterWebView.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#import "FlutterWebView.h"
#import "FLTWKNavigationDelegate.h"
#import "FLTWKProgressionDelegate.h"
#import "JavaScriptChannelHandler.h"

@implementation FLTWebViewFactory {
Expand Down Expand Up @@ -64,6 +65,7 @@ @implementation FLTWebViewController {
// The set of registered JavaScript channel names.
NSMutableSet* _javaScriptChannelNames;
FLTWKNavigationDelegate* _navigationDelegate;
FLTWKProgressionDelegate* _progressionDelegate;
}

- (instancetype)initWithFrame:(CGRect)frame
Expand Down Expand Up @@ -119,6 +121,12 @@ - (instancetype)initWithFrame:(CGRect)frame
return self;
}

- (void)dealloc {
if (_progressionDelegate != nil) {
[_progressionDelegate stopObservingProgress:_webView];
}
}

- (UIView*)view {
return _webView;
}
Expand Down Expand Up @@ -323,6 +331,13 @@ - (NSString*)applySettings:(NSDictionary<NSString*, id>*)settings {
} else if ([key isEqualToString:@"hasNavigationDelegate"]) {
NSNumber* hasDartNavigationDelegate = settings[key];
_navigationDelegate.hasDartNavigationDelegate = [hasDartNavigationDelegate boolValue];
} else if ([key isEqualToString:@"hasProgressTracking"]) {
NSNumber* hasProgressTrackingValue = settings[key];
bool hasProgressTracking = [hasProgressTrackingValue boolValue];
if (hasProgressTracking) {
_progressionDelegate = [[FLTWKProgressionDelegate alloc] initWithWebView:_webView
channel:_channel];
}
} else if ([key isEqualToString:@"debuggingEnabled"]) {
// no-op debugging is always enabled on iOS.
} else if ([key isEqualToString:@"gestureNavigationEnabled"]) {
Expand Down
9 changes: 8 additions & 1 deletion packages/webview_flutter/lib/platform_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ abstract class WebViewPlatformCallbacksHandler {
/// Invoked by [WebViewPlatformController] when a page has finished loading.
void onPageFinished(String url);

/// Invoked by [WebViewPlatformController] when a page is loading.
jeremie-movify marked this conversation as resolved.
Show resolved Hide resolved
void onProgress(int progress);

/// Report web resource loading error to the host application.
void onWebResourceError(WebResourceError error);
}
Expand Down Expand Up @@ -380,6 +383,7 @@ class WebSettings {
WebSettings({
this.javascriptMode,
this.hasNavigationDelegate,
this.hasProgressTracking,
this.debuggingEnabled,
this.gestureNavigationEnabled,
@required this.userAgent,
Expand All @@ -391,6 +395,9 @@ class WebSettings {
/// Whether the [WebView] has a [NavigationDelegate] set.
final bool hasNavigationDelegate;

/// Whether the [WebView] should track page loading progress.
jeremie-movify marked this conversation as resolved.
Show resolved Hide resolved
final bool hasProgressTracking;

/// Whether to enable the platform's webview content debugging tools.
///
/// See also: [WebView.debuggingEnabled].
Expand All @@ -413,7 +420,7 @@ class WebSettings {

@override
String toString() {
return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent)';
return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, hasProgressTracking: $hasProgressTracking, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent)';
}
}

Expand Down
4 changes: 4 additions & 0 deletions packages/webview_flutter/lib/src/webview_method_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController {
case 'onPageFinished':
_platformCallbacksHandler.onPageFinished(call.arguments['url']);
return null;
case 'onProgress':
_platformCallbacksHandler.onProgress(call.arguments['progress']);
jeremie-movify marked this conversation as resolved.
Show resolved Hide resolved
return null;
case 'onPageStarted':
_platformCallbacksHandler.onPageStarted(call.arguments['url']);
return null;
Expand Down Expand Up @@ -178,6 +181,7 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController {

_addIfNonNull('jsMode', settings.javascriptMode?.index);
_addIfNonNull('hasNavigationDelegate', settings.hasNavigationDelegate);
_addIfNonNull('hasProgressTracking', settings.hasProgressTracking);
_addIfNonNull('debuggingEnabled', settings.debuggingEnabled);
_addIfNonNull(
'gestureNavigationEnabled', settings.gestureNavigationEnabled);
Expand Down
20 changes: 20 additions & 0 deletions packages/webview_flutter/lib/webview_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ typedef void PageStartedCallback(String url);
/// Signature for when a [WebView] has finished loading a page.
typedef void PageFinishedCallback(String url);

/// Signature for when a [WebView] is loading a page.
typedef void PageLoadingCallback(int progress);

/// Signature for when a [WebView] has failed to load a resource.
typedef void WebResourceErrorCallback(WebResourceError error);

Expand Down Expand Up @@ -150,6 +153,7 @@ class WebView extends StatefulWidget {
this.gestureRecognizers,
this.onPageStarted,
this.onPageFinished,
this.onProgress,
this.onWebResourceError,
this.debuggingEnabled = false,
this.gestureNavigationEnabled = false,
Expand Down Expand Up @@ -281,6 +285,9 @@ class WebView extends StatefulWidget {
/// [WebViewController.evaluateJavascript] can assume this.
final PageFinishedCallback onPageFinished;

/// Invoked when a page is loading.
final PageLoadingCallback onProgress;

/// Invoked when a web resource has failed to load.
///
/// This can be called for any resource (iframe, image, etc.), not just for
Expand Down Expand Up @@ -400,6 +407,7 @@ WebSettings _webSettingsFromWidget(WebView widget) {
return WebSettings(
javascriptMode: widget.javascriptMode,
hasNavigationDelegate: widget.navigationDelegate != null,
hasProgressTracking: widget.onProgress != null,
debuggingEnabled: widget.debuggingEnabled,
gestureNavigationEnabled: widget.gestureNavigationEnabled,
userAgent: WebSetting<String>.of(widget.userAgent),
Expand All @@ -411,6 +419,7 @@ WebSettings _clearUnchangedWebSettings(
WebSettings currentValue, WebSettings newValue) {
assert(currentValue.javascriptMode != null);
assert(currentValue.hasNavigationDelegate != null);
assert(currentValue.hasProgressTracking != null);
assert(currentValue.debuggingEnabled != null);
assert(currentValue.userAgent.isPresent);
assert(newValue.javascriptMode != null);
Expand All @@ -420,6 +429,7 @@ WebSettings _clearUnchangedWebSettings(

JavascriptMode javascriptMode;
bool hasNavigationDelegate;
bool hasProgressTracking;
bool debuggingEnabled;
WebSetting<String> userAgent = WebSetting<String>.absent();
if (currentValue.javascriptMode != newValue.javascriptMode) {
Expand All @@ -428,6 +438,9 @@ WebSettings _clearUnchangedWebSettings(
if (currentValue.hasNavigationDelegate != newValue.hasNavigationDelegate) {
hasNavigationDelegate = newValue.hasNavigationDelegate;
}
if (currentValue.hasProgressTracking != newValue.hasProgressTracking) {
hasProgressTracking = newValue.hasProgressTracking;
}
if (currentValue.debuggingEnabled != newValue.debuggingEnabled) {
debuggingEnabled = newValue.debuggingEnabled;
}
Expand All @@ -438,6 +451,7 @@ WebSettings _clearUnchangedWebSettings(
return WebSettings(
javascriptMode: javascriptMode,
hasNavigationDelegate: hasNavigationDelegate,
hasProgressTracking: hasProgressTracking,
debuggingEnabled: debuggingEnabled,
userAgent: userAgent,
);
Expand Down Expand Up @@ -493,6 +507,12 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler {
}

@override
void onProgress(int progress) {
if (_widget.onProgress != null) {
_widget.onProgress(progress);
}
}

void onWebResourceError(WebResourceError error) {
if (_widget.onWebResourceError != null) {
_widget.onWebResourceError(error);
Expand Down
Loading