Skip to content

Commit b3138a6

Browse files
[webview_flutter_android][webview_flutter_wkwebview] Adds support for getUserAgent for webview_flutter platform implementations (#4927)
Platform implementations for #4472
1 parent c3cc4d8 commit b3138a6

38 files changed

+714
-41
lines changed

packages/webview_flutter/webview_flutter_android/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.12.0
2+
3+
* Adds support for `PlatformWebViewController.getUserAgent`.
4+
15
## 3.11.0
26

37
* Adds support to register a callback to receive JavaScript console messages. See `AndroidWebViewController.onConsoleMessage`.
@@ -27,7 +31,7 @@
2731
## 3.9.2
2832

2933
* Fixes bug where `PlatformWebViewWidget` doesn't rebuild when the controller or PlatformView
30-
implementation flag changes.
34+
implementation flag changes.
3135

3236
## 3.9.1
3337

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,6 +1790,9 @@ public interface WebSettingsHostApi {
17901790

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

1793+
@NonNull
1794+
String getUserAgentString(@NonNull Long instanceId);
1795+
17931796
/** The codec used by WebSettingsHostApi. */
17941797
static @NonNull MessageCodec<Object> getCodec() {
17951798
return new StandardMessageCodec();
@@ -2179,6 +2182,33 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable WebSetting
21792182
channel.setMessageHandler(null);
21802183
}
21812184
}
2185+
{
2186+
BasicMessageChannel<Object> channel =
2187+
new BasicMessageChannel<>(
2188+
binaryMessenger,
2189+
"dev.flutter.pigeon.webview_flutter_android.WebSettingsHostApi.getUserAgentString",
2190+
getCodec());
2191+
if (api != null) {
2192+
channel.setMessageHandler(
2193+
(message, reply) -> {
2194+
ArrayList<Object> wrapped = new ArrayList<Object>();
2195+
ArrayList<Object> args = (ArrayList<Object>) message;
2196+
Number instanceIdArg = (Number) args.get(0);
2197+
try {
2198+
String output =
2199+
api.getUserAgentString(
2200+
(instanceIdArg == null) ? null : instanceIdArg.longValue());
2201+
wrapped.add(0, output);
2202+
} catch (Throwable exception) {
2203+
ArrayList<Object> wrappedError = wrapError(exception);
2204+
wrapped = wrappedError;
2205+
}
2206+
reply.reply(wrapped);
2207+
});
2208+
} else {
2209+
channel.setMessageHandler(null);
2210+
}
2211+
}
21822212
}
21832213
}
21842214
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,11 @@ public void setTextZoom(@NonNull Long instanceId, @NonNull Long textZoom) {
132132
final WebSettings webSettings = Objects.requireNonNull(instanceManager.getInstance(instanceId));
133133
webSettings.setTextZoom(textZoom.intValue());
134134
}
135+
136+
@NonNull
137+
@Override
138+
public String getUserAgentString(@NonNull Long instanceId) {
139+
final WebSettings webSettings = Objects.requireNonNull(instanceManager.getInstance(instanceId));
140+
return webSettings.getUserAgentString();
141+
}
135142
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package io.flutter.plugins.webviewflutter;
66

7+
import static org.junit.Assert.assertEquals;
78
import static org.mockito.ArgumentMatchers.any;
89
import static org.mockito.Mockito.mock;
910
import static org.mockito.Mockito.verify;
@@ -117,4 +118,11 @@ public void setTextZoom() {
117118
testHostApiImpl.setTextZoom(0L, 100L);
118119
verify(mockWebSettings).setTextZoom(100);
119120
}
121+
122+
@Test
123+
public void getUserAgentString() {
124+
final String userAgent = "str";
125+
when(mockWebSettings.getUserAgentString()).thenReturn(userAgent);
126+
assertEquals(testHostApiImpl.getUserAgentString(0L), userAgent);
127+
}
120128
}

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

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ Future<void> main() async {
342342

343343
await pageFinished.future;
344344

345-
final String customUserAgent = await _getUserAgent(controller);
345+
final String? customUserAgent = await controller.getUserAgent();
346346
expect(customUserAgent, 'Custom_User_Agent1');
347347
});
348348

@@ -1353,19 +1353,6 @@ Future<void> main() async {
13531353
});
13541354
}
13551355

