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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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