Skip to content

Conversation

@gaaclarke
Copy link
Member

@gaaclarke gaaclarke commented May 20, 2025

fixes #169218

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

FlutterAppDelegate.window.rootViewController in launch functions.
@github-actions github-actions bot added tool Affects the "flutter" command-line tool. See also t: labels. team-ios Owned by iOS platform team labels May 20, 2025
@github-actions github-actions bot added the d: examples Sample code and demos label May 20, 2025
@github-actions github-actions bot added platform-ios iOS applications specifically and removed d: examples Sample code and demos labels May 21, 2025
@gaaclarke gaaclarke force-pushed the launch-viewcontroller-warning branch from ffb0565 to 01d385a Compare May 21, 2025 18:27
@github-actions github-actions bot added platform-ios iOS applications specifically and removed platform-ios iOS applications specifically labels May 21, 2025
@gaaclarke
Copy link
Member Author

@vashworth This behaves like we'd want it but isn't quite done. We have to make a decision about how to wrap this up:

  1. We continue down this path of looking for warning tags and I tweak mac.dart to print out my warnings but also throw them away from the build result (right now we don't throw them out but print them out).
  2. We run the check for the warning twice, once from the xcodebuild script and once from the flutter cli.
  3. Maybe you have another idea?

Let me know what you are thinking.

@gaaclarke gaaclarke requested a review from vashworth May 21, 2025 22:55
@vashworth
Copy link
Contributor

vashworth commented May 22, 2025

@vashworth This behaves like we'd want it but isn't quite done. We have to make a decision about how to wrap this up:

  1. We continue down this path of looking for warning tags and I tweak mac.dart to print out my warnings but also throw them away from the build result (right now we don't throw them out but print them out).
  2. We run the check for the warning twice, once from the xcodebuild script and once from the flutter cli.
  3. Maybe you have another idea?

Let me know what you are thinking.

Okay here's what I would do

I would change this

if (resultStderr.isNotEmpty) {
final StringBuffer errorOutput = StringBuffer();
if (result.exitCode != 0) {
// "error:" prefix makes this show up as an Xcode compilation error.
errorOutput.write('error: ');
}
errorOutput.write(resultStderr);
echoError(errorOutput.toString());
}

to

    if (resultStderr.isNotEmpty) {
      final StringBuffer errorOutput = StringBuffer();
      if (result.exitCode != 0) {
        // "error:" prefix makes this show up as an Xcode compilation error.
        errorOutput.write('error: ');
      }
      errorOutput.write(resultStderr);
      echoError(errorOutput.toString());

+      // Stream stderr to the Flutter build process.
+      // When in verbose mode, `echoError` above will show the logs. So only
+      // stream if not in verbose mode to avoid duplicate logs.
+      // Also, only stream if exitCode is 0 since errors are handled separately
+      // by the tool on failure.
+      if (!verbose && exitCode == 0) {
+        streamOutput(errorOutput.toString());
+      }
    }

And change this

} else {
initialBuildStatus?.cancel();
initialBuildStatus = null;
buildSubStatus = globals.logger.startProgress(
line,
progressIndicatorPadding: kDefaultStatusPadding - 7,
);
}

to

          } else {
+            if (!globals.logger.isVerbose) {
+              if (line.contains('error:')) {
+                globals.printError(line);
+              } else if (line.contains('warning:')) {
+                globals.printWarning(line);
+              }
+              continue;
+            }
            initialBuildStatus?.cancel();
            initialBuildStatus = null;
            buildSubStatus = globals.logger.startProgress(
              line,
              progressIndicatorPadding: kDefaultStatusPadding - 7,
            );
          }

I tested it out and that works for me, but let me know if you run into problems

@gaaclarke
Copy link
Member Author

@vashworth okay, so forwarding warning print statements to stdout only for that subprocess and avoiding the xcresult altogether. That works except it chops off the extra context that follows the warning, all the stuff in the note: block. I'll see if I can get this working the way we want.

@gaaclarke gaaclarke force-pushed the launch-viewcontroller-warning branch from a2e149e to d16d2f9 Compare May 22, 2025 21:28
@gaaclarke gaaclarke marked this pull request as ready for review May 22, 2025 21:35
@gaaclarke gaaclarke requested a review from a team as a code owner May 22, 2025 21:35
@gaaclarke
Copy link
Member Author

@vashworth this is ready to review now. Let me know if you have a good idea on a more complete integration test.

@gaaclarke
Copy link
Member Author

friendly ping @hellohuanlin @vashworth

@vashworth
Copy link
Contributor

Let me know if you have a good idea on a more complete integration test.

I think you can do something like this for integration testing:
https://github.com/flutter/flutter/blob/master/packages/flutter_tools/test/integration.shard/xcode_dev_dependencies_test.dart

Basically, create an app, alter the AppDelegate to have the rootViewController code, then build (either flutter build or xcodebuild or both) and check the stdout/stderr for the warnings