1356-
/// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests.
1357-
Future<String> _getUserAgent(PlatformWebViewController controller) async {
1358-
return _runJavaScriptReturningResult(controller, 'navigator.userAgent;');
1359-
}
1360-
1361-
Future<String> _runJavaScriptReturningResult(
1362-
PlatformWebViewController controller,
1363-
String js,
1364-
) async {
1365-
return jsonDecode(await controller.runJavaScriptReturningResult(js) as String)
1366-
as String;
1367-
}
1368-
13691356
class ResizableWebView extends StatefulWidget {
13701357
const ResizableWebView({
13711358
super.key,

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,11 @@ class WebSettings extends JavaObject {
695695
return api.setSetTextZoomFromInstance(this, textZoom);
696696
}
697697

698+
/// Gets the WebView's user-agent string.
699+
Future<String> getUserAgentString() {
700+
return api.getUserAgentStringFromInstance(this);
701+
}
702+
698703
@override
699704
WebSettings copy() {
700705
return WebSettings.detached(

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,34 @@ class WebSettingsHostApi {
14991499
return;
15001500
}
15011501
}
1502+
1503+
Future<String> getUserAgentString(int arg_instanceId) async {
1504+
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
1505+
'dev.flutter.pigeon.webview_flutter_android.WebSettingsHostApi.getUserAgentString',
1506+
codec,
1507+
binaryMessenger: _binaryMessenger);
1508+
final List<Object?>? replyList =
1509+
await channel.send(<Object?>[arg_instanceId]) as List<Object?>?;
1510+
if (replyList == null) {
1511+
throw PlatformException(
1512+
code: 'channel-error',
1513+
message: 'Unable to establish connection on channel.',
1514+
);
1515+
} else if (replyList.length > 1) {
1516+
throw PlatformException(
1517+
code: replyList[0]! as String,
1518+
message: replyList[1] as String?,
1519+
details: replyList[2],
1520+
);
1521+
} else if (replyList[0] == null) {
1522+
throw PlatformException(
1523+
code: 'null-error',
1524+
message: 'Host platform returned null value for non-null return value.',
1525+
);
1526+
} else {
1527+
return (replyList[0] as String?)!;
1528+
}
1529+
}
15021530
}
15031531

15041532
class JavaScriptChannelHostApi {

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,11 @@ class WebSettingsHostApiImpl extends WebSettingsHostApi {
553553
enabled,
554554
);
555555
}
556+
557+
/// Helper method to convert instances ids to objects.
558+
Future<String> getUserAgentStringFromInstance(WebSettings instance) {
559+
return getUserAgentString(instanceManager.getIdentifier(instance)!);
560+
}
556561
}
557562

558563
/// Host api implementation for [JavaScriptChannel].

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,9 @@ class AndroidWebViewController extends PlatformWebViewController {
617617
return _webChromeClient.setSynchronousReturnValueForOnConsoleMessage(
618618
_onConsoleLogCallback != null);
619619
}
620+
621+
@override
622+
Future<String?> getUserAgent() => _webView.settings.getUserAgentString();
620623
}
621624

622625
/// Android implementation of [PlatformWebViewPermissionRequest].

packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ abstract class WebSettingsHostApi {
299299
void setAllowFileAccess(int instanceId, bool enabled);
300300

301301
void setTextZoom(int instanceId, int textZoom);
302+
303+
String getUserAgentString(int instanceId);
302304
}
303305

304306
@HostApi(dartHostTestHandler: 'TestJavaScriptChannelHostApi')

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/packages/tree/main/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: 3.11.0
5+
version: 3.12.0
66

77
environment:
88
sdk: ">=2.19.0 <4.0.0"

packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,20 @@ void main() {
12591259
verify(mockWebView.settings).called(1);
12601260
verify(mockSettings.setUserAgentString('Test Framework')).called(1);
12611261
});
1262+
1263+
test('getUserAgent', () async {
1264+
final MockWebSettings mockSettings = MockWebSettings();
1265+
final AndroidWebViewController controller = createControllerWithMocks(
1266+
mockSettings: mockSettings,
1267+
);
1268+
1269+
const String userAgent = 'str';
1270+
1271+
when(mockSettings.getUserAgentString())
1272+
.thenAnswer((_) => Future<String>.value(userAgent));
1273+
1274+
expect(await controller.getUserAgent(), userAgent);
1275+
});
12621276
});
12631277

12641278
test('setMediaPlaybackRequiresUserGesture', () async {

0 commit comments

Comments
 (0)