Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[webview_flutter] Implement loadRequest in Android package. #4563

4 changes: 4 additions & 0 deletions packages/webview_flutter/webview_flutter_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.7.0

* Adds support for the `loadRequest` method from the platform interface.

## 2.6.0

* Adds implementation of the `loadFlutterAsset` method from the platform interface.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ void loadDataWithBaseUrl(

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

void postUrl(Long instanceId, String url, byte[] data);

String getUrl(Long instanceId);

Boolean canGoBack(Long instanceId);
Expand Down Expand Up @@ -410,6 +412,39 @@ static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.postUrl", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
}
String urlArg = (String) args.get(1);
if (urlArg == null) {
throw new NullPointerException("urlArg unexpectedly null.");
}
byte[] dataArg = (byte[]) args.get(2);
if (dataArg == null) {
throw new NullPointerException("dataArg unexpectedly null.");
}
api.postUrl(instanceIdArg.longValue(), urlArg, dataArg);
wrapped.put("result", null);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,12 @@ public void loadUrl(Long instanceId, String url, Map<String, String> headers) {
webView.loadUrl(url, headers);
}

@Override
public void postUrl(Long instanceId, String url, byte[] data) {
final WebView webView = (WebView) instanceManager.getInstance(instanceId);
webView.postUrl(url, data);
}

@Override
public String getUrl(Long instanceId) {
final WebView webView = (WebView) instanceManager.getInstance(instanceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ public void loadUrl() {
verify(mockWebView).loadUrl("https://www.google.com", new HashMap<>());
}

@Test
public void postUrl() {
testHostApiImpl.postUrl(0L, "https://www.google.com", new byte[] {0x01, 0x02});
verify(mockWebView).postUrl("https://www.google.com", new byte[] {0x01, 0x02});
}

@Test
public void getUrl() {
when(mockWebView.getUrl()).thenReturn("https://www.google.com");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_driver/driver_extension.dart';
Expand Down Expand Up @@ -189,6 +190,7 @@ enum _MenuOptions {
loadLocalFile,
loadHtmlString,
transparentBackground,
doPostRequest,
}

class _SampleMenu extends StatelessWidget {
Expand Down Expand Up @@ -239,6 +241,9 @@ class _SampleMenu extends StatelessWidget {
case _MenuOptions.transparentBackground:
_onTransparentBackground(controller.data!, context);
break;
case _MenuOptions.doPostRequest:
_onDoPostRequest(controller.data!, context);
break;
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<_MenuOptions>>[
Expand Down Expand Up @@ -288,6 +293,10 @@ class _SampleMenu extends StatelessWidget {
value: _MenuOptions.transparentBackground,
child: Text('Transparent background example'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.doPostRequest,
child: Text('Post Request'),
),
],
);
},
Expand Down Expand Up @@ -382,6 +391,16 @@ class _SampleMenu extends StatelessWidget {
await controller.loadHtmlString(kExamplePage);
}

Future<void> _onDoPostRequest(
WebViewController controller, BuildContext context) async {
final WebViewRequest request = WebViewRequest(
uri: Uri.parse('https://httpbin.org/post'),
method: WebViewRequestMethod.post,
body: Uint8List.fromList('Test Body'.codeUnits),
);
await controller.loadRequest(request);
}

Widget _getCookieList(String cookies) {
if (cookies == null || cookies == '""') {
return Container();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,11 @@ class WebViewController {
return _webViewPlatformController.loadUrl(url, headers);
}

/// Loads a page by making the specified request.
Future<void> loadRequest(WebViewRequest request) async {
return _webViewPlatformController.loadRequest(request);
}

/// Accessor to the current URL that the WebView is displaying.
///
/// If [WebView.initialUrl] was never specified, returns `null`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:typed_data';
import 'dart:ui';

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

/// Loads the URL with postData using "POST" method into this WebView.
///
/// If url is not a network URL, it will be loaded with [loadUrl] instead, ignoring the postData param.
Future<void> postUrl(String url, Uint8List data) {
return api.postUrlFromInstance(this, url, data);
}

/// Gets the URL for the current page.
///
/// This is not always the same as the URL passed to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,33 @@ class WebViewHostApi {
}
}

Future<void> postUrl(
int arg_instanceId, String arg_url, Uint8List arg_data) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebViewHostApi.postUrl', codec,
binaryMessenger: _binaryMessenger);
final Map<Object?, Object?>? replyMap =
await channel.send(<Object>[arg_instanceId, arg_url, arg_data])
as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
(replyMap['error'] as Map<Object?, Object?>?)!;
throw PlatformException(
code: (error['code'] as String?)!,
message: error['message'] as String?,
details: error['details'],
);
} else {
return;
}
}

Future<String> getUrl(int arg_instanceId) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebViewHostApi.getUrl', codec,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:typed_data';

import 'package:flutter/services.dart';

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

/// Helper method to convert instances ids to objects.
Future<void> postUrlFromInstance(
WebView instance,
String url,
Uint8List data,
) {
return postUrl(instanceManager.getInstanceId(instance)!, url, data);
}

/// Helper method to convert instances ids to objects.
Future<String> getUrlFromInstance(WebView instance) {
return getUrl(instanceManager.getInstanceId(instance)!);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:typed_data';

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

/// When making a POST request, headers are ignored. As a workaround, make
/// the request manually and load the response data using [loadHTMLString].
@override
Future<void> loadRequest(
WebViewRequest request,
) async {
if (!request.uri.hasScheme) {
throw ArgumentError('WebViewRequest#uri is required to have a scheme.');
}
switch (request.method) {
case WebViewRequestMethod.get:
return webView.loadUrl(request.uri.toString(), request.headers);
case WebViewRequestMethod.post:
return webView.postUrl(
request.uri.toString(), request.body ?? Uint8List(0));
default:
throw UnimplementedError(
'This version of webview_android_widget currently has no implementation for HTTP method ${request.method.serialize()} in loadRequest.',
);
}
}

@override
Future<String?> currentUrl() => webView.getUrl();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ abstract class WebViewHostApi {
Map<String, String> headers,
);

void postUrl(
int instanceId,
String url,
Uint8List data,
);

String getUrl(int instanceId);

bool canGoBack(int instanceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter_android
description: A Flutter plugin that provides a WebView widget on Android.
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
version: 2.6.0
version: 2.7.0

environment:
sdk: ">=2.14.0 <3.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ abstract class TestWebViewHostApi {
void loadDataWithBaseUrl(int instanceId, String baseUrl, String data,
String mimeType, String encoding, String historyUrl);
void loadUrl(int instanceId, String url, Map<String?, String?> headers);
void postUrl(int instanceId, String url, Uint8List data);
String getUrl(int instanceId);
bool canGoBack(int instanceId);
bool canGoForward(int instanceId);
Expand Down Expand Up @@ -180,6 +181,31 @@ abstract class TestWebViewHostApi {
});
}
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebViewHostApi.postUrl', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMockMessageHandler(null);
} else {
channel.setMockMessageHandler((Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null.');
final List<Object?> args = (message as List<Object?>?)!;
final int? arg_instanceId = (args[0] as int?);
assert(arg_instanceId != null,
'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null int.');
final String? arg_url = (args[1] as String?);
assert(arg_url != null,
'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null String.');
final Uint8List? arg_data = (args[2] as Uint8List?);
assert(arg_data != null,
'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null Uint8List.');
api.postUrl(arg_instanceId!, arg_url!, arg_data!);
return <Object?, Object?>{};
});
}
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebViewHostApi.getUrl', codec,
Expand Down
Loading