Skip to content

Commit

Permalink
[webview_flutter_android][webview_flutter_wkwebview] Adds platform im…
Browse files Browse the repository at this point in the history
…plementations for onHttpError (#6149)

Copy of #3695 since it doesn't contain permission to edit from contributors.

Part of flutter/flutter#39502

Full PR #3278
  • Loading branch information
bparrishMines authored Mar 14, 2024
1 parent e8ab632 commit 92a8b7a
Show file tree
Hide file tree
Showing 50 changed files with 2,196 additions and 1,092 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## NEXT
## 3.16.0

* Adds onReceivedHttpError WebViewClient callback to support
`PlatformNavigationDelegate.onHttpError`.
* Updates minimum supported SDK version to Flutter 3.13/Dart 3.1.
* Updates compileSdk to 34.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,58 @@ ArrayList<Object> toList() {
}
}

/** Generated class from Pigeon that represents data sent in messages. */
public static final class WebResourceResponseData {
private @NonNull Long statusCode;

public @NonNull Long getStatusCode() {
return statusCode;
}

public void setStatusCode(@NonNull Long setterArg) {
if (setterArg == null) {
throw new IllegalStateException("Nonnull field \"statusCode\" is null.");
}
this.statusCode = setterArg;
}

/** Constructor is non-public to enforce null safety; use Builder. */
WebResourceResponseData() {}

public static final class Builder {

private @Nullable Long statusCode;

public @NonNull Builder setStatusCode(@NonNull Long setterArg) {
this.statusCode = setterArg;
return this;
}

public @NonNull WebResourceResponseData build() {
WebResourceResponseData pigeonReturn = new WebResourceResponseData();
pigeonReturn.setStatusCode(statusCode);
return pigeonReturn;
}
}

@NonNull
ArrayList<Object> toList() {
ArrayList<Object> toListResult = new ArrayList<Object>(1);
toListResult.add(statusCode);
return toListResult;
}

static @NonNull WebResourceResponseData fromList(@NonNull ArrayList<Object> list) {
WebResourceResponseData pigeonResult = new WebResourceResponseData();
Object statusCode = list.get(0);
pigeonResult.setStatusCode(
(statusCode == null)
? null
: ((statusCode instanceof Integer) ? (Integer) statusCode : (Long) statusCode));
return pigeonResult;
}
}

/** Generated class from Pigeon that represents data sent in messages. */
public static final class WebResourceErrorData {
private @NonNull Long errorCode;
Expand Down Expand Up @@ -2388,6 +2440,8 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) {
return WebResourceErrorData.fromList((ArrayList<Object>) readValue(buffer));
case (byte) 129:
return WebResourceRequestData.fromList((ArrayList<Object>) readValue(buffer));
case (byte) 130:
return WebResourceResponseData.fromList((ArrayList<Object>) readValue(buffer));
default:
return super.readValueOfType(type, buffer);
}
Expand All @@ -2401,6 +2455,9 @@ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) {
} else if (value instanceof WebResourceRequestData) {
stream.write(129);
writeValue(stream, ((WebResourceRequestData) value).toList());
} else if (value instanceof WebResourceResponseData) {
stream.write(130);
writeValue(stream, ((WebResourceResponseData) value).toList());
} else {
super.writeValue(stream, value);
}
Expand Down Expand Up @@ -2455,6 +2512,23 @@ public void onPageFinished(
channelReply -> callback.reply(null));
}

public void onReceivedHttpError(
@NonNull Long instanceIdArg,
@NonNull Long webViewInstanceIdArg,
@NonNull WebResourceRequestData requestArg,
@NonNull WebResourceResponseData responseArg,
@NonNull Reply<Void> callback) {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.webview_flutter_android.WebViewClientFlutterApi.onReceivedHttpError",
getCodec());
channel.send(
new ArrayList<Object>(
Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg, responseArg)),
channelReply -> callback.reply(null));
}

public void onReceivedRequestError(
@NonNull Long instanceIdArg,
@NonNull Long webViewInstanceIdArg,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.webkit.HttpAuthHandler;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
Expand Down Expand Up @@ -70,6 +71,16 @@ static GeneratedAndroidWebView.WebResourceRequestData createWebResourceRequestDa
return requestData.build();
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
static GeneratedAndroidWebView.WebResourceResponseData createWebResourceResponseData(
WebResourceResponse response) {
final GeneratedAndroidWebView.WebResourceResponseData.Builder responseData =
new GeneratedAndroidWebView.WebResourceResponseData.Builder()
.setStatusCode((long) response.getStatusCode());

return responseData.build();
}

/**
* Creates a Flutter api that sends messages to Dart.
*
Expand Down Expand Up @@ -110,6 +121,25 @@ public void onPageFinished(
onPageFinished(getIdentifierForClient(webViewClient), webViewIdentifier, urlArg, callback);
}

/** Passes arguments from {@link WebViewClient#onReceivedHttpError} to Dart. */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void onReceivedHttpError(
@NonNull WebViewClient webViewClient,
@NonNull WebView webView,
@NonNull WebResourceRequest request,
@NonNull WebResourceResponse response,
@NonNull Reply<Void> callback) {
webViewFlutterApi.create(webView, reply -> {});

final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView);
onReceivedHttpError(
getIdentifierForClient(webViewClient),
webViewIdentifier,
createWebResourceRequestData(request),
createWebResourceResponseData(response),
callback);
}

