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

Commit c32b27b

Browse files
authored
[webview_flutter] Add a backgroundColor option to the iOS webview (#4570)
This PR add an option to set the background color of the iOS webview. Part of #3431 Part of flutter/flutter#29300
1 parent 178e365 commit c32b27b

7 files changed

Lines changed: 136 additions & 9 deletions

File tree

packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 2.5.0
22

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

2324
## 2.0.14
2425

25-
* 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).
26+
* 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).
2627

2728
## 2.0.13
2829

packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerUITests/FLTWebViewUITests.m

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@
55
@import XCTest;
66
@import os.log;
77

8+
static UIColor* getPixelColorInImage(CGImageRef image, size_t x, size_t y) {
9+
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image));
10+
const UInt8* data = CFDataGetBytePtr(pixelData);
11+
12+
size_t bytesPerRow = CGImageGetBytesPerRow(image);
13+
size_t pixelInfo = (bytesPerRow * y) + (x * 4); // 4 bytes per pixel
14+
15+
UInt8 red = data[pixelInfo + 0];
16+
UInt8 green = data[pixelInfo + 1];
17+
UInt8 blue = data[pixelInfo + 2];
18+
UInt8 alpha = data[pixelInfo + 3];
19+
CFRelease(pixelData);
20+
21+
return [UIColor colorWithRed:red / 255.0f
22+
green:green / 255.0f
23+
blue:blue / 255.0f
24+
alpha:alpha / 255.0f];
25+
}
26+
827
@interface FLTWebViewUITests : XCTestCase
928
@property(nonatomic, strong) XCUIApplication* app;
1029
@end
@@ -18,6 +37,54 @@ - (void)setUp {
1837
[self.app launch];
1938
}
2039

