-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[webview_flutter] Add onReceivedError callback #2639
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Overall looks good, left a few nits and questions.
final Map<String, String> errorResult = await errorCompleter.future; | ||
expect(errorResult['errorCode'], isNotNull); | ||
expect(errorResult['description'], isNotNull); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a test with a valid url that verifies the error callback is not invoked on a valid url. I'd use a data url like:
'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
} | ||
|
||
final String message = | ||
String.format(Locale.getDefault(), "Could not find a string for errorCode: %d", errorCode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
Is %d
formatting affected by the locale?
Also seems like you can omit specifying Locale.getDefault()
as this is the default for the String.format
version that doesn't take a locale.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only added the Locale.getDefault()
to get rid of the lint warning. It does change the digit to whatever locale the device is set to. I don't think it would change the interpretation of the digit though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, my read of https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax is that %d
formatting is not affected by the locale.
/// (e.g. The error code of `WebViewClient.ERROR_AUTHENTICATION` on Android | ||
/// translates to `AUTHENTICATION` in Dart. | ||
/// | ||
/// On iOS, the error code will represent the "domain" and the "code" for an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My preference would be to avoid having different semantic meaning to the same field on different platforms.
Instead I'd have different fields with a single semantic meaning which may not be set on all platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. I added a domain
only for iOS and a errorType
that can be null
on iOS.
/// translates to `AUTHENTICATION` in Dart. | ||
/// | ||
/// On iOS, the error code will represent the "domain" and the "code" for an | ||
/// `NSError` in Objective-C. The format will be `$domain: $code`. See |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is $code the http status code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's possible for it to be an http status code, but the documentation doesn't say anything about it:
https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455623-webview?language=objc
However, their https://developer.apple.com/documentation/webkit/wkerrorcode?language=objc states that these are possible values. I can't tell if these are the ONLY possible values or not.
typedef void PageFinishedCallback(String url); | ||
|
||
/// Signature for when a [WebView] has failed to load a resource. | ||
typedef void ReceivedErrorCallback(String errorCode, String description); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When reading this my gut was that we should have an error class though I'm not finding good arguments any way 😄 (slight pro of an object is that it's easier for users to pass the error information around within their app)
I wonder if you had a reason to prefer not introducing an error class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was in favor of a data class as well. I chose not to create one to be consistent with the style of the WebViewPlatformCallbacksHandler
. Method
void onJavaScriptChannelMessage(String channel, String message);
and
FutureOr<bool> onNavigationRequest({String url, bool isForMainFrame});
don't use them either.
However, since I need more than 2 parameters now, I created a WebResourceError
class.
this.gestureRecognizers, | ||
this.onPageStarted, | ||
this.onPageFinished, | ||
this.onReceivedError, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another nit: why onReceivedError and not onError/onResourceLoadError?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was the name of the method in WebViewClient
. Same as onPageStarted
and onPageFinished
. It was mostly to keep the pattern of method name origins, but I think WebResourceError
is more expressive. (or something similar)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM after addressing remaining comments
} | ||
|
||
final String message = | ||
String.format(Locale.getDefault(), "Could not find a string for errorCode: %d", errorCode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, my read of https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax is that %d
formatting is not affected by the locale.
expect(currentUrl, 'https://www.google.com/'); | ||
}); | ||
|
||
testWidgets('onReceivedError', (WidgetTester tester) async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: onWebResourceError
if (Platform.isAndroid) expect(error.errorType, isNotNull); | ||
}); | ||
|
||
testWidgets('onReceivedError is not called with valid url', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
javaScriptResultTypeIsUnsupported, | ||
} | ||
|
||
/// On Android, the error code will be a constant from |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class comment probably needs an update as well?
/// for more information on error handling on iOS. | ||
final String domain; | ||
|
||
/// Describes the error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style guide says avoid useless documentation
|
||
/// The type of error. | ||
/// | ||
/// This is will never be null on Android, but can be null on iOS. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: s/is//
? null | ||
: WebResourceErrorType.values.firstWhere( | ||
(WebResourceErrorType type) { | ||
final String enumName = type.toString().replaceFirst( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, may be easier to follow as:
return type.toString() == '$WebResourceErrorType.${call.arguments['errorType']}';
Don't forget to add a version bump and a changelog entry |
This reverts commit 8819b21. # Conflicts: # packages/webview_flutter/CHANGELOG.md # packages/webview_flutter/pubspec.yaml
Description
This adds the feature where the webview can report an error when loading page resources.
After looking for error reporting in the
Webview
implementation of each platform I found Android uses onReceivedError in itsWebviewClient
and iOS uses webView:didFailNavigation:withError: and webView:didFailProvisionalNavigation:withError: in itsWKNavigationDelegate
.However, each platform handles error codes differently. Android provides a
WebResourceError
which has anint
code that is defined as a constant inWebViewClient
. iOS uses a genericNSError
and doesn't specify the possible values for the error code.Related Issues
Fixes flutter/flutter#53023
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.///
).flutter analyze
) does not report any problems on my PR.Breaking Change
Does your PR require plugin users to manually update their apps to accommodate your change?