Skip to content

Commit

Permalink
[webview_flutter] Add a backgroundColor option to the iOS webview (fl…
Browse files Browse the repository at this point in the history
…utter#4570)

This PR add an option to set the background color of the iOS webview.

Part of flutter#3431
Part of flutter/flutter#29300
  • Loading branch information
e-adrien authored and KyleFin committed Dec 21, 2021
1 parent dcc820f commit 1e5b61c
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 2.5.0

* Adds an option to set the background color of the webview.
* Migrates from `analysis_options_legacy.yaml` to `analysis_options.yaml`.
* Integration test fixes.
* Updates to webview_flutter_platform_interface version 1.5.2.
Expand All @@ -22,7 +23,7 @@

## 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@
@import XCTest;
@import os.log;

static UIColor* getPixelColorInImage(CGImageRef image, size_t x, size_t y) {
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image));
const UInt8* data = CFDataGetBytePtr(pixelData);

size_t bytesPerRow = CGImageGetBytesPerRow(image);
size_t pixelInfo = (bytesPerRow * y) + (x * 4); // 4 bytes per pixel

UInt8 red = data[pixelInfo + 0];
UInt8 green = data[pixelInfo + 1];
UInt8 blue = data[pixelInfo + 2];
UInt8 alpha = data[pixelInfo + 3];
CFRelease(pixelData);

return [UIColor colorWithRed:red / 255.0f
green:green / 255.0f
blue:blue / 255.0f
alpha:alpha / 255.0f];
}

@interface FLTWebViewUITests : XCTestCase
@property(nonatomic, strong) XCUIApplication* app;
@end
Expand All @@ -18,6 +37,54 @@ - (void)setUp {
[self.app launch];
}

- (void)testTransparentBackground {
XCUIApplication* app = self.app;
XCUIElement* menu = app.buttons[@"Show menu"];
if (![menu waitForExistenceWithTimeout:30.0]) {
os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription);
XCTFail(@"Failed due to not able to find menu");
}
[menu tap];

XCUIElement* transparentBackground = app.buttons[@"Transparent background example"];
if (![transparentBackground waitForExistenceWithTimeout:30.0]) {
os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription);
XCTFail(@"Failed due to not able to find Transparent background example");
}
[transparentBackground tap];

XCUIElement* transparentBackgroundLoaded =
app.webViews.staticTexts[@"Transparent background test"];
if (![transparentBackgroundLoaded waitForExistenceWithTimeout:30.0]) {
os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription);
XCTFail(@"Failed due to not able to find Transparent background test");
}

XCUIScreenshot* screenshot = [[XCUIScreen mainScreen] screenshot];

UIImage* screenshotImage = screenshot.image;
CGImageRef screenshotCGImage = screenshotImage.CGImage;
UIColor* centerLeftColor =
getPixelColorInImage(screenshotCGImage, 0, CGImageGetHeight(screenshotCGImage) / 2);
UIColor* centerColor =
getPixelColorInImage(screenshotCGImage, CGImageGetWidth(screenshotCGImage) / 2,
CGImageGetHeight(screenshotCGImage) / 2);

CGColorSpaceRef centerLeftColorSpace = CGColorGetColorSpace(centerLeftColor.CGColor);
// Flutter Colors.green color : 0xFF4CAF50 -> rgba(76, 175, 80, 1)
// 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)
CGFloat flutterGreenColorComponents[] = {38.0f / 255.0f, 87.0f / 255.0f, 40.0f / 255.0f, 1.0f};
CGColorRef flutterGreenColor = CGColorCreate(centerLeftColorSpace, flutterGreenColorComponents);
CGFloat redColorComponents[] = {1.0f, 0.0f, 0.0f, 1.0f};
CGColorRef redColor = CGColorCreate(centerLeftColorSpace, redColorComponents);
CGColorSpaceRelease(centerLeftColorSpace);

XCTAssertTrue(CGColorEqualToColor(flutterGreenColor, centerLeftColor.CGColor));
XCTAssertTrue(CGColorEqualToColor(redColor, centerColor.CGColor));
}

