Skip to content

Conversation

@jmagman
Copy link
Member

@jmagman jmagman commented Feb 26, 2020

Description

Xcode 11.4 changed its behavior to require linked and embedded frameworks (App.framework and Flutter.framework) to have the right architecture BEFORE the Flutter script can run. So building against the simulator would work, then the next time building against a real device it would just fail:

Linked and embedded framework 'App.framework' was built for iOS Simulator

and vice versa from real device to simulator:

Linked and embedded framework 'App.framework' was built for iOS

Observations

  1. App.framework doesn't need to be linked since there are no symbols.
  2. It would be better to push the linker and embedding logic down in the tool so we have more control. For example, we could distribute a Flutter.xcframework and link on that without a breaking change. Or name App.framework uniquely to support different add-to-app modules. Or we could move more things from xcode_backend into the tool. Or we could update search paths to point directly to the right build mode engine artifacts directory without copying Flutter.framework into the project.
  3. We keep needing to change the Xcode project file template (Disable CocoaPods input and output paths in Xcode build phase and adopt new Xcode build system #33684, so many more examples).
  4. Ideally this migration could be versioned, see Flutter migrate #40460. However this migration looks safe: there are unique identifiers!
  5. Since it's not versioned, the migrator will run on every flutter build ios/flutter run! However these migrations are really fast when there's no changes to make.

Changes

  • Remove App.framework and Flutter.framework link step in template build phase.
  • Add OTHER_LDFLAGS=$(inherited) -framework Flutter to Generated.xcconfig and remove Flutter.framework from linking build phase (no need add for App since there are no symbols).
  • Remove App.framework and Flutter.framework from the framework embedding build phase.
  • Add migrators to do this automatically based on the Xcode identifiers. I confirmed these are the original template identifiers (first Flutter.framework was Finish integrating HelloServices model on iOS #4820 and App.framework was Build Flutter app as a framework on iOS #8971).
  • Add error message and temporary workaround instructions in case the migration failed:
 Your Xcode project requires migration. See https://github.com/flutter/flutter/issues/50568 for details.
 
 You can temporarily work around this issue by running:
  rm -rf ios/Flutter/App.framework
  • Run the SHARD=build_tests and let all the examples migrate.

Related Issues

Fixes #50568
Fixes #32454

Tests

ios_project_migration_test, updated xcodeproj_test

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I signed the [CLA].
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

  • No, no existing tests failed, so this is not a breaking change.
  • Yes, this is a breaking change. If not, delete the remainder of this section.

@jmagman jmagman added platform-ios iOS applications specifically tool Affects the "flutter" command-line tool. See also t: labels. work in progress; do not review t: xcode "xcodebuild" on iOS and general Xcode project management labels Feb 26, 2020
@jmagman jmagman self-assigned this Feb 26, 2020
@fluttergithubbot fluttergithubbot added d: examples Sample code and demos c: contributor-productivity Team-specific productivity, code health, technical debt. customer: gallery Relating to flutter/gallery repository. Please transfer non-framework issues there. labels Feb 26, 2020
Copy link
Member Author

@jmagman jmagman Feb 26, 2020

Choose a reason for hiding this comment

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

EXPANDED_CODE_SIGN_IDENTITY is more correct, it's the resolved underlying ID as opposed to a name (on my machine the name was ambiguous)

@evolvesoft-marwan

This comment has been minimized.

@jmagman

This comment has been minimized.

Copy link
Member Author

@jmagman jmagman Feb 26, 2020

Choose a reason for hiding this comment

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

This link is temporary. I will write wiki or website instructions and update this link: flutter/website#3741

Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

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

Follow up questions:

  1. Did you use the flutter tool to migrate the examples in repo?

  2. Do we need to make a similar change to the macOS project structure? If so, that doesn't need to be done now but it would be nice to have an issue for it.

  3. Is there an issue filled for adding this information to the web site?

Re: migration time - I think this is okay provided that we're not overwriting the file if it isn't necessary. It doesn't look like this is the case in your code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is a private member with a private typedef, I would instead do the function type inline:

void _processFileLines(File file, String Function(String) processLine)

Copy link
Contributor

Choose a reason for hiding this comment

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

consider a better name, like migrateProject et cetera

Copy link
Contributor

Choose a reason for hiding this comment

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

I would add some contextual top level information about why this class exists

@jmagman
Copy link
Member Author

jmagman commented Feb 26, 2020

Follow up questions:

  1. Did you use the flutter tool to migrate the examples in repo?

Yes, all examples and tests were migrated by running flutter build ios in the right directory (or letting integration tests do it for me).

  1. Do we need to make a similar change to the macOS project structure? If so, that doesn't need to be done now but it would be nice to have an issue for it.

I think it may be a good idea to do the same pattern for macOS for the future-proofing xcframework / App.framework rename reasons I mentioned in the "Observations" section, and to remove the disable_input_output_paths hack in the macOS Podfile. However there's no immediate need to do this since Mac won't hit #50568 (there is no simulator, frameworks always have the x86 architectures, no thinning happens). I would defer to @stuartmorgan on the necessity and/or timing of that change.

  1. Is there an issue filled for adding this information to the web site?

flutter/website#3741

Re: migration time - I think this is okay provided that we're not overwriting the file if it isn't necessary. It doesn't look like this is the case in your code.

No, it doesn't overwrite the file unless there's a change. See the "skipped if nothing to upgrade" ios_project_migration_test unit test.

@jonahwilliams
Copy link
Contributor

Even if its not necessary, it would be nice to keep the macOS and iOS projects as similar as possible.

@jmagman
Copy link
Member Author

jmagman commented Feb 27, 2020

Oh another thing: this migration will prevent users from downgrading Flutter versions to before this change since OTHER_LDFLAGS won't exist in past Generated.xcconfigs... I'm not quite sure how to help with that...

I could change the script build phase to first run embed, then run thin, since that's all the new embed_and_thin is doing. embed_and_thin doesn't exist on past Flutter versions, but embed and thin do, respectively.

@jonahwilliams
Copy link
Contributor

I would recommend that if you modify the project files, to take the old sources and save them as "*.old". Then the documentation on the website/wiki can explain how to restore the project by renaming them

Copy link
Contributor

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

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

It terms of the general approach to managing the framework, this looks good to me! And capturing from offline discussion, it has the added bonus that it should make it pretty easy to solve the debug/profile/release problem with assemble that @jonahwilliams had encountered previously, since we won't be bound by Xcode's limitation of needing a single known path to the Flutter framework.

My comments are actually about the specifics of we do the migration, rather than the end result.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why do only some of the projects have these input/output path changes?

Copy link
Member Author

Choose a reason for hiding this comment

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

CocoaPods adds this in their scripting, so it's present in apps that have iOS platform code in their plugins.

Copy link
Member Author

Choose a reason for hiding this comment

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

(so projects that have Podfiles)

Copy link
Contributor

Choose a reason for hiding this comment

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

Breadcrumb for later reference: I think we can use this to fix #39659

Copy link
Member Author

@jmagman jmagman Feb 28, 2020

Choose a reason for hiding this comment

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

I would love to move most of that logic into a Ruby helper script in the project (like xcode_backend) so it (almost) never has to be upgraded again #45197

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm looking at this class and thinking about what happens when we want to add a second migration for something else later; it seems like it'll become very hard to maintain/understand pretty quickly.

I think it would be helpful to design this up front so that instead of a single processor, it uses an array of processors. That way we can encapsulate each conceptual migration and keep them all from bleeding together over time. It would also mean we could run individual ones selectively (see later comment). I don't think it would add too much complexity, and it would make the next migration much easier to add in a maintainable way (vs us always deciding that it's not bad enough to refactor this time, but maybe next time...)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor

Choose a reason for hiding this comment

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

Couldn't we pretty easily use the .metadata file to keep track of migrations that we've done (say, with a UUID for each completed migration)?

In addition to efficiency over time, it also means that we won't accidentally fight users. E.g., if someone had their own unrelated reasons that they needed disable_input_output_paths in their podspec, they'd have a really bad time if we re-run on every build.

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 really wish we could wait until https://docs.google.com/document/d/1fPnpUI6gXE9PkNWuFoAW20m_sQ87ZSC1rrn_D7fxBvs/edit?ts=5e58625e#heading=h.pub7jnop54q0 was in place and use that instead of having a bunch of one-off migrators fighting each other... but we can't wait in this case.

Copy link
Member Author

Choose a reason for hiding this comment

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

Since I removed the disable_input_output_paths change, I didn't implement migration versioning, but it really is a good idea. I'd like to split it out into it's own change as part of the wider flutter migrate effort. For now it's running on every run like #13011.

@jmagman jmagman mentioned this pull request Aug 10, 2020
10 tasks
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 1, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

c: contributor-productivity Team-specific productivity, code health, technical debt. customer: gallery Relating to flutter/gallery repository. Please transfer non-framework issues there. d: examples Sample code and demos platform-ios iOS applications specifically t: xcode "xcodebuild" on iOS and general Xcode project management tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[App.framework] Linked and embedded framework 'App.framework' was built for iOS/iOS Simulator flutter build ios failing: ld: framework not found App

8 participants