/**
* Passes arguments from {@link WebViewClient#onReceivedError(WebView, WebResourceRequest,
* WebResourceError)} to Dart.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import android.webkit.HttpAuthHandler;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
Expand Down Expand Up @@ -55,6 +56,14 @@ public void onPageFinished(@NonNull WebView view, @NonNull String url) {
flutterApi.onPageFinished(this, view, url, reply -> {});
}

@Override
public void onReceivedHttpError(
@NonNull WebView view,
@NonNull WebResourceRequest request,
@NonNull WebResourceResponse response) {
flutterApi.onReceivedHttpError(this, view, request, response, reply -> {});
}

@Override
public void onReceivedError(
@NonNull WebView view,
Expand Down Expand Up @@ -140,6 +149,15 @@ public void onPageFinished(@NonNull WebView view, @NonNull String url) {
flutterApi.onPageFinished(this, view, url, reply -> {});
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onReceivedHttpError(
@NonNull WebView view,
@NonNull WebResourceRequest request,
@NonNull WebResourceResponse response) {
flutterApi.onReceivedHttpError(this, view, request, response, reply -> {});
}

// This method is only called when the WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR feature is
// enabled. The deprecated method is called when a device doesn't support this.
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import android.net.Uri;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
Expand Down Expand Up @@ -136,4 +137,28 @@ public void doUpdateVisitedHistory() {
.doUpdateVisitedHistory(
eq(webViewClient), eq(mockWebView), eq("https://www.google.com"), eq(true), any());
}

@Test
public void onReceivedHttpError() {
final Uri mockUri = mock(Uri.class);
when(mockUri.toString()).thenReturn("");

final WebResourceRequest mockRequest = mock(WebResourceRequest.class);
when(mockRequest.getMethod()).thenReturn("method");
when(mockRequest.getUrl()).thenReturn(mockUri);
when(mockRequest.isForMainFrame()).thenReturn(true);
when(mockRequest.getRequestHeaders()).thenReturn(null);

final WebResourceResponse mockResponse = mock(WebResourceResponse.class);
when(mockResponse.getStatusCode()).thenReturn(404);

webViewClient.onReceivedHttpError(mockWebView, mockRequest, mockResponse);
verify(mockFlutterApi)
.onReceivedHttpError(
eq(webViewClient),
eq(mockWebView),
any(WebResourceRequest.class),
any(WebResourceResponse.class),
any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,81 @@ Future<void> main() async {
await pageFinishCompleter.future;
});

testWidgets('onHttpError', (WidgetTester tester) async {
final Completer<HttpResponseError> errorCompleter =
Completer<HttpResponseError>();

final PlatformWebViewController controller = PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
);
unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted));
final PlatformNavigationDelegate delegate = PlatformNavigationDelegate(
const PlatformNavigationDelegateCreationParams(),
);
unawaited(delegate.setOnHttpError((HttpResponseError error) {
errorCompleter.complete(error);
}));
unawaited(controller.setPlatformNavigationDelegate(delegate));
unawaited(controller.loadRequest(
LoadRequestParams(uri: Uri.parse('$prefixUrl/favicon.ico')),
));

await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

final HttpResponseError error = await errorCompleter.future;

expect(error, isNotNull);
expect(error.response?.statusCode, 404);
});

testWidgets('onHttpError is not called when no HTTP error is received',
(WidgetTester tester) async {
const String testPage = '''
<!DOCTYPE html><html>
</head>
<body>
</body>
</html>
''';

final Completer<HttpResponseError> errorCompleter =
Completer<HttpResponseError>();
final Completer<void> pageFinishCompleter = Completer<void>();

final PlatformWebViewController controller = PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
);
unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted));
final PlatformNavigationDelegate delegate = PlatformNavigationDelegate(
const PlatformNavigationDelegateCreationParams(),
);
unawaited(delegate.setOnHttpError((HttpResponseError error) {
errorCompleter.complete(error);
}));
unawaited(delegate.setOnPageFinished(
(_) => pageFinishCompleter.complete(),
));
unawaited(controller.setPlatformNavigationDelegate(delegate));
unawaited(controller.loadHtmlString(testPage));

await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

expect(errorCompleter.future, doesNotComplete);
await pageFinishCompleter.future;
});

testWidgets('can block requests', (WidgetTester tester) async {
Completer<void> pageLoaded = Completer<void>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ class _WebViewExampleState extends State<WebViewExample> {
..setOnPageFinished((String url) {
debugPrint('Page finished loading: $url');
})
..setOnHttpError((HttpResponseError error) {
debugPrint(
'HTTP error occured on page: ${error.response?.statusCode}',
);
})
..setOnWebResourceError((WebResourceError error) {
debugPrint('''
Page resource error:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ class AndroidWebViewProxy {
final android_webview.WebViewClient Function({
void Function(android_webview.WebView webView, String url)? onPageStarted,
void Function(android_webview.WebView webView, String url)? onPageFinished,
void Function(
android_webview.WebView webView,
android_webview.WebResourceRequest request,
android_webview.WebResourceResponse response,
)? onReceivedHttpError,
void Function(
android_webview.WebView webView,
android_webview.WebResourceRequest request,
Expand Down
Loading

0 comments on commit 92a8b7a

Please sign in to comment.