diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index e9c59c26c3ce..22f45f27c4d7 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -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. @@ -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 diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerUITests/FLTWebViewUITests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerUITests/FLTWebViewUITests.m index d193be745972..e43fb97d41ef 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerUITests/FLTWebViewUITests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerUITests/FLTWebViewUITests.m @@ -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 @@ -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"]; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart index df85d42bea8f..41297bfd94fe 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart @@ -37,6 +37,27 @@ The navigation delegate is set to block navigation to the youtube website. '''; +const String kTransparentBackgroundPage = ''' + + + + Transparent background test + + + +
+

Transparent background test

+
+
+ + +'''; + const String kLocalFileExamplePage = ''' @@ -47,8 +68,8 @@ const String kLocalFileExamplePage = '''

Local demo page

- This is an example page used to demonstrate how to load a local file or HTML - string using the Flutter + This is an example page used to demonstrate how to load a local file or HTML + string using the Flutter webview plugin.

@@ -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. @@ -96,6 +118,7 @@ class _WebViewExampleState extends State<_WebViewExample> { print('allowing navigation to $request'); return NavigationDecision.navigate; }, + backgroundColor: const Color(0x80000000), ); }), floatingActionButton: favoriteButton(), @@ -146,6 +169,7 @@ enum _MenuOptions { loadLocalFile, loadHtmlString, doPostRequest, + transparentBackground, } class _SampleMenu extends StatelessWidget { @@ -160,6 +184,7 @@ class _SampleMenu extends StatelessWidget { builder: (BuildContext context, AsyncSnapshot controller) { return PopupMenuButton<_MenuOptions>( + key: const ValueKey('ShowPopupMenu'), onSelected: (_MenuOptions value) { switch (value) { case _MenuOptions.showUserAgent: @@ -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) => >[ @@ -236,6 +264,11 @@ class _SampleMenu extends StatelessWidget { value: _MenuOptions.doPostRequest, child: Text('Post Request'), ), + const PopupMenuItem<_MenuOptions>( + key: ValueKey('ShowTransparentBackgroundExample'), + value: _MenuOptions.transparentBackground, + child: Text('Transparent background example'), + ), ], ); }, @@ -346,6 +379,11 @@ class _SampleMenu extends StatelessWidget { ); } + Future _onTransparentBackground( + WebViewController controller, BuildContext context) async { + await controller.loadHtmlString(kTransparentBackgroundPage); + } + static Future _prepareLocalFile() async { final String tmpDir = (await getTemporaryDirectory()).path; final File indexFile = File('$tmpDir/www/index.html'); diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart index ae540ae23c2d..69fa2bdb79e3 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart @@ -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), @@ -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(); } @@ -278,6 +285,7 @@ class _WebViewState extends State { _javascriptChannelRegistry.channels.keys.toSet(), autoMediaPlaybackPolicy: widget.initialMediaPlaybackPolicy, userAgent: widget.userAgent, + backgroundColor: widget.backgroundColor, ), javascriptChannelRegistry: _javascriptChannelRegistry, ); diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml index 2888cddac552..2070b1161ba0 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml @@ -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 @@ -34,4 +34,3 @@ flutter: assets: - assets/sample_audio.ogg - assets/sample_video.mp4 - \ No newline at end of file diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m index 351d1ae58760..25a93a67addc 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m @@ -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; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index a152e2ba2882..702473382793 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -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" @@ -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 \ No newline at end of file + pedantic: ^1.10.0