await _checkForLaunchRootViewControllerAccessDeprecation(
logger,
file,
RegExp('self.*?window.*?rootViewController'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also check if they're casting it to a FlutterViewController.

Suggested change
RegExp('self.*?window.*?rootViewController'),
RegExp('FlutterViewController.*?self.*?window.*?rootViewController'),

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so because in objc id is a valid type. I'm also concerned about newlines:

id viewController = self.window.rootViewController;
FlutterViewController* vc = (FlutterViewController*)
  self.window.rootViewController;

logger,
file,
RegExp('self.*?window.*?rootViewController'),
RegExp('^}'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we check for any terminator? We don't know if they're properly formatted. I'd lean on the side of catching fewer than catching too many, but I don't feel too strongly about it.

Suggested change
RegExp('^}'),
RegExp('}'),

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caret is necessary to identify the whole block for the method (the caret means matching the beginning of the line).

await _checkForLaunchRootViewControllerAccessDeprecation(
logger,
file,
'window?.rootViewController',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'window?.rootViewController',
'window?.rootViewController.*?FlutterViewController',

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't do this because I wanted to catch things like this:

analyticsLibrary.viewController = window?.rootViewController

globals.printWarning(line);
inNoteBlock = false;
} else if (inWarningBlock) {
if (line.startsWith(RegExp(r'\s+?note[:]'))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (line.startsWith(RegExp(r'\s+?note[:]'))) {
if (line.startsWith(RegExp(r'\s*?note[:]\s*?$'))) {

Notes can also be a single line. This regex shouldn't match if it is

note: hello world

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now this is the only instance of printing notes in our script and we don't ever do that. What I found was that Xcode's parser was ripping out the note: line. I spent a couple hours fiddling with it and this was the best I could get. I think we should have the more specific regex for now and only change it if we need to support it in the future.

inNoteBlock = false;
} else if (inWarningBlock) {
if (line.startsWith(RegExp(r'\s+?note[:]'))) {
// Xcode doesn't echo this, so we don't.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Xcode doesn't echo notes? I'm pretty sure it does...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That "note:" line in particular it doesn't. I fought with it for a while. It's a black box.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(notice the "note:" line isn't echoed)

Screenshot 2025-05-29 at 2 11 01 PM

gaaclarke and others added 2 commits May 29, 2025 13:30
Co-authored-by: Victoria Ashworth <15619084+vashworth@users.noreply.github.com>
Co-authored-by: Victoria Ashworth <15619084+vashworth@users.noreply.github.com>
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 3, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 3, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 3, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 3, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 3, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 4, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 4, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 4, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 4, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 4, 2025
@FelixMittermeier
Copy link

FelixMittermeier commented Jun 4, 2025

Hello @gaaclarke, I wonder if it's required to change anything in our apps now since this merge? I previously used master and everything was fine but since this commit is included my app works in debug mode - but instantly crashes in release mode.

According to https://docs.google.com/document/d/1ZfcQOs-UKRa9jsFG84-MTFeibZTLKCvPQLxF2eskx44/edit?tab=t.0 I understood it like the info.plist has to be updated to include:

<key>UISceneDelegateClassName</key>
<string>FlutterSceneDelegate</string>

and the AppDelegate.swift file needs to be changed from:

import Flutter
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

to

import Flutter
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate {

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  @objc override func registerLaunchPlugins() {
    GeneratedPluginRegistrant.register(with: self)
  }
}

This swift code change resulted in an Swift Compiler Error (Xcode): Method does not override any method from its superclass for me using the latest flutter master version from today.
I also tried only the info.plist change without the swift code change but unfortunately the app still directly crashes. Am I doing something wrong?

Any help or hint would be much appreciated, thanks a lot.

More information:
I am using these plugins:

FPPDeviceInfoPlusPlugin, FLTFirebaseAnalyticsPlugin, FLTFirebaseCorePlugin, SmartlookPlugin, GeolocatorPlugin, InAppReviewPlugin, MapboxMapsPlugin, FPPPackageInfoPlusPlugin, PathProviderPlugin, PermissionHandlerPlugin, SentryFlutterPlugin, FPPSharePlusPlugin, SqflitePlugin, SuperwallkitFlutterPlugin, URLLauncherPlugin

Flutter version:

Flutter 3.33.0-1.0.pre.380 • channel master • https://github.com/flutter/flutter.git
Framework • revision 27d9c0f (2 hours ago) • 2025-06-04 16:21:20 -0400
Engine • revision 27d9c0f (2 hours ago) • 2025-06-04 16:21:20 -0400
Tools • Dart 3.9.0 (build 3.9.0-196.0.dev) • DevTools 2.47.0

@gaaclarke
Copy link
Member Author

Hello @gaaclarke, I wonder if it's required to change anything in our apps now since this merge? I previously used master and everything was fine but since this commit is included my app works in debug mode - but instantly crashes in release mode.

It depends, maybe not. There is a PR open for the migration guide: flutter/website#12082

Please give that a look and hopefully that clears everything up for you.

@FelixMittermeier
Copy link

Hello @gaaclarke, I wonder if it's required to change anything in our apps now since this merge? I previously used master and everything was fine but since this commit is included my app works in debug mode - but instantly crashes in release mode.

It depends, maybe not. There is a PR open for the migration guide: flutter/website#12082

Please give that a look and hopefully that clears everything up for you.

Spent a couple of hours trying to find the reason for the crash and turned it out it's unrelated to this topic. Created a new ticket: #170038

I will try to provide more information soon. Thanks for your quick answer anyway.

engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform-ios iOS applications specifically team-ios Owned by iOS platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ios]: Make deprecation notice for accessing rootViewController at launch

3 participants