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

DO NOT MERGE #4579

Closed
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
11 changes: 7 additions & 4 deletions packages/webview_flutter/webview_flutter_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.5.0

* Add an option to set the background color of the webview.

## 2.4.0

* Adds support for Android's `WebView.loadData` and `WebView.loadDataWithBaseUrl` methods and implements the `loadFile` and `loadHtmlString` methods from the platform interface.
Expand Down Expand Up @@ -27,13 +31,12 @@ when it is created without Hybrid Composition.

## 2.0.15

* Added Overrides in FlutterWebView.java
* Added Overrides in FlutterWebView.java

## 2.0.14

* Update example App so navigation menu loads immediatly but only becomes available when `WebViewController` is available (same behavior as example App in webview_flutter package).
* Update example App so navigation menu loads immediatly but only becomes available when `WebViewController` is available (same behavior as example App in webview_flutter package).

## 2.0.13

* Extract Android implementation from `webview_flutter`.

Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ void loadDataWithBaseUrl(

void setWebChromeClient(Long instanceId, Long clientInstanceId);

void setBackgroundColor(Long instanceId, Long color);

/** The codec used by WebViewHostApi. */
static MessageCodec<Object> getCodec() {
return WebViewHostApiCodec.INSTANCE;
Expand Down Expand Up @@ -958,6 +960,37 @@ public void error(Throwable error) {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.WebViewHostApi.setBackgroundColor",
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.");
}
Number colorArg = (Number) args.get(1);
if (colorArg == null) {
throw new NullPointerException("colorArg unexpectedly null.");
}
api.setBackgroundColor(instanceIdArg.longValue(), colorArg.longValue());
wrapped.put("result", null);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,12 @@ public void setWebChromeClient(Long instanceId, Long clientInstanceId) {
webView.setWebChromeClient((WebChromeClient) instanceManager.getInstance(clientInstanceId));
}

@Override
public void setBackgroundColor(Long instanceId, Long color) {
final WebView webView = (WebView) instanceManager.getInstance(instanceId);
webView.setBackgroundColor(color.intValue());
}

@Nullable
private static String parseNullStringIdentifier(String value) {
if (value.equals(nullStringIdentifier)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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.

package io.flutter.plugins.webviewflutterexample;

import static androidx.test.espresso.flutter.EspressoFlutter.onFlutterWidget;
import static androidx.test.espresso.flutter.action.FlutterActions.click;
import static androidx.test.espresso.flutter.matcher.FlutterMatchers.withText;
import static androidx.test.espresso.flutter.matcher.FlutterMatchers.withValueKey;
import static org.junit.Assert.assertEquals;

import android.graphics.Bitmap;
import android.graphics.Color;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.screenshot.ScreenCapture;
import androidx.test.runner.screenshot.Screenshot;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class BackgroundColorTest {
@Rule
public ActivityTestRule<DriverExtensionActivity> myActivityTestRule =
new ActivityTestRule<>(DriverExtensionActivity.class, true, false);

@Before
public void setUp() {
ActivityScenario.launch(DriverExtensionActivity.class);
}

@Test
public void backgroundColor() {
onFlutterWidget(withValueKey("ShowPopupMenu")).perform(click());
onFlutterWidget(withValueKey("ShowTransparentBackgroundExample")).perform(click());
onFlutterWidget(withText("Transparent background test"));

final ScreenCapture screenCapture = Screenshot.capture();
final Bitmap screenBitmap = screenCapture.getBitmap();

final int centerLeftColor =
screenBitmap.getPixel(10, (int) Math.floor(screenBitmap.getHeight() / 2.0));
final int centerColor =
screenBitmap.getPixel(
(int) Math.floor(screenBitmap.getWidth() / 2.0),
(int) Math.floor(screenBitmap.getHeight() / 2.0));

// Flutter Colors.green color : 0xFF4CAF50
// https://github.com/flutter/flutter/blob/f4abaa0735eba4dfd8f33f73363911d63931fe03/packages/flutter/lib/src/material/colors.dart#L1208
// The background color of the webview is : rgba(0, 0, 0, 0.5)
// The expected color is : rgba(38, 87, 40, 1) -> 0xFF265728
assertEquals(0xFF265728, centerLeftColor);
assertEquals(Color.RED, centerColor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,13 @@
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
</activity>
<activity
android:name=".DriverExtensionActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
</activity>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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.

package io.flutter.plugins.webviewflutterexample;

import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;

public class DriverExtensionActivity extends FlutterActivity {
@Override
@NonNull
public String getDartEntrypointFunctionName() {
return "appMain";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'package:path_provider/path_provider.dart';
import 'package:webview_flutter_android/webview_surface_android.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
Expand All @@ -17,6 +18,11 @@ import 'navigation_decision.dart';
import 'navigation_request.dart';
import 'web_view.dart';

void appMain() {
enableFlutterDriverExtension();
main();
}

void main() {
// Configure the [WebView] to use the [SurfaceAndroidWebView]
// implementation instead of the default [AndroidWebView].
Expand Down Expand Up @@ -59,6 +65,27 @@ const String kExamplePage = '''
</html>
''';

const String kTransparentBackgroundPage = '''
<!DOCTYPE html>
<html>
<head>
<title>Transparent background test</title>
</head>
<style type="text/css">
body { background: transparent; margin: 0; padding: 0; }
#container { position: relative; margin: 0; padding: 0; width: 100vw; height: 100vh; }
#shape { background: #FF0000; width: 200px; height: 100%; margin: 0; padding: 0; position: absolute; top: 0; bottom: 0; left: calc(50% - 100px); }
p { text-align: center; }
</style>
<body>
<div id="container">
<p>Transparent background test</p>
<div id="shape"></div>
</div>
</body>
</html>
''';

class _WebViewExample extends StatefulWidget {
const _WebViewExample({Key? key}) : super(key: key);

Expand All @@ -73,6 +100,7 @@ class _WebViewExampleState extends State<_WebViewExample> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF4CAF50),
appBar: AppBar(
title: const Text('Flutter WebView example'),
// This drop down menu demonstrates that Flutter widgets can be shown over the web view.
Expand Down Expand Up @@ -109,6 +137,7 @@ class _WebViewExampleState extends State<_WebViewExample> {
javascriptChannels: _createJavascriptChannels(context),
javascriptMode: JavascriptMode.unrestricted,
userAgent: 'Custom_User_Agent',
backgroundColor: const Color(0x80000000),
);
}),
floatingActionButton: favoriteButton(),
Expand Down Expand Up @@ -158,6 +187,7 @@ enum _MenuOptions {
navigationDelegate,
loadLocalFile,
loadHtmlString,
transparentBackground,
}

class _SampleMenu extends StatelessWidget {
Expand All @@ -172,6 +202,7 @@ class _SampleMenu extends StatelessWidget {
builder:
(BuildContext context, AsyncSnapshot<WebViewController> controller) {
return PopupMenuButton<_MenuOptions>(
key: const ValueKey<String>('ShowPopupMenu'),
onSelected: (_MenuOptions value) {
switch (value) {
case _MenuOptions.showUserAgent:
Expand Down Expand Up @@ -201,6 +232,9 @@ class _SampleMenu extends StatelessWidget {
case _MenuOptions.loadHtmlString:
_onLoadHtmlStringExample(controller.data!, context);
break;
case _MenuOptions.transparentBackground:
_onTransparentBackground(controller.data!, context);
break;
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<_MenuOptions>>[
Expand Down Expand Up @@ -241,6 +275,11 @@ class _SampleMenu extends StatelessWidget {
value: _MenuOptions.loadLocalFile,
child: Text('Load local file'),
),
const PopupMenuItem<_MenuOptions>(
key: ValueKey<String>('ShowTransparentBackgroundExample'),
value: _MenuOptions.transparentBackground,
child: Text('Transparent background example'),
),
],
);
},
Expand Down Expand Up @@ -353,6 +392,11 @@ class _SampleMenu extends StatelessWidget {

return indexFile.path;
}

Future<void> _onTransparentBackground(
WebViewController controller, BuildContext context) async {
await controller.loadHtmlString(kTransparentBackgroundPage);
}
}

class _NavigationControls extends StatelessWidget {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class WebView extends StatefulWidget {
this.initialMediaPlaybackPolicy =
AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
this.allowsInlineMediaPlayback = false,
this.backgroundColor,
}) : assert(javascriptMode != null),
assert(initialMediaPlaybackPolicy != null),
assert(allowsInlineMediaPlayback != null),
Expand Down Expand Up @@ -236,6 +237,12 @@ class WebView extends StatefulWidget {
/// The default policy is [AutoMediaPlaybackPolicy.require_user_action_for_all_media_types].
final AutoMediaPlaybackPolicy initialMediaPlaybackPolicy;

/// The background color of the [WebView].
///
/// When `null` the platform's webview default background color is used. By
/// default [backgroundColor] is `null`.
final Color? backgroundColor;

@override
_WebViewState createState() => _WebViewState();
}
Expand Down Expand Up @@ -287,6 +294,7 @@ class _WebViewState extends State<WebView> {
_javascriptChannelRegistry.channels.keys.toSet(),
autoMediaPlaybackPolicy: widget.initialMediaPlaybackPolicy,
userAgent: widget.userAgent,
backgroundColor: widget.backgroundColor,
),
javascriptChannelRegistry: _javascriptChannelRegistry,
);
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:ui';

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart' show AndroidViewSurface;

Expand Down Expand Up @@ -349,6 +351,11 @@ class WebView {
return api.setWebChromeClientFromInstance(this, client);
}

/// Sets the background color of this WebView.
Future<void> setBackgroundColor(Color color) {
return api.setBackgroundColorFromInstance(this, color.value);
}

/// Releases all resources used by the [WebView].
///
/// Any methods called after [release] will throw an exception.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,31 @@ class WebViewHostApi {
return;
}
}

Future<void> setBackgroundColor(int arg_instanceId, int arg_color) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebViewHostApi.setBackgroundColor', codec,
binaryMessenger: _binaryMessenger);
final Map<Object?, Object?>? replyMap = await channel
.send(<Object>[arg_instanceId, arg_color]) 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;
}
}
}

class _WebSettingsHostApiCodec extends StandardMessageCodec {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,11 @@ class WebViewHostApiImpl extends WebViewHostApi {
instanceManager.getInstanceId(client)!,
);
}

/// Helper method to convert instances ids to objects.
Future<void> setBackgroundColorFromInstance(WebView instance, int color) {
return setBackgroundColor(instanceManager.getInstanceId(instance)!, color);
}
}

/// Host api implementation for [WebSettings].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ class WebViewAndroidPlatformController extends WebViewPlatformController {
AutoMediaPlaybackPolicy.always_allow,
);

final Color? backgroundColor = creationParams.backgroundColor;
if (backgroundColor != null) {
webView.setBackgroundColor(backgroundColor);
}

addJavascriptChannels(creationParams.javascriptChannelNames);
}

Expand Down
Loading