Skip to content

Commit 0f0dcbf

Browse files
authored
[webview_flutter] Implement loadRequest in Android package. (flutter#4563)
Implements the `loadRequest` method added in flutter#4450 for the Android package. Related issue: - flutter#27730
1 parent 3ce611e commit 0f0dcbf

File tree

16 files changed

+335
-59
lines changed

16 files changed

+335
-59
lines changed

packages/webview_flutter/webview_flutter_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.7.0
2+
3+
* Adds support for the `loadRequest` method from the platform interface.
4+
15
## 2.6.0
26

37
* Adds implementation of the `loadFlutterAsset` method from the platform interface.

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ void loadDataWithBaseUrl(
186186

187187
void loadUrl(Long instanceId, String url, Map<String, String> headers);
188188

189+
void postUrl(Long instanceId, String url, byte[] data);
190+
189191
String getUrl(Long instanceId);
190192

191193
Boolean canGoBack(Long instanceId);
@@ -410,6 +412,39 @@ static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) {
410412
channel.setMessageHandler(null);
411413
}
412414
}
415+
{
416+
BasicMessageChannel<Object> channel =
417+
new BasicMessageChannel<>(
418+
binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.postUrl", getCodec());
419+
if (api != null) {
420+
channel.setMessageHandler(
421+
(message, reply) -> {
422+
Map<String, Object> wrapped = new HashMap<>();
423+
try {
424+
ArrayList<Object> args = (ArrayList<Object>) message;
425+
Number instanceIdArg = (Number) args.get(0);
426+
if (instanceIdArg == null) {
427+
throw new NullPointerException("instanceIdArg unexpectedly null.");
428+
}
429+
String urlArg = (String) args.get(1);
430+
if (urlArg == null) {
431+
throw new NullPointerException("urlArg unexpectedly null.");
432+
}
433+
byte[] dataArg = (byte[]) args.get(2);
434+
if (dataArg == null) {
435+
throw new NullPointerException("dataArg unexpectedly null.");
436+
}
437+
api.postUrl(instanceIdArg.longValue(), urlArg, dataArg);
438+
wrapped.put("result", null);
439+
} catch (Error | RuntimeException exception) {
440+
wrapped.put("error", wrapError(exception));
441+
}
442+
reply.reply(wrapped);
443+
});
444+
} else {
445+
channel.setMessageHandler(null);
446+
}
447+
}
413448
{
414449
BasicMessageChannel<Object> channel =
415450
new BasicMessageChannel<>(

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,12 @@ public void loadUrl(Long instanceId, String url, Map<String, String> headers) {
382382
webView.loadUrl(url, headers);
383383
}
384384

385+
@Override
386+
public void postUrl(Long instanceId, String url, byte[] data) {
387+
final WebView webView = (WebView) instanceManager.getInstance(instanceId);
388+
webView.postUrl(url, data);
389+
}
390+
385391
@Override
386392
public String getUrl(Long instanceId) {
387393
final WebView webView = (WebView) instanceManager.getInstance(instanceId);

packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@ public void loadUrl() {
208208
verify(mockWebView).loadUrl("https://www.google.com", new HashMap<>());
209209
}
210210

211+
@Test
212+
public void postUrl() {
213+
testHostApiImpl.postUrl(0L, "https://www.google.com", new byte[] {0x01, 0x02});
214+
verify(mockWebView).postUrl("https://www.google.com", new byte[] {0x01, 0x02});
215+
}
216+
211217
@Test
212218
public void getUrl() {
213219
when(mockWebView.getUrl()).thenReturn("https://www.google.com");

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import 'dart:async';
88
import 'dart:convert';
99
import 'dart:io';
10+
import 'dart:typed_data';
1011
import 'package:flutter/foundation.dart';
1112
import 'package:flutter/material.dart';
1213
import 'package:flutter_driver/driver_extension.dart';
@@ -189,6 +190,7 @@ enum _MenuOptions {
189190
loadLocalFile,
190191
loadHtmlString,
191192
transparentBackground,
193+
doPostRequest,
192194
}
193195

194196
class _SampleMenu extends StatelessWidget {
@@ -239,6 +241,9 @@ class _SampleMenu extends StatelessWidget {
239241
case _MenuOptions.transparentBackground:
240242
_onTransparentBackground(controller.data!, context);
241243
break;
244+
case _MenuOptions.doPostRequest:
245+
_onDoPostRequest(controller.data!, context);
246+
break;
242247
}
243248
},
244249
itemBuilder: (BuildContext context) => <PopupMenuItem<_MenuOptions>>[
@@ -288,6 +293,10 @@ class _SampleMenu extends StatelessWidget {
288293
value: _MenuOptions.transparentBackground,
289294
child: Text('Transparent background example'),
290295
),
296+
const PopupMenuItem<_MenuOptions>(
297+
value: _MenuOptions.doPostRequest,
298+
child: Text('Post Request'),
299+
),
291300
],
292301
);
293302
},
@@ -382,6 +391,16 @@ class _SampleMenu extends StatelessWidget {
382391
await controller.loadHtmlString(kExamplePage);
383392
}
384393

394+
Future<void> _onDoPostRequest(
395+
WebViewController controller, BuildContext context) async {
396+
final WebViewRequest request = WebViewRequest(
397+
uri: Uri.parse('https://httpbin.org/post'),
398+
method: WebViewRequestMethod.post,
399+
body: Uint8List.fromList('Test Body'.codeUnits),
400+
);
401+
await controller.loadRequest(request);
402+
}
403+
385404
Widget _getCookieList(String cookies) {
386405
if (cookies == null || cookies == '""') {
387406
return Container();

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,11 @@ class WebViewController {
418418
return _webViewPlatformController.loadUrl(url, headers);
419419
}
420420

421+
/// Loads a page by making the specified request.
422+
Future<void> loadRequest(WebViewRequest request) async {
423+
return _webViewPlatformController.loadRequest(request);
424+
}
425+
421426
/// Accessor to the current URL that the WebView is displaying.
422427
///
423428
/// If [WebView.initialUrl] was never specified, returns `null`.

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:typed_data';
56
import 'dart:ui';
67

78
import 'package:flutter/foundation.dart';
@@ -169,6 +170,13 @@ class WebView {
169170
return api.loadUrlFromInstance(this, url, headers);
170171
}
171172

173+
/// Loads the URL with postData using "POST" method into this WebView.
174+
///
175+
/// If url is not a network URL, it will be loaded with [loadUrl] instead, ignoring the postData param.
176+
Future<void> postUrl(String url, Uint8List data) {
177+
return api.postUrlFromInstance(this, url, data);
178+
}
179+
172180
/// Gets the URL for the current page.
173181
///
174182
/// This is not always the same as the URL passed to

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,33 @@ class WebViewHostApi {
220220
}
221221
}
222222

223+
Future<void> postUrl(
224+
int arg_instanceId, String arg_url, Uint8List arg_data) async {
225+
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
226+
'dev.flutter.pigeon.WebViewHostApi.postUrl', codec,
227+
binaryMessenger: _binaryMessenger);
228+
final Map<Object?, Object?>? replyMap =
229+
await channel.send(<Object>[arg_instanceId, arg_url, arg_data])
230+
as Map<Object?, Object?>?;
231+
if (replyMap == null) {
232+
throw PlatformException(
233+
code: 'channel-error',
234+
message: 'Unable to establish connection on channel.',
235+
details: null,
236+
);
237+
} else if (replyMap['error'] != null) {
238+
final Map<Object?, Object?> error =
239+
(replyMap['error'] as Map<Object?, Object?>?)!;
240+
throw PlatformException(
241+
code: (error['code'] as String?)!,
242+
message: error['message'] as String?,
243+
details: error['details'],
244+
);
245+
} else {
246+
return;
247+
}
248+
}
249+
223250
Future<String> getUrl(int arg_instanceId) async {
224251
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
225252
'dev.flutter.pigeon.WebViewHostApi.getUrl', codec,

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:typed_data';
6+
57
import 'package:flutter/services.dart';
68

79
import 'android_webview.dart';
@@ -152,6 +154,15 @@ class WebViewHostApiImpl extends WebViewHostApi {
152154
return loadUrl(instanceManager.getInstanceId(instance)!, url, headers);
153155
}
154156

157+
/// Helper method to convert instances ids to objects.
158+
Future<void> postUrlFromInstance(
159+
WebView instance,
160+
String url,
161+
Uint8List data,
162+
) {
163+
return postUrl(instanceManager.getInstanceId(instance)!, url, data);
164+
}
165+
155166
/// Helper method to convert instances ids to objects.
156167
Future<String> getUrlFromInstance(WebView instance) {
157168
return getUrl(instanceManager.getInstanceId(instance)!);

packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
import 'dart:async';
6+
import 'dart:typed_data';
67

78
import 'package:flutter/widgets.dart';
89
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
@@ -210,6 +211,28 @@ class WebViewAndroidPlatformController extends WebViewPlatformController {
210211
return webView.loadUrl(url, headers ?? <String, String>{});
211212
}
212213

214+
/// When making a POST request, headers are ignored. As a workaround, make
215+
/// the request manually and load the response data using [loadHTMLString].
216+
@override
217+
Future<void> loadRequest(
218+
WebViewRequest request,
219+
) async {
220+
if (!request.uri.hasScheme) {
221+
throw ArgumentError('WebViewRequest#uri is required to have a scheme.');
222+
}
223+
switch (request.method) {
224+
case WebViewRequestMethod.get:
225+
return webView.loadUrl(request.uri.toString(), request.headers);
226+
case WebViewRequestMethod.post:
227+
return webView.postUrl(
228+
request.uri.toString(), request.body ?? Uint8List(0));
229+
default:
230+
throw UnimplementedError(
231+
'This version of webview_android_widget currently has no implementation for HTTP method ${request.method.serialize()} in loadRequest.',
232+
);
233+
}
234+
}
235+
213236
@override
214237
Future<String?> currentUrl() => webView.getUrl();
215238

packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ abstract class WebViewHostApi {
4646
Map<String, String> headers,
4747
);
4848

49+
void postUrl(
50+
int instanceId,
51+
String url,
52+
Uint8List data,
53+
);
54+
4955
String getUrl(int instanceId);
5056

5157
bool canGoBack(int instanceId);

packages/webview_flutter/webview_flutter_android/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter_android
22
description: A Flutter plugin that provides a WebView widget on Android.
33
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 2.6.0
5+
version: 2.7.0
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"

packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ abstract class TestWebViewHostApi {
2727
void loadDataWithBaseUrl(int instanceId, String baseUrl, String data,
2828
String mimeType, String encoding, String historyUrl);
2929
void loadUrl(int instanceId, String url, Map<String?, String?> headers);
30+
void postUrl(int instanceId, String url, Uint8List data);
3031
String getUrl(int instanceId);
3132
bool canGoBack(int instanceId);
3233
bool canGoForward(int instanceId);
@@ -180,6 +181,31 @@ abstract class TestWebViewHostApi {
180181
});
181182
}
182183
}
184+
{
185+
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
186+
'dev.flutter.pigeon.WebViewHostApi.postUrl', codec,
187+
binaryMessenger: binaryMessenger);
188+
if (api == null) {
189+
channel.setMockMessageHandler(null);
190+
} else {
191+
channel.setMockMessageHandler((Object? message) async {
192+
assert(message != null,
193+
'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null.');
194+
final List<Object?> args = (message as List<Object?>?)!;
195+
final int? arg_instanceId = (args[0] as int?);
196+
assert(arg_instanceId != null,
197+
'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null int.');
198+
final String? arg_url = (args[1] as String?);
199+
assert(arg_url != null,
200+
'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null String.');
201+
final Uint8List? arg_data = (args[2] as Uint8List?);
202+
assert(arg_data != null,
203+
'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null Uint8List.');
204+
api.postUrl(arg_instanceId!, arg_url!, arg_data!);
205+
return <Object?, Object?>{};
206+
});
207+
}
208+
}
183209
{
184210
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
185211
'dev.flutter.pigeon.WebViewHostApi.getUrl', codec,

0 commit comments

Comments
 (0)