[webview_flutter_android] Adds support for use of old hybrid composition (#6063)
diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
index 7261cc1..a8e9a92 100644
--- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
@@ -1,6 +1,13 @@
-## NEXT
+## 2.9.0
* Ignores unnecessary import warnings in preparation for [upcoming Flutter changes](https://github.com/flutter/flutter/pull/106316).
+* Fixes bug where `Directionality` from context didn't affect `SurfaceAndroidWebView`.
+* Fixes bug where default text direction was different for `SurfaceAndroidWebView` and `AndroidWebView`.
+ Default is now `TextDirection.ltr` for both.
+* Fixes bug where setting WebView to a transparent background could cause visual errors when using
+ `SurfaceAndroidWebView`. Hybrid composition is now used when the background color is not 100%
+ opaque.
+* Raises minimum Flutter version to 3.0.0.
## 2.8.14
diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart
index 00d7c8c..61ec110 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart
@@ -14,14 +14,20 @@
import 'webview_android.dart';
import 'webview_android_widget.dart';
-/// Android [WebViewPlatform] that uses [AndroidViewSurface] to build the [WebView] widget.
+/// Android [WebViewPlatform] that uses [AndroidViewSurface] to build the
+/// [WebView] widget.
///
/// To use this, set [WebView.platform] to an instance of this class.
///
-/// This implementation uses hybrid composition to render the [WebView] on
+/// This implementation uses [AndroidViewSurface] to render the [WebView] on
/// Android. It solves multiple issues related to accessibility and interaction
/// with the [WebView] at the cost of some performance on Android versions below
-/// 10. See https://github.com/flutter/flutter/wiki/Hybrid-Composition for more
+/// 10.
+///
+/// To support transparent backgrounds on all Android devices, this
+/// implementation uses hybrid composition when the opacity of
+/// `CreationParams.backgroundColor` is less than 1.0. See
+/// https://github.com/flutter/flutter/wiki/Hybrid-Composition for more
/// information.
class SurfaceAndroidWebView extends AndroidWebView {
@override
@@ -53,16 +59,23 @@
);
},
onCreatePlatformView: (PlatformViewCreationParams params) {
- return PlatformViewsService.initSurfaceAndroidView(
+ final Color? backgroundColor = creationParams.backgroundColor;
+ return _createViewController(
+ // On some Android devices, transparent backgrounds can cause
+ // rendering issues on the non hybrid composition
+ // AndroidViewSurface. This switches the WebView to Hybrid
+ // Composition when the background color is not 100% opaque.
+ hybridComposition:
+ backgroundColor != null && backgroundColor.opacity < 1.0,
id: params.id,
viewType: 'plugins.flutter.io/webview',
// WebView content is not affected by the Android view's layout direction,
// we explicitly set it here so that the widget doesn't require an ambient
// directionality.
- layoutDirection: TextDirection.rtl,
- creationParams:
- InstanceManager.instance.getInstanceId(controller.webView),
- creationParamsCodec: const StandardMessageCodec(),
+ layoutDirection:
+ Directionality.maybeOf(context) ?? TextDirection.ltr,
+ webViewIdentifier:
+ InstanceManager.instance.getInstanceId(controller.webView)!,
)
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
..addOnPlatformViewCreatedListener((int id) {
@@ -76,4 +89,29 @@
},
);
}
+
+ AndroidViewController _createViewController({
+ required bool hybridComposition,
+ required int id,
+ required String viewType,
+ required TextDirection layoutDirection,
+ required int webViewIdentifier,
+ }) {
+ if (hybridComposition) {
+ return PlatformViewsService.initExpensiveAndroidView(
+ id: id,
+ viewType: viewType,
+ layoutDirection: layoutDirection,
+ creationParams: webViewIdentifier,
+ creationParamsCodec: const StandardMessageCodec(),
+ );
+ }
+ return PlatformViewsService.initSurfaceAndroidView(
+ id: id,
+ viewType: viewType,
+ layoutDirection: layoutDirection,
+ creationParams: webViewIdentifier,
+ creationParamsCodec: const StandardMessageCodec(),
+ );
+ }
}
diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
index a386cad..aaa4984 100644
--- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
@@ -2,11 +2,11 @@
description: A Flutter plugin that provides a WebView widget on Android.
repository: https://github.com/flutter/plugins/tree/main/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.8.14
+version: 2.9.0
environment:
sdk: ">=2.14.0 <3.0.0"
- flutter: ">=2.8.0"
+ flutter: ">=3.0.0"
flutter:
plugin:
diff --git a/packages/webview_flutter/webview_flutter_android/test/surface_android_test.dart b/packages/webview_flutter/webview_flutter_android/test/surface_android_test.dart
new file mode 100644
index 0000000..63e752b
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/test/surface_android_test.dart
@@ -0,0 +1,115 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:webview_flutter_android/webview_surface_android.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+
+void main() {
+ TestWidgetsFlutterBinding.ensureInitialized();
+
+ group('SurfaceAndroidWebView', () {
+ late List<MethodCall> log;
+
+ setUpAll(() {
+ SystemChannels.platform_views.setMockMethodCallHandler(
+ (MethodCall call) async {
+ log.add(call);
+ if (call.method == 'resize') {
+ return <String, Object?>{
+ 'width': call.arguments['width'],
+ 'height': call.arguments['height'],
+ };
+ }
+ },
+ );
+ });
+
+ tearDownAll(() {
+ SystemChannels.platform_views.setMockMethodCallHandler(null);
+ });
+
+ setUp(() {
+ log = <MethodCall>[];
+ });
+
+ testWidgets(
+ 'uses hybrid composition when background color is not 100% opaque',
+ (WidgetTester tester) async {
+ await tester.pumpWidget(Builder(builder: (BuildContext context) {
+ return SurfaceAndroidWebView().build(
+ context: context,
+ creationParams: CreationParams(
+ backgroundColor: Colors.transparent,
+ webSettings: WebSettings(
+ userAgent: const WebSetting<String?>.absent(),
+ hasNavigationDelegate: false,
+ )),
+ javascriptChannelRegistry: JavascriptChannelRegistry(null),
+ webViewPlatformCallbacksHandler:
+ TestWebViewPlatformCallbacksHandler(),
+ );
+ }));
+ await tester.pumpAndSettle();
+
+ final MethodCall createMethodCall = log[0];
+ expect(createMethodCall.method, 'create');
+ expect(createMethodCall.arguments, containsPair('hybrid', true));
+ });
+
+ testWidgets('default text direction is ltr', (WidgetTester tester) async {
+ await tester.pumpWidget(Builder(builder: (BuildContext context) {
+ return SurfaceAndroidWebView().build(
+ context: context,
+ creationParams: CreationParams(
+ webSettings: WebSettings(
+ userAgent: const WebSetting<String?>.absent(),
+ hasNavigationDelegate: false,
+ )),
+ javascriptChannelRegistry: JavascriptChannelRegistry(null),
+ webViewPlatformCallbacksHandler:
+ TestWebViewPlatformCallbacksHandler(),
+ );
+ }));
+ await tester.pumpAndSettle();
+
+ final MethodCall createMethodCall = log[0];
+ expect(createMethodCall.method, 'create');
+ expect(
+ createMethodCall.arguments,
+ containsPair(
+ 'direction',
+ AndroidViewController.kAndroidLayoutDirectionLtr,
+ ),
+ );
+ });
+ });
+}
+
+class TestWebViewPlatformCallbacksHandler
+ implements WebViewPlatformCallbacksHandler {
+ @override
+ FutureOr<bool> onNavigationRequest({
+ required String url,
+ required bool isForMainFrame,
+ }) {
+ throw UnimplementedError();
+ }
+
+ @override
+ void onPageFinished(String url) {}
+
+ @override
+ void onPageStarted(String url) {}
+
+ @override
+ void onProgress(int progress) {}
+
+ @override
+ void onWebResourceError(WebResourceError error) {}
+}