Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 4.3.0

* Adds support to retrieve the user agent. See `WebViewController.getUserAgent`.

## 4.2.2

* Fixes documentation typo.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ Future<void> main() async {

await pageFinished.future;

final String customUserAgent = await _getUserAgent(controller);
final String? customUserAgent = await controller.getUserAgent();
expect(customUserAgent, 'Custom_User_Agent1');
});

Expand Down Expand Up @@ -876,22 +876,6 @@ String _webViewString(String value) {
return '"$value"';
}

/// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests.
Future<String> _getUserAgent(WebViewController controller) async {
return _runJavascriptReturningResult(controller, 'navigator.userAgent;');
}

Future<String> _runJavascriptReturningResult(
WebViewController controller,
String js,
) async {
if (defaultTargetPlatform == TargetPlatform.iOS) {
return await controller.runJavaScriptReturningResult(js) as String;
}
return jsonDecode(await controller.runJavaScriptReturningResult(js) as String)
as String;
}

class ResizableWebView extends StatefulWidget {
const ResizableWebView({
super.key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,8 @@ flutter:
- assets/sample_video.mp4
- assets/www/index.html
- assets/www/styles/style.css

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{webview_flutter_android: {path: ../../../webview_flutter/webview_flutter_android}, webview_flutter_platform_interface: {path: ../../../webview_flutter/webview_flutter_platform_interface}, webview_flutter_wkwebview: {path: ../../../webview_flutter/webview_flutter_wkwebview}}
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,11 @@ class WebViewController {
Future<void> setUserAgent(String? userAgent) {
return platform.setUserAgent(userAgent);
}

/// Gets the value used for the HTTP `User-Agent:` request header.
Future<String?> getUserAgent() {
return platform.getUserAgent();
}
}

/// Permissions request when web content requests access to protected resources.
Expand Down
7 changes: 6 additions & 1 deletion packages/webview_flutter/webview_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter
description: A Flutter plugin that provides a WebView widget on Android and iOS.
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
version: 4.2.2
version: 4.3.0

environment:
sdk: ">=2.18.0 <4.0.0"
Expand All @@ -29,3 +29,8 @@ dev_dependencies:
sdk: flutter
mockito: 5.4.1
plugin_platform_interface: ^2.1.3

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{webview_flutter_android: {path: ../../webview_flutter/webview_flutter_android}, webview_flutter_platform_interface: {path: ../../webview_flutter/webview_flutter_platform_interface}, webview_flutter_wkwebview: {path: ../../webview_flutter/webview_flutter_wkwebview}}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.1 from annotations
// in webview_flutter/test/legacy/webview_flutter_test.dart.
// Do not manually edit this file.

// @dart=2.19

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i9;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.1 from annotations
// in webview_flutter/test/navigation_delegate_test.dart.
// Do not manually edit this file.

// @dart=2.19

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i8;

Expand Down Expand Up @@ -208,6 +210,16 @@ class MockPlatformNavigationDelegate extends _i1.Mock
returnValueForMissingStub: _i8.Future<void>.value(),
) as _i8.Future<void>);
@override
_i8.Future<void> setOnHttpError(_i3.HttpResponseErrorCallback? onHttpError) =>
(super.noSuchMethod(
Invocation.method(
#setOnHttpError,
[onHttpError],
),
returnValue: _i8.Future<void>.value(),
returnValueForMissingStub: _i8.Future<void>.value(),
) as _i8.Future<void>);
@override
_i8.Future<void> setOnProgress(_i3.ProgressCallback? onProgress) =>
(super.noSuchMethod(
Invocation.method(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,23 @@ void main() {
requestCallback(const TestPlatformWebViewPermissionRequest());
expect(permissionRequestCallbackCalled, isTrue);
});

test('getUserAgent', () async {
final MockPlatformWebViewController mockPlatformWebViewController =
MockPlatformWebViewController();

const String userAgent = 'str';

when(mockPlatformWebViewController.getUserAgent()).thenAnswer(
(_) => Future<String?>.value(userAgent),
);

final WebViewController webViewController = WebViewController.fromPlatform(
mockPlatformWebViewController,
);

await expectLater(webViewController.getUserAgent(), completion(userAgent));
});
}

class TestPlatformWebViewPermissionRequest
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.1 from annotations
// in webview_flutter/test/webview_controller_test.dart.
// Do not manually edit this file.

// @dart=2.19

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i5;
import 'dart:ui' as _i3;
Expand Down Expand Up @@ -353,6 +355,14 @@ class MockPlatformWebViewController extends _i1.Mock
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<String?> getUserAgent() => (super.noSuchMethod(
Invocation.method(
#getUserAgent,
[],
),
returnValue: _i5.Future<String?>.value(),
) as _i5.Future<String?>);
}

/// A class which mocks [PlatformNavigationDelegate].
Expand Down Expand Up @@ -405,6 +415,16 @@ class MockPlatformNavigationDelegate extends _i1.Mock
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> setOnHttpError(_i6.HttpResponseErrorCallback? onHttpError) =>
(super.noSuchMethod(
Invocation.method(
#setOnHttpError,
[onHttpError],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> setOnProgress(_i6.ProgressCallback? onProgress) =>
(super.noSuchMethod(
Invocation.method(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.1 from annotations
// in webview_flutter/test/webview_cookie_manager_test.dart.
// Do not manually edit this file.

// @dart=2.19

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.1 from annotations
// in webview_flutter/test/webview_widget_test.dart.
// Do not manually edit this file.

// @dart=2.19

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i7;
import 'dart:ui' as _i3;
Expand Down Expand Up @@ -371,6 +373,14 @@ class MockPlatformWebViewController extends _i1.Mock
returnValue: _i7.Future<void>.value(),
returnValueForMissingStub: _i7.Future<void>.value(),
) as _i7.Future<void>);
@override
_i7.Future<String?> getUserAgent() => (super.noSuchMethod(
Invocation.method(
#getUserAgent,
[],
),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
}

/// A class which mocks [PlatformWebViewWidget].
Expand Down
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 @@
## 3.10.0

* Adds support for `PlatformWebViewController.getUserAgent`.

## 3.9.1

* Adjusts SDK checks for better testability.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,9 @@ public interface WebSettingsHostApi {

void setTextZoom(@NonNull Long instanceId, @NonNull Long textZoom);

@NonNull
String getUserAgentString(@NonNull Long instanceId);

/** The codec used by WebSettingsHostApi. */
static @NonNull MessageCodec<Object> getCodec() {
return new StandardMessageCodec();
Expand Down Expand Up @@ -1992,6 +1995,33 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable WebSetting
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.WebSettingsHostApi.getUserAgentString",
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
Number instanceIdArg = (Number) args.get(0);
try {
String output =
api.getUserAgentString(
(instanceIdArg == null) ? null : instanceIdArg.longValue());
wrapped.add(0, output);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,11 @@ public void setTextZoom(@NonNull Long instanceId, @NonNull Long textZoom) {
final WebSettings webSettings = Objects.requireNonNull(instanceManager.getInstance(instanceId));
webSettings.setTextZoom(textZoom.intValue());
}

@NonNull
@Override
public String getUserAgentString(@NonNull Long instanceId) {
final WebSettings webSettings = Objects.requireNonNull(instanceManager.getInstance(instanceId));
return webSettings.getUserAgentString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package io.flutter.plugins.webviewflutter;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -117,4 +118,11 @@ public void setTextZoom() {
testHostApiImpl.setTextZoom(0L, 100L);
verify(mockWebSettings).setTextZoom(100);
}

@Test
public void getUserAgentString() {
final String userAgent = "str";
when(mockWebSettings.getUserAgentString()).thenReturn(userAgent);
assertEquals(testHostApiImpl.getUserAgentString(0L), userAgent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ Future<void> main() async {

await pageFinished.future;

final String customUserAgent = await _getUserAgent(controller);
final String? customUserAgent = await controller.getUserAgent();
expect(customUserAgent, 'Custom_User_Agent1');
});

Expand Down Expand Up @@ -1228,19 +1228,6 @@ Future<void> main() async {
);
}

/// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests.
Future<String> _getUserAgent(PlatformWebViewController controller) async {
return _runJavaScriptReturningResult(controller, 'navigator.userAgent;');
}

Future<String> _runJavaScriptReturningResult(
PlatformWebViewController controller,
String js,
) async {
return jsonDecode(await controller.runJavaScriptReturningResult(js) as String)
as String;
}

class ResizableWebView extends StatefulWidget {
const ResizableWebView({
super.key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ flutter:
- assets/sample_video.mp4
- assets/www/index.html
- assets/www/styles/style.css

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{webview_flutter_android: {path: ../../../webview_flutter/webview_flutter_android}, webview_flutter_platform_interface: {path: ../../../webview_flutter/webview_flutter_platform_interface}}
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,11 @@ class WebSettings extends JavaObject {
return api.setSetTextZoomFromInstance(this, textZoom);
}

/// Gets the WebView's user-agent string.
Future<String> getUserAgentString() {
return api.getUserAgentStringFromInstance(this);
}

@override
WebSettings copy() {
return WebSettings.detached(
Expand Down
Loading