Skip to content

Commit 6a6c2fc

Browse files
committed
Implementation of the AndroidNavigationDelegate class
1 parent c4b24b7 commit 6a6c2fc

File tree

5 files changed

+1079
-0
lines changed

5 files changed

+1079
-0
lines changed
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:async';
6+
7+
import 'package:flutter/foundation.dart';
8+
import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
9+
10+
import '../android_webview.dart' as android_webview;
11+
import 'types/android_navigation_delegate_creation_params.dart';
12+
import 'types/android_web_resource_error.dart';
13+
14+
/// A place to register callback methods responsible to handle navigation events
15+
/// triggered by the [android_webview.WebView].
16+
class AndroidNavigationDelegate extends PlatformNavigationDelegate {
17+
/// Creates a new [AndroidNavigationkDelegate].
18+
AndroidNavigationDelegate(AndroidNavigationDelegateCreationParams params)
19+
: this.fromNativeApi(
20+
params,
21+
);
22+
23+
/// Creates a new [AndroidNavigationDelegate] using the Android native [android_webview.WebView] implementation.
24+
///
25+
/// This constructor is only used for testing. An instance should be obtained
26+
/// with the default [AndroidNavigationDelegate] constructor.
27+
@visibleForTesting
28+
AndroidNavigationDelegate.fromNativeApi(
29+
AndroidNavigationDelegateCreationParams params,
30+
) : _androidWebViewClient = params.androidWebViewClient,
31+
_androidWebChromeClient = params.androidWebChromeClient,
32+
_loadUrl = params.loadUrl,
33+
super.implementation(params);
34+
35+
final AndroidWebViewClient _androidWebViewClient;
36+
37+
final AndroidWebChromeClient _androidWebChromeClient;
38+
39+
final Future<void> Function(String url, Map<String, String>? headers)?
40+
_loadUrl;
41+
42+
@override
43+
Future<void> setOnNavigationRequest(
44+
FutureOr<bool> Function({required String url, required bool isForMainFrame})
45+
onNavigationRequest,
46+
) async {
47+
_androidWebViewClient.onLoadUrlCallback = _loadUrl;
48+
_androidWebViewClient.onNavigationRequestCallback = onNavigationRequest;
49+
}
50+
51+
@override
52+
Future<void> setOnPageStarted(
53+
void Function(String url) onPageStarted,
54+
) async {
55+
_androidWebViewClient.onPageStartedCallback = onPageStarted;
56+
}
57+
58+
@override
59+
Future<void> setOnPageFinished(
60+
void Function(String url) onPageFinished,
61+
) async {
62+
_androidWebViewClient.onPageFinishedCallback = onPageFinished;
63+
}
64+
65+
@override
66+
Future<void> setOnProgress(
67+
void Function(int progress) onProgress,
68+
) async {
69+
_androidWebChromeClient.onProgress = onProgress;
70+
}
71+
72+
@override
73+
Future<void> setOnWebResourceError(
74+
void Function(WebResourceError error) onWebResourceError,
75+
) async {
76+
_androidWebViewClient.onWebResourceErrorCallback = onWebResourceError;
77+
}
78+
}
79+
80+
/// Receives various navigation requests and errors for [AndroidNavigationDelegate].
81+
class AndroidWebViewClient extends android_webview.WebViewClient {
82+
/// Callback when [android_webview.WebViewClient] receives a callback from [android_webview.WebViewClient.onPageStarted].
83+
void Function(String url)? onPageStartedCallback;
84+
85+
/// Callback when [android_webview.WebViewClient] receives a callback from [android_webview.WebViewClient.onPageFinished].
86+
void Function(String url)? onPageFinishedCallback;
87+
88+
/// Callback when [android_webview.WebViewClient] receives an error callback.
89+
void Function(WebResourceError error)? onWebResourceErrorCallback;
90+
91+
/// Checks whether a navigation request should be approved or disaproved.
92+
FutureOr<bool> Function({
93+
required String url,
94+
required bool isForMainFrame,
95+
})? onNavigationRequestCallback;
96+
97+
/// Callback when a navigation request is approved.
98+
Future<void> Function(String url, Map<String, String>? headers)?
99+
onLoadUrlCallback;
100+
101+
static WebResourceErrorType _errorCodeToErrorType(int errorCode) {
102+
switch (errorCode) {
103+
case android_webview.WebViewClient.errorAuthentication:
104+
return WebResourceErrorType.authentication;
105+
case android_webview.WebViewClient.errorBadUrl:
106+
return WebResourceErrorType.badUrl;
107+
case android_webview.WebViewClient.errorConnect:
108+
return WebResourceErrorType.connect;
109+
case android_webview.WebViewClient.errorFailedSslHandshake:
110+
return WebResourceErrorType.failedSslHandshake;
111+
case android_webview.WebViewClient.errorFile:
112+
return WebResourceErrorType.file;
113+
case android_webview.WebViewClient.errorFileNotFound:
114+
return WebResourceErrorType.fileNotFound;
115+
case android_webview.WebViewClient.errorHostLookup:
116+
return WebResourceErrorType.hostLookup;
117+
case android_webview.WebViewClient.errorIO:
118+
return WebResourceErrorType.io;
119+
case android_webview.WebViewClient.errorProxyAuthentication:
120+
return WebResourceErrorType.proxyAuthentication;
121+
case android_webview.WebViewClient.errorRedirectLoop:
122+
return WebResourceErrorType.redirectLoop;
123+
case android_webview.WebViewClient.errorTimeout:
124+
return WebResourceErrorType.timeout;
125+
case android_webview.WebViewClient.errorTooManyRequests:
126+
return WebResourceErrorType.tooManyRequests;
127+
case android_webview.WebViewClient.errorUnknown:
128+
return WebResourceErrorType.unknown;
129+
case android_webview.WebViewClient.errorUnsafeResource:
130+
return WebResourceErrorType.unsafeResource;
131+
case android_webview.WebViewClient.errorUnsupportedAuthScheme:
132+
return WebResourceErrorType.unsupportedAuthScheme;
133+
case android_webview.WebViewClient.errorUnsupportedScheme:
134+
return WebResourceErrorType.unsupportedScheme;
135+
}
136+
137+
throw ArgumentError(
138+
'Could not find a WebResourceErrorType for errorCode: $errorCode',
139+
);
140+
}
141+
142+
/// Whether this [android_webview.WebViewClient] handles navigation requests.
143+
bool get handlesNavigation =>
144+
onLoadUrlCallback != null && onNavigationRequestCallback != null;
145+
146+
@override
147+
void onPageStarted(android_webview.WebView webView, String url) {
148+
if (onPageStartedCallback != null) {
149+
onPageStartedCallback!(url);
150+
}
151+
}
152+
153+
@override
154+
void onPageFinished(android_webview.WebView webView, String url) {
155+
if (onPageFinishedCallback != null) {
156+
onPageFinishedCallback!(url);
157+
}
158+
}
159+
160+
@override
161+
void onReceivedError(
162+
android_webview.WebView webView,
163+
int errorCode,
164+
String description,
165+
String failingUrl,
166+
) {
167+
if (onWebResourceErrorCallback != null) {
168+
onWebResourceErrorCallback!(AndroidWebResourceError(
169+
errorCode: errorCode,
170+
description: description,
171+
failingUrl: failingUrl,
172+
errorType: _errorCodeToErrorType(errorCode),
173+
));
174+
}
175+
}
176+
177+
@override
178+
void onReceivedRequestError(
179+
android_webview.WebView webView,
180+
android_webview.WebResourceRequest request,
181+
android_webview.WebResourceError error,
182+
) {
183+
if (request.isForMainFrame && onWebResourceErrorCallback != null) {
184+
onWebResourceErrorCallback!(AndroidWebResourceError(
185+
errorCode: error.errorCode,
186+
description: error.description,
187+
failingUrl: request.url,
188+
errorType: _errorCodeToErrorType(error.errorCode),
189+
));
190+
}
191+
}
192+
193+
@override
194+
void urlLoading(
195+
android_webview.WebView webView,
196+
String url,
197+
) {
198+
if (!handlesNavigation) {
199+
return;
200+
}
201+
202+
final FutureOr<bool> returnValue = onNavigationRequestCallback!(
203+
url: url,
204+
isForMainFrame: true,
205+
);
206+
207+
if (returnValue is bool && returnValue) {
208+
onLoadUrlCallback!(url, <String, String>{});
209+
} else if (returnValue is Future<bool>) {
210+
returnValue.then((bool shouldLoadUrl) {
211+
if (shouldLoadUrl) {
212+
onLoadUrlCallback!(url, <String, String>{});
213+
}
214+
});
215+
}
216+
}
217+
218+
@override
219+
void requestLoading(
220+
android_webview.WebView webView,
221+
android_webview.WebResourceRequest request,
222+
) {
223+
if (!handlesNavigation) {
224+
return;
225+
}
226+
227+
final FutureOr<bool> returnValue = onNavigationRequestCallback!(
228+
url: request.url,
229+
isForMainFrame: request.isForMainFrame,
230+
);
231+
232+
if (returnValue is bool && returnValue) {
233+
onLoadUrlCallback!(request.url, <String, String>{});
234+
} else if (returnValue is Future<bool>) {
235+
returnValue.then((bool shouldLoadUrl) {
236+
if (shouldLoadUrl) {
237+
onLoadUrlCallback!(request.url, <String, String>{});
238+
}
239+
});
240+
}
241+
}
242+
}
243+
244+
/// Handles JavaScript dialogs, favicons, titles, and the progress for [WebViewAndroidPlatformController].
245+
class AndroidWebChromeClient extends android_webview.WebChromeClient {
246+
/// Callback when [android_webview.WebChromeClient] receives a callback from [android_webview.WebChromeClient.onProgressChanged].
247+
void Function(int progress)? onProgress;
248+
249+
@override
250+
void onProgressChanged(android_webview.WebView webView, int progress) {
251+
if (onProgress != null) {
252+
onProgress!(progress);
253+
}
254+
}
255+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
import 'package:webview_flutter_android/src/v4/android_navigation_delegate.dart';
7+
import 'package:webview_flutter_platform_interface/v4/src/types/types.dart';
8+
9+
/// Object specifying creation parameters for creating a [AndroidNavigationDelegate].
10+
///
11+
/// When adding additional fields make sure they can be null or have a default
12+
/// value to avoid breaking changes. See [PlatformNavigationDelegateCreationParams] for
13+
/// more information.
14+
@immutable
15+
class AndroidNavigationDelegateCreationParams
16+
extends PlatformNavigationDelegateCreationParams {
17+
/// Creates a new [AndroidNavigationDelegateCreationParams] instance.
18+
const AndroidNavigationDelegateCreationParams._(
19+
// This parameter prevents breaking changes later.
20+
// ignore: avoid_unused_constructor_parameters
21+
PlatformNavigationDelegateCreationParams params, {
22+
required this.androidWebViewClient,
23+
required this.androidWebChromeClient,
24+
this.loadUrl,
25+
}) : super();
26+
27+
/// Creates a [AndroidNavigationDelegateCreationParams] instance based on [PlatformNavigationDelegateCreationParams].
28+
factory AndroidNavigationDelegateCreationParams.fromPlatformNavigationDelegateCreationParams(
29+
PlatformNavigationDelegateCreationParams params, {
30+
required AndroidWebViewClient androidWebViewClient,
31+
required AndroidWebChromeClient androidWebChromeClient,
32+
Future<void> Function(String url, Map<String, String>? headers)? loadUrl,
33+
}) {
34+
return AndroidNavigationDelegateCreationParams._(
35+
params,
36+
androidWebViewClient: androidWebViewClient,
37+
androidWebChromeClient: androidWebChromeClient,
38+
loadUrl: loadUrl,
39+
);
40+
}
41+
42+
/// The [AndroidWebViewClient] exposing navigation events triggered by [android_webview.WebView].
43+
final AndroidWebViewClient androidWebViewClient;
44+
45+
/// The [AndroidWebChromeClient] exposing progress events triggered by [android_webview.WebView].
46+
final AndroidWebChromeClient androidWebChromeClient;
47+
48+
/// Callback responsible for loading the [url] after a navigation request is approved.
49+
final Future<void> Function(String url, Map<String, String>? headers)?
50+
loadUrl;
51+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
6+
7+
/// Error returned in `WebView.onWebResourceError` when a web resource loading error has occurred.
8+
class AndroidWebResourceError extends WebResourceError {
9+
/// Creates a new [AndroidWebResourceError].
10+
const AndroidWebResourceError({
11+
required int errorCode,
12+
required String description,
13+
WebResourceErrorType? errorType,
14+
this.failingUrl,
15+
}) : super(
16+
errorCode: errorCode,
17+
description: description,
18+
errorType: errorType,
19+
);
20+
21+
/// Gets the URL for which the failing resource request was made.
22+
final String? failingUrl;
23+
}

0 commit comments

Comments
 (0)