Skip to content

Commit 3fb8d80

Browse files
committed
Refactor auth to pass handler object to Dart
1 parent 0a8b8ce commit 3fb8d80

26 files changed

+1493
-1649
lines changed

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java

Lines changed: 462 additions & 650 deletions
Large diffs are not rendered by default.
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+
package io.flutter.plugins.webviewflutter;
6+
7+
import android.webkit.HttpAuthHandler;
8+
import androidx.annotation.NonNull;
9+
import io.flutter.plugin.common.BinaryMessenger;
10+
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.HttpAuthHandlerFlutterApi;
11+
12+
/**
13+
* Flutter API implementation for {@link HttpAuthHandler}.
14+
*
15+
* <p>This class may handle adding native instances that are attached to a Dart instance or passing
16+
* arguments of callbacks methods to a Dart instance.
17+
*/
18+
public class HttpAuthHandlerFlutterApiImpl {
19+
// To ease adding additional methods, this value is added prematurely.
20+
@SuppressWarnings({"unused", "FieldCanBeLocal"})
21+
private final BinaryMessenger binaryMessenger;
22+
23+
private final InstanceManager instanceManager;
24+
25+
private final HttpAuthHandlerFlutterApi api;
26+
27+
/**
28+
* Constructs a {@link HttpAuthHandlerFlutterApiImpl}.
29+
*
30+
* @param binaryMessenger used to communicate with Dart over asynchronous messages
31+
* @param instanceManager maintains instances stored to communicate with attached Dart objects
32+
*/
33+
public HttpAuthHandlerFlutterApiImpl(
34+
@NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) {
35+
this.binaryMessenger = binaryMessenger;
36+
this.instanceManager = instanceManager;
37+
api = new HttpAuthHandlerFlutterApi(binaryMessenger);
38+
}
39+
40+
/**
41+
* Stores the `HttpAuthHandler` instance and notifies Dart to create and store a new
42+
* `HttpAuthHandler` instance that is attached to this one. If `instance` has already been added,
43+
* this method does nothing.
44+
*/
45+
public void create(
46+
@NonNull HttpAuthHandler instance, @NonNull HttpAuthHandlerFlutterApi.Reply<Void> callback) {
47+
if (!instanceManager.containsInstance(instance)) {
48+
api.create(instanceManager.addHostCreatedInstance(instance), callback);
49+
}
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
package io.flutter.plugins.webviewflutter;
6+
7+
import android.webkit.HttpAuthHandler;
8+
import androidx.annotation.NonNull;
9+
import io.flutter.plugin.common.BinaryMessenger;
10+
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.HttpAuthHandlerHostApi;
11+
import java.util.Objects;
12+
13+
/**
14+
* Host api implementation for {@link HttpAuthHandler}.
15+
*
16+
* <p>Handles creating {@link HttpAuthHandler}s that intercommunicate with a paired Dart object.
17+
*/
18+
public class HttpAuthHandlerHostApiImpl implements HttpAuthHandlerHostApi {
19+
// To ease adding additional methods, this value is added prematurely.
20+
@SuppressWarnings({"unused", "FieldCanBeLocal"})
21+
private final BinaryMessenger binaryMessenger;
22+
23+
private final InstanceManager instanceManager;
24+
25+
/**
26+
* Constructs a {@link HttpAuthHandlerHostApiImpl}.
27+
*
28+
* @param binaryMessenger used to communicate with Dart over asynchronous messages
29+
* @param instanceManager maintains instances stored to communicate with attached Dart objects
30+
*/
31+
public HttpAuthHandlerHostApiImpl(
32+
@NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) {
33+
this.binaryMessenger = binaryMessenger;
34+
this.instanceManager = instanceManager;
35+
}
36+
37+
@NonNull
38+
@Override
39+
public Boolean useHttpAuthUsernamePassword(@NonNull Long instanceId) {
40+
return getHttpAuthHandlerInstance(instanceId).useHttpAuthUsernamePassword();
41+
}
42+
43+
@Override
44+
public void cancel(@NonNull Long instanceId) {
45+
getHttpAuthHandlerInstance(instanceId).cancel();
46+
}
47+
48+
@Override
49+
public void proceed(
50+
@NonNull Long instanceId, @NonNull String username, @NonNull String password) {
51+
getHttpAuthHandlerInstance(instanceId).proceed(username, password);
52+
}
53+
54+
private HttpAuthHandler getHttpAuthHandlerInstance(@NonNull Long instanceId) {
55+
return Objects.requireNonNull(instanceManager.getInstance(instanceId));
56+
}
57+
}

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import android.webkit.WebView;
1313
import android.webkit.WebViewClient;
1414
import androidx.annotation.NonNull;
15-
import androidx.annotation.Nullable;
1615
import androidx.annotation.RequiresApi;
1716
import androidx.webkit.WebResourceErrorCompat;
1817
import io.flutter.plugin.common.BinaryMessenger;
@@ -236,16 +235,20 @@ public void doUpdateVisitedHistory(
236235
public void onReceivedHttpAuthRequest(
237236
@NonNull WebViewClient webViewClient,
238237
@NonNull WebView webview,
239-
@Nullable HttpAuthHandler handler,
238+
@NonNull HttpAuthHandler httpAuthHandler,
240239
@NonNull String host,
241240
@NonNull String realm,
242241
@NonNull Reply<Void> callback) {
243-
webViewFlutterApi.create(webview, reply -> {});
244-
final Long webViewIdentifier =
245-
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webview));
242+
new HttpAuthHandlerFlutterApiImpl(binaryMessenger, instanceManager)
243+
.create(httpAuthHandler, reply -> {});
246244

247245
onReceivedHttpAuthRequest(
248-
getIdentifierForClient(webViewClient), webViewIdentifier, host, realm, callback);
246+
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webViewClient)),
247+
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webview)),
248+
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(httpAuthHandler)),
249+
host,
250+
realm,
251+
callback);
249252
}
250253