- (void)testUserAgent {
XCUIApplication* app = self.app;
XCUIElement* menu = app.buttons[@"Show menu"];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,27 @@ The navigation delegate is set to block navigation to the youtube website.
</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>
''';

const String kLocalFileExamplePage = '''
<!DOCTYPE html>
<html lang="en">
Expand All @@ -47,8 +68,8 @@ const String kLocalFileExamplePage = '''
<h1>Local demo page</h1>
<p>
This is an example page used to demonstrate how to load a local file or HTML
string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
This is an example page used to demonstrate how to load a local file or HTML
string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
webview</a> plugin.
</p>
Expand All @@ -70,6 +91,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 All @@ -96,6 +118,7 @@ class _WebViewExampleState extends State<_WebViewExample> {
print('allowing navigation to $request');
return NavigationDecision.navigate;
},
backgroundColor: const Color(0x80000000),
);
}),
floatingActionButton: favoriteButton(),
Expand Down Expand Up @@ -146,6 +169,7 @@ enum _MenuOptions {
loadLocalFile,
loadHtmlString,
doPostRequest,
transparentBackground,
}

class _SampleMenu extends StatelessWidget {
Expand All @@ -160,6 +184,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 @@ -192,6 +217,9 @@ class _SampleMenu extends StatelessWidget {
case _MenuOptions.doPostRequest:
_onDoPostRequest(controller.data!, context);
break;
case _MenuOptions.transparentBackground:
_onTransparentBackground(controller.data!, context);
break;
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<_MenuOptions>>[
Expand Down Expand Up @@ -236,6 +264,11 @@ class _SampleMenu extends StatelessWidget {
value: _MenuOptions.doPostRequest,
child: Text('Post Request'),
),
const PopupMenuItem<_MenuOptions>(
key: ValueKey<String>('ShowTransparentBackgroundExample'),
value: _MenuOptions.transparentBackground,
child: Text('Transparent background example'),
),
],
);
},
Expand Down Expand Up @@ -346,6 +379,11 @@ class _SampleMenu extends StatelessWidget {
);
}

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

static Future<String> _prepareLocalFile() async {
final String tmpDir = (await getTemporaryDirectory()).path;
final File indexFile = File('$tmpDir/www/index.html');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,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 @@ -227,6 +228,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 @@ -278,6 +285,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 @@ -10,7 +10,7 @@ dependencies:
sdk: flutter

path_provider: ^2.0.6

webview_flutter_wkwebview:
# When depending on this package from a real application you should use:
# webview_flutter: ^x.y.z
Expand All @@ -34,4 +34,3 @@ flutter:
assets:
- assets/sample_audio.ogg
- assets/sample_video.mp4

Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ - (instancetype)initWithFrame:(CGRect)frame
inConfiguration:configuration];

_webView = [[FLTWKWebView alloc] initWithFrame:frame configuration:configuration];

// Background color
NSNumber* backgroundColorNSNumber = args[@"backgroundColor"];
if ([backgroundColorNSNumber isKindOfClass:[NSNumber class]]) {
int backgroundColorInt = [backgroundColorNSNumber intValue];
UIColor* backgroundColor = [UIColor colorWithRed:(backgroundColorInt >> 16 & 0xff) / 255.0
green:(backgroundColorInt >> 8 & 0xff) / 255.0
blue:(backgroundColorInt & 0xff) / 255.0
alpha:(backgroundColorInt >> 24 & 0xff) / 255.0];
_webView.opaque = NO;
_webView.backgroundColor = UIColor.clearColor;
_webView.scrollView.backgroundColor = backgroundColor;
}

_navigationDelegate = [[FLTWKNavigationDelegate alloc] initWithChannel:_channel];
_webView.UIDelegate = self;
_webView.navigationDelegate = _navigationDelegate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter_wkwebview
description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_wkwebview
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
version: 2.4.0
version: 2.5.0

environment:
sdk: ">=2.14.0 <3.0.0"
Expand All @@ -18,11 +18,11 @@ flutter:
dependencies:
flutter:
sdk: flutter
webview_flutter_platform_interface: ^1.5.2
webview_flutter_platform_interface: ^1.7.0

dev_dependencies:
flutter_driver:
sdk: flutter
flutter_test:
sdk: flutter
pedantic: ^1.10.0
pedantic: ^1.10.0

0 comments on commit 1e5b61c

Please sign in to comment.