diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 61a568c9aa1..3659a50c0a6 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.2.5 + +* Removes use of deprecated `renderView` API. + ## 6.2.4 * Updates support matrix in README to indicate that iOS 11 is no longer supported. diff --git a/packages/url_launcher/url_launcher/lib/src/legacy_api.dart b/packages/url_launcher/url_launcher/lib/src/legacy_api.dart index 9f6d2dca001..f709a75f758 100644 --- a/packages/url_launcher/url_launcher/lib/src/legacy_api.dart +++ b/packages/url_launcher/url_launcher/lib/src/legacy_api.dart @@ -3,8 +3,10 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:ui'; import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; @@ -85,15 +87,14 @@ Future launch( /// [true] so that ui is automatically computed if [statusBarBrightness] is set. bool previousAutomaticSystemUiAdjustment = true; - if (statusBarBrightness != null && - defaultTargetPlatform == TargetPlatform.iOS && - _ambiguate(WidgetsBinding.instance) != null) { - previousAutomaticSystemUiAdjustment = _ambiguate(WidgetsBinding.instance)! - .renderView - .automaticSystemUiAdjustment; - _ambiguate(WidgetsBinding.instance)! - .renderView - .automaticSystemUiAdjustment = false; + final RenderView? renderViewToAdjust = + statusBarBrightness != null && defaultTargetPlatform == TargetPlatform.iOS + ? _findImplicitRenderView() + : null; + if (renderViewToAdjust != null) { + previousAutomaticSystemUiAdjustment = + renderViewToAdjust.automaticSystemUiAdjustment; + renderViewToAdjust.automaticSystemUiAdjustment = false; SystemChrome.setSystemUIOverlayStyle(statusBarBrightness == Brightness.light ? SystemUiOverlayStyle.dark : SystemUiOverlayStyle.light); @@ -110,11 +111,9 @@ Future launch( webOnlyWindowName: webOnlyWindowName, ); - if (statusBarBrightness != null && - _ambiguate(WidgetsBinding.instance) != null) { - _ambiguate(WidgetsBinding.instance)! - .renderView - .automaticSystemUiAdjustment = previousAutomaticSystemUiAdjustment; + if (renderViewToAdjust != null) { + renderViewToAdjust.automaticSystemUiAdjustment = + previousAutomaticSystemUiAdjustment; } return result; @@ -146,8 +145,22 @@ Future closeWebView() async { return UrlLauncherPlatform.instance.closeWebView(); } -/// This allows a value of type T or T? to be treated as a value of type T?. +/// Returns the [RenderView] associated with the implicit [FlutterView], if any. /// -/// We use this so that APIs that have become non-nullable can still be used -/// with `!` and `?` on the stable branch. -T? _ambiguate(T? value) => value; +/// [launch] predates multi-window support, and it doesn't have enough context +/// to get the right render view, so this assumes anyone still trying to use +/// the deprecated API with `statusBarBrightness` is in a single-view scenario. +/// This allows a best-effort implementation of the deprecated API for as long +/// as it continues to exist, without depending on deprecated Flutter APIs (and +/// therefore keeping url_launcher forward-compatible with future versions of +/// Flutter for longer). +RenderView? _findImplicitRenderView() { + final FlutterView? implicitFlutterView = + WidgetsBinding.instance.platformDispatcher.implicitView; + if (implicitFlutterView == null) { + return null; + } + return WidgetsBinding.instance.renderViews + .where((RenderView v) => v.flutterView == implicitFlutterView) + .firstOrNull; +} diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index fe3f2990d08..e59afe4690d 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -3,11 +3,11 @@ description: Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes. repository: https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22 -version: 6.2.4 +version: 6.2.5 environment: - sdk: ">=3.1.0 <4.0.0" - flutter: ">=3.13.0" + sdk: ">=3.2.0 <4.0.0" + flutter: ">=3.16.0" flutter: plugin: diff --git a/packages/url_launcher/url_launcher/test/src/legacy_api_test.dart b/packages/url_launcher/url_launcher/test/src/legacy_api_test.dart index 8a694546397..091f9b7c8fd 100644 --- a/packages/url_launcher/url_launcher/test/src/legacy_api_test.dart +++ b/packages/url_launcher/url_launcher/test/src/legacy_api_test.dart @@ -235,10 +235,11 @@ void main() { ..setResponse(true); final TestWidgetsFlutterBinding binding = - _anonymize(TestWidgetsFlutterBinding.ensureInitialized())! - as TestWidgetsFlutterBinding; + TestWidgetsFlutterBinding.ensureInitialized(); debugDefaultTargetPlatformOverride = TargetPlatform.iOS; - final RenderView renderView = binding.renderView; + final RenderView renderView = + RenderView(view: binding.platformDispatcher.implicitView!); + binding.addRenderView(renderView); renderView.automaticSystemUiAdjustment = true; final Future launchResult = launch('http://flutter.dev/', statusBarBrightness: Brightness.dark); @@ -248,6 +249,7 @@ void main() { expect(renderView.automaticSystemUiAdjustment, isFalse); await launchResult; expect(renderView.automaticSystemUiAdjustment, isTrue); + binding.removeRenderView(renderView); }); test('sets automaticSystemUiAdjustment to not be null', () async { @@ -265,10 +267,11 @@ void main() { ..setResponse(true); final TestWidgetsFlutterBinding binding = - _anonymize(TestWidgetsFlutterBinding.ensureInitialized())! - as TestWidgetsFlutterBinding; + TestWidgetsFlutterBinding.ensureInitialized(); debugDefaultTargetPlatformOverride = TargetPlatform.android; - final RenderView renderView = binding.renderView; + final RenderView renderView = + RenderView(view: binding.platformDispatcher.implicitView!); + binding.addRenderView(renderView); expect(renderView.automaticSystemUiAdjustment, true); final Future launchResult = launch('http://flutter.dev/', statusBarBrightness: Brightness.dark); @@ -278,6 +281,7 @@ void main() { expect(renderView.automaticSystemUiAdjustment, true); await launchResult; expect(renderView.automaticSystemUiAdjustment, true); + binding.removeRenderView(renderView); }); test('open non-parseable url', () async { @@ -317,9 +321,3 @@ void main() { }); }); } - -/// This removes the type information from a value so that it can be cast -/// to another type even if that cast is redundant. -/// We use this so that APIs whose type have become more descriptive can still -/// be used on the stable branch where they require a cast. -Object? _anonymize(T? value) => value;