251254
private long getIdentifierForClient(WebViewClient webViewClient) {

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ public class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebView
3030
private final WebViewClientCreator webViewClientCreator;
3131
private final WebViewClientFlutterApiImpl flutterApi;
3232

33-
static HttpAuthHandler httpAuthHandler;
34-
3533
/** Implementation of {@link WebViewClient} that passes arguments of callback methods to Dart. */
3634
@RequiresApi(Build.VERSION_CODES.N)
3735
public static class WebViewClientImpl extends WebViewClient {
@@ -41,7 +39,7 @@ public static class WebViewClientImpl extends WebViewClient {
4139
/**
4240
* Creates a {@link WebViewClient} that passes arguments of callbacks methods to Dart.
4341
*
44-
* @param flutterApi handles sending messages to Dart
42+
* @param flutterApi handles sending messages to Dart.
4543
*/
4644
public WebViewClientImpl(@NonNull WebViewClientFlutterApiImpl flutterApi) {
4745
this.flutterApi = flutterApi;
@@ -100,8 +98,10 @@ public void doUpdateVisitedHistory(
10098

10199
@Override
102100
public void onReceivedHttpAuthRequest(
103-
@NonNull WebView view, HttpAuthHandler handler, String host, String realm) {
104-
httpAuthHandler = handler;
101+
@NonNull WebView view,
102+
@NonNull HttpAuthHandler handler,
103+
@NonNull String host,
104+
@NonNull String realm) {
105105
flutterApi.onReceivedHttpAuthRequest(this, view, handler, host, realm, reply -> {});
106106
}
107107

@@ -272,18 +272,4 @@ public void setSynchronousReturnValueForShouldOverrideUrlLoading(
272272
"This WebViewClient doesn't support setting the returnValueForShouldOverrideUrlLoading.");
273273
}
274274
}
275-
276-
@Override
277-
public void setAuthCredentials(
278-
@NonNull Long instanceId,
279-
@NonNull String host,
280-
@NonNull String realm,
281-
@NonNull String username,
282-
@NonNull String password,
283-
@NonNull GeneratedAndroidWebView.Result<Void> callBack) {
284-
WebView webView = Objects.requireNonNull(instanceManager.getInstance(instanceId));
285-
286-
httpAuthHandler.proceed(username, password);
287-
callBack.success(null);
288-
}
289275
}

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi;
1919
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.FlutterAssetManagerHostApi;
2020
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.GeolocationPermissionsCallbackHostApi;
21+
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.HttpAuthHandlerHostApi;
2122
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.InstanceManagerHostApi;
2223
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaObjectHostApi;
2324
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi;
@@ -141,6 +142,8 @@ private void setUp(
141142
GeolocationPermissionsCallbackHostApi.setup(
142143
binaryMessenger,
143144
new GeolocationPermissionsCallbackHostApiImpl(binaryMessenger, instanceManager));
145+
HttpAuthHandlerHostApi.setup(
146+
binaryMessenger, new HttpAuthHandlerHostApiImpl(binaryMessenger, instanceManager));
144147
}
145148

146149
@Override

packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ Future<void> main() async {
7979

8080
final Completer<String> hostCompleter = Completer<String>();
8181
final Completer<String> realmCompleter = Completer<String>();
82+
final Completer<void Function(String, String)> onProceedCompleter =
83+
Completer<void Function(String, String)>();
8284
final Completer<void> pageFinishedCompleter = Completer<void>();
8385

8486
final PlatformWebViewController controller = PlatformWebViewController(
@@ -87,9 +89,10 @@ Future<void> main() async {
8789
..setPlatformNavigationDelegate(PlatformNavigationDelegate(
8890
const PlatformNavigationDelegateCreationParams(),
8991
)
90-
..setOnReceiveHttpAuthRequest((String h, String r) {
91-
hostCompleter.complete(h);
92-
realmCompleter.complete(r);
92+
..setOnHttpAuthRequest((HttpAuthRequest request) {
93+
hostCompleter.complete(request.host);
94+
realmCompleter.complete(request.realm);
95+
onProceedCompleter.complete(request.onProceed);
9396
})
9497
..setOnPageFinished((_) => pageFinishedCompleter.complete()))
9598
..setJavaScriptMode(JavaScriptMode.unrestricted)
@@ -110,7 +113,9 @@ Future<void> main() async {
110113
expect(host, equals('jigsaw.w3.org'));
111114
expect(realm, equals('test'));
112115

113-
await controller.setHttpAuthCredentials(host, realm, username, password);
116+
final void Function(String, String) onProceed =
117+
await onProceedCompleter.future;
118+
onProceed(username, password);
114119
await pageFinishedCompleter.future;
115120

116121
final String content = await controller.runJavaScriptReturningResult(

packages/webview_flutter/webview_flutter_android/example/lib/main.dart

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,12 @@ class _WebViewExampleState extends State<WebViewExample> {
8787
late TextEditingController usernameTextController;
8888
late TextEditingController passwordTextController;
8989

90-
Future<dynamic> openDialog(String host, String realm) async {
90+
Future<dynamic> openDialog(HttpAuthRequest httpRequest) async {
9191
await showDialog(
9292
context: context,
9393
builder: (BuildContext context) => AlertDialog(
94-
title: const Text('Authentication'),
94+
title: Text(
95+
'Authentication request from ${httpRequest.host}, ${httpRequest.realm}'),
9596
content: Column(
9697
mainAxisSize: MainAxisSize.min,
9798
children: <Widget>[
@@ -110,11 +111,10 @@ class _WebViewExampleState extends State<WebViewExample> {
110111
actions: <Widget>[
111112
TextButton(
112113
onPressed: () {
113-
_controller.setHttpAuthCredentials(
114-
host,
115-
realm,
116-
usernameTextController.text,
117-
passwordTextController.text);
114+
httpRequest.onProceed(
115+
usernameTextController.text,
116+
passwordTextController.text,
117+
);
118118
Navigator.of(context).pop();
119119
},
120120
child: const Text('Login')),
@@ -156,9 +156,6 @@ Page resource error:
156156
isForMainFrame: ${error.isForMainFrame}
157157
''');
158158
})
159-
..setOnReceiveHttpAuthRequest((String host, String realm) async {
160-
await openDialog(host, realm);
161-
})
162159
..setOnNavigationRequest((NavigationRequest request) {
163160
if (request.url.startsWith('https://www.youtube.com/')) {
164161
debugPrint('blocking navigation to ${request.url}');
@@ -191,7 +188,8 @@ Page resource error:
191188
LoadRequestParams(
192189
uri: Uri.parse('https://flutter.dev'),
193190
),
194-
);
191+
)
192+
..setOnHttpAuthRequest(openDialog);
195193
}
196194

197195
// https://authenticationtest.com/simpleFormAuth/

packages/webview_flutter/webview_flutter_android/lib/src/android_proxy.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,12 @@ class AndroidWebViewProxy {
6868
void Function(android_webview.WebView webView, String url)? urlLoading,
6969
void Function(android_webview.WebView webView, String url, bool isReload)?
7070
doUpdateVisitedHistory,
71-
void Function(android_webview.WebView webView, String host, String realm)?
72-
onReceivedHttpAuthRequest,
71+
void Function(
72+
android_webview.WebView webView,
73+
android_webview.HttpAuthHandler handler,
74+
String host,
75+
String realm,
76+
)? onReceivedHttpAuthRequest,
7377
}) createAndroidWebViewClient;
7478

7579
/// Constructs a [android_webview.FlutterAssetManager].

packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -934,8 +934,12 @@ class WebViewClient extends JavaObject {
934934
doUpdateVisitedHistory;
935935

936936
/// This callback is only called for requests that require HTTP authentication.
937-
final void Function(WebView webView, String host, String realm)?
938-
onReceivedHttpAuthRequest;
937+
final void Function(
938+
WebView webView,
939+
HttpAuthHandler handler,
940+
String host,
941+
String realm,
942+
)? onReceivedHttpAuthRequest;
939943

940944
/// Sets the required synchronous return value for the Java method,
941945
/// `WebViewClient.shouldOverrideUrlLoading(...)`.
@@ -955,18 +959,6 @@ class WebViewClient extends JavaObject {
955959
return api.setShouldOverrideUrlLoadingReturnValueFromInstance(this, value);
956960
}
957961

958-
/// Sets the authentication credentials for the basic authentication request.
959-
static Future<void> setHttpAuthCredentials(
960-
WebView webView,
961-
String host,
962-
String realm,
963-
String username,
964-
String password,
965-
) {
966-
return api.setHttpAuthCredentialsInstance(
967-
webView, host, realm, username, password);
968-
}
969-
970962
@override
971963
WebViewClient copy() {
972964
return WebViewClient.detached(
@@ -1389,3 +1381,32 @@ class WebStorage extends JavaObject {
13891381
);
13901382
}
13911383
}
1384+
1385+
/// Represents a request for HTTP authentication.
1386+
///
1387+
/// Instances of this class are created by the [WebView] and passed to
1388+
/// [WebViewClient.onReceivedHttpAuthRequest]. The host application must call
1389+
/// either [HttpAuthHandler.proceed] or [HttpAuthHandler.cancel] to set the
1390+
/// WebView's response to the request.
1391+
class HttpAuthHandler extends JavaObject {
1392+
/// Constructs a [HttpAuthHandler].
1393+
HttpAuthHandler({
1394+
super.binaryMessenger,
1395+
super.instanceManager,
1396+
}) : super.detached();
1397+
1398+
/// Pigeon Host Api implementation for [HttpAuthHandler].
1399+
@visibleForTesting
1400+
static HttpAuthHandlerHostApiImpl api = HttpAuthHandlerHostApiImpl();
1401+
1402+
/// Instructs the WebView to cancel the authentication request.
1403+
Future<void> cancel() {
1404+
return api.cancelFromInstance(this);
1405+
}
1406+
1407+
/// Instructs the WebView to proceed with the authentication with the provided
1408+
/// credentials.
1409+
Future<void> proceed(String username, String password) {
1410+
return api.proceedFromInstance(this, username, password);
1411+
}
1412+
}

0 commit comments

Comments
 (0)