40+
- (void)testTransparentBackground {
41+
XCUIApplication* app = self.app;
42+
XCUIElement* menu = app.buttons[@"Show menu"];
43+
if (![menu waitForExistenceWithTimeout:30.0]) {
44+
os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription);
45+
XCTFail(@"Failed due to not able to find menu");
46+
}
47+
[menu tap];
48+
49+
XCUIElement* transparentBackground = app.buttons[@"Transparent background example"];
50+
if (![transparentBackground waitForExistenceWithTimeout:30.0]) {
51+
os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription);
52+
XCTFail(@"Failed due to not able to find Transparent background example");
53+
}
54+
[transparentBackground tap];
55+
56+
XCUIElement* transparentBackgroundLoaded =
57+
app.webViews.staticTexts[@"Transparent background test"];
58+
if (![transparentBackgroundLoaded waitForExistenceWithTimeout:30.0]) {
59+
os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription);
60+
XCTFail(@"Failed due to not able to find Transparent background test");
61+
}
62+
63+
XCUIScreenshot* screenshot = [[XCUIScreen mainScreen] screenshot];
64+
65+
UIImage* screenshotImage = screenshot.image;
66+
CGImageRef screenshotCGImage = screenshotImage.CGImage;
67+
UIColor* centerLeftColor =
68+
getPixelColorInImage(screenshotCGImage, 0, CGImageGetHeight(screenshotCGImage) / 2);
69+
UIColor* centerColor =
70+
getPixelColorInImage(screenshotCGImage, CGImageGetWidth(screenshotCGImage) / 2,
71+
CGImageGetHeight(screenshotCGImage) / 2);
72+
73+
CGColorSpaceRef centerLeftColorSpace = CGColorGetColorSpace(centerLeftColor.CGColor);
74+
// Flutter Colors.green color : 0xFF4CAF50 -> rgba(76, 175, 80, 1)
75+
// https://github.com/flutter/flutter/blob/f4abaa0735eba4dfd8f33f73363911d63931fe03/packages/flutter/lib/src/material/colors.dart#L1208
76+
// The background color of the webview is : rgba(0, 0, 0, 0.5)
77+
// The expected color is : rgba(38, 87, 40, 1)
78+
CGFloat flutterGreenColorComponents[] = {38.0f / 255.0f, 87.0f / 255.0f, 40.0f / 255.0f, 1.0f};
79+
CGColorRef flutterGreenColor = CGColorCreate(centerLeftColorSpace, flutterGreenColorComponents);
80+
CGFloat redColorComponents[] = {1.0f, 0.0f, 0.0f, 1.0f};
81+
CGColorRef redColor = CGColorCreate(centerLeftColorSpace, redColorComponents);
82+
CGColorSpaceRelease(centerLeftColorSpace);
83+
84+
XCTAssertTrue(CGColorEqualToColor(flutterGreenColor, centerLeftColor.CGColor));
85+
XCTAssertTrue(CGColorEqualToColor(redColor, centerColor.CGColor));
86+
}
87+
2188
- (void)testUserAgent {
2289
XCUIApplication* app = self.app;
2390
XCUIElement* menu = app.buttons[@"Show menu"];

packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,27 @@ The navigation delegate is set to block navigation to the youtube website.
3737
</html>
3838
''';
3939

40+
const String kTransparentBackgroundPage = '''
41+
<!DOCTYPE html>
42+
<html>
43+
<head>
44+
<title>Transparent background test</title>
45+
</head>
46+
<style type="text/css">
47+
body { background: transparent; margin: 0; padding: 0; }
48+
#container { position: relative; margin: 0; padding: 0; width: 100vw; height: 100vh; }
49+
#shape { background: #FF0000; width: 200px; height: 100%; margin: 0; padding: 0; position: absolute; top: 0; bottom: 0; left: calc(50% - 100px); }
50+
p { text-align: center; }
51+
</style>
52+
<body>
53+
<div id="container">
54+
<p>Transparent background test</p>
55+
<div id="shape"></div>
56+
</div>
57+
</body>
58+
</html>
59+
''';
60+
4061
const String kLocalFileExamplePage = '''
4162
<!DOCTYPE html>
4263
<html lang="en">
@@ -47,8 +68,8 @@ const String kLocalFileExamplePage = '''
4768
4869
<h1>Local demo page</h1>
4970
<p>
50-
This is an example page used to demonstrate how to load a local file or HTML
51-
string using the <a href="proxy.php?url=https%3A%2F%2Fpub.dev%2Fpackages%2Fwebview_flutter">Flutter
71+
This is an example page used to demonstrate how to load a local file or HTML
72+
string using the <a href="proxy.php?url=https%3A%2F%2Fpub.dev%2Fpackages%2Fwebview_flutter">Flutter
5273
webview</a> plugin.
5374
</p>
5475
@@ -70,6 +91,7 @@ class _WebViewExampleState extends State<_WebViewExample> {
7091
@override
7192
Widget build(BuildContext context) {
7293
return Scaffold(
94+
backgroundColor: const Color(0xFF4CAF50),
7395
appBar: AppBar(
7496
title: const Text('Flutter WebView example'),
7597
// This drop down menu demonstrates that Flutter widgets can be shown over the web view.
@@ -96,6 +118,7 @@ class _WebViewExampleState extends State<_WebViewExample> {
96118
print('allowing navigation to $request');
97119
return NavigationDecision.navigate;
98120
},
121+
backgroundColor: const Color(0x80000000),
99122
);
100123
}),
101124
floatingActionButton: favoriteButton(),
@@ -146,6 +169,7 @@ enum _MenuOptions {
146169
loadLocalFile,
147170
loadHtmlString,
148171
doPostRequest,
172+
transparentBackground,
149173
}
150174

151175
class _SampleMenu extends StatelessWidget {
@@ -160,6 +184,7 @@ class _SampleMenu extends StatelessWidget {
160184
builder:
161185
(BuildContext context, AsyncSnapshot<WebViewController> controller) {
162186
return PopupMenuButton<_MenuOptions>(
187+
key: const ValueKey<String>('ShowPopupMenu'),
163188
onSelected: (_MenuOptions value) {
164189
switch (value) {
165190
case _MenuOptions.showUserAgent:
@@ -192,6 +217,9 @@ class _SampleMenu extends StatelessWidget {
192217
case _MenuOptions.doPostRequest:
193218
_onDoPostRequest(controller.data!, context);
194219
break;
220+
case _MenuOptions.transparentBackground:
221+
_onTransparentBackground(controller.data!, context);
222+
break;
195223
}
196224
},
197225
itemBuilder: (BuildContext context) => <PopupMenuItem<_MenuOptions>>[
@@ -236,6 +264,11 @@ class _SampleMenu extends StatelessWidget {
236264
value: _MenuOptions.doPostRequest,
237265
child: Text('Post Request'),
238266
),
267+
const PopupMenuItem<_MenuOptions>(
268+
key: ValueKey<String>('ShowTransparentBackgroundExample'),
269+
value: _MenuOptions.transparentBackground,
270+
child: Text('Transparent background example'),
271+
),
239272
],
240273
);
241274
},
@@ -346,6 +379,11 @@ class _SampleMenu extends StatelessWidget {
346379
);
347380
}
348381

382+
Future<void> _onTransparentBackground(
383+
WebViewController controller, BuildContext context) async {
384+
await controller.loadHtmlString(kTransparentBackgroundPage);
385+
}
386+
349387
static Future<String> _prepareLocalFile() async {
350388
final String tmpDir = (await getTemporaryDirectory()).path;
351389
final File indexFile = File('$tmpDir/www/index.html');

packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class WebView extends StatefulWidget {
6969
this.initialMediaPlaybackPolicy =
7070
AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
7171
this.allowsInlineMediaPlayback = false,
72+
this.backgroundColor,
7273
}) : assert(javascriptMode != null),
7374
assert(initialMediaPlaybackPolicy != null),
7475
assert(allowsInlineMediaPlayback != null),
@@ -227,6 +228,12 @@ class WebView extends StatefulWidget {
227228
/// The default policy is [AutoMediaPlaybackPolicy.require_user_action_for_all_media_types].
228229
final AutoMediaPlaybackPolicy initialMediaPlaybackPolicy;
229230

231+
/// The background color of the [WebView].
232+
///
233+
/// When `null` the platform's webview default background color is used. By
234+
/// default [backgroundColor] is `null`.
235+
final Color? backgroundColor;
236+
230237
@override
231238
_WebViewState createState() => _WebViewState();
232239
}
@@ -278,6 +285,7 @@ class _WebViewState extends State<WebView> {
278285
_javascriptChannelRegistry.channels.keys.toSet(),
279286
autoMediaPlaybackPolicy: widget.initialMediaPlaybackPolicy,
280287
userAgent: widget.userAgent,
288+
backgroundColor: widget.backgroundColor,
281289
),
282290
javascriptChannelRegistry: _javascriptChannelRegistry,
283291
);

packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies:
1010
sdk: flutter
1111

1212
path_provider: ^2.0.6
13-
13+
1414
webview_flutter_wkwebview:
1515
# When depending on this package from a real application you should use:
1616
# webview_flutter: ^x.y.z
@@ -34,4 +34,3 @@ flutter:
3434
assets:
3535
- assets/sample_audio.ogg
3636
- assets/sample_video.mp4
37-

packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,20 @@ - (instancetype)initWithFrame:(CGRect)frame
9696
inConfiguration:configuration];
9797

9898
_webView = [[FLTWKWebView alloc] initWithFrame:frame configuration:configuration];
99+
100+
// Background color
101+
NSNumber* backgroundColorNSNumber = args[@"backgroundColor"];
102+
if ([backgroundColorNSNumber isKindOfClass:[NSNumber class]]) {
103+
int backgroundColorInt = [backgroundColorNSNumber intValue];
104+
UIColor* backgroundColor = [UIColor colorWithRed:(backgroundColorInt >> 16 & 0xff) / 255.0
105+
green:(backgroundColorInt >> 8 & 0xff) / 255.0
106+
blue:(backgroundColorInt & 0xff) / 255.0
107+
alpha:(backgroundColorInt >> 24 & 0xff) / 255.0];
108+
_webView.opaque = NO;
109+
_webView.backgroundColor = UIColor.clearColor;
110+
_webView.scrollView.backgroundColor = backgroundColor;
111+
}
112+
99113
_navigationDelegate = [[FLTWKNavigationDelegate alloc] initWithChannel:_channel];
100114
_webView.UIDelegate = self;
101115
_webView.navigationDelegate = _navigationDelegate;

packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter_wkwebview
22
description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
33
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_wkwebview
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 2.4.0
5+
version: 2.5.0
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"
@@ -18,11 +18,11 @@ flutter:
1818
dependencies:
1919
flutter:
2020
sdk: flutter
21-
webview_flutter_platform_interface: ^1.5.2
21+
webview_flutter_platform_interface: ^1.7.0
2222

2323
dev_dependencies:
2424
flutter_driver:
2525
sdk: flutter
2626
flutter_test:
2727
sdk: flutter
28-
pedantic: ^1.10.0
28+
pedantic: ^1.10.0

0 commit comments

Comments
 (0)