[SwiftPM] Make 'flutter build ios-framework' generate an empty Package.swift (#161464)

<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->

### Background

Flutter generates a `Package.swift` file that contains the plugins that
should be built using SwiftPM.

Since Flutter does not support Swift Package Manager in add-to-app
scenarios yet, Flutter uses CocoaPods to build plugins if you call
`flutter build ios-framework`. To ensure `pod install` is rerun, the
tool deleted the `Package.swift` file.

Unfortunately, deleting the `Package.swift` file causes the Xcode
project to no longer build if it has SwiftPM integration. This caused
the [`build_ios_framework_module_test` to fail when SwiftPM was turned
on by
default](https://ci.chromium.org/ui/p/flutter/builders/prod/Mac%20build_ios_framework_module_test/21807/overview).

### Fix

Instead of deleting the `Package.swift` file, we instead generate a
`Package.swift` file with no dependencies. This will invalidate the
fingerprint and cause `pod install` to rerun if the app had plugins that
were previously built using SwiftPM.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

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

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
Loïc Sharma 2025-01-14 13:13:15 -08:00 committed by GitHub
parent e5b1ab040e
commit fa04f4a8d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 45 additions and 20 deletions

View File

@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../base/error_handling_io.dart';
import '../base/fingerprint.dart';
import '../build_info.dart';
import '../cache.dart';
import '../flutter_plugins.dart';
import '../globals.dart' as globals;
import '../plugins.dart';
import '../project.dart';
import 'swift_package_manager.dart';
/// For a given build, determines whether dependencies have changed since the
/// last call to processPods, then calls processPods with that information.
@ -61,8 +62,15 @@ Future<void> processPodsIfNeeded(
await globals.cocoaPods?.setupPodfile(xcodeProject);
}
// Delete Swift Package Manager manifest to invalidate fingerprinter
ErrorHandlingFileSystem.deleteIfExists(xcodeProject.flutterPluginSwiftPackageManifest);
// Generate an empty Swift Package Manager manifest to invalidate fingerprinter
final SwiftPackageManager swiftPackageManager = SwiftPackageManager(
fileSystem: globals.localFileSystem,
templateRenderer: globals.templateRenderer,
);
final SupportedPlatform platform =
xcodeProject is IosProject ? SupportedPlatform.ios : SupportedPlatform.macos;
await swiftPackageManager.generatePluginsSwiftPackage(const <Plugin>[], platform, xcodeProject);
}
// If the Xcode project, Podfile, generated plugin Swift Package, or podhelper

View File

@ -6,6 +6,7 @@ import 'dart:convert';
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/dart/pub.dart';
@ -239,7 +240,8 @@ void main() {
setUpProject(flutterProject, fs);
createFakePlugins(flutterProject, fs, <String>['plugin_one', 'plugin_two']);
flutterProject.ios.usesSwiftPackageManager = true;
flutterProject.ios.flutterPluginSwiftPackageManifest.createSync(recursive: true);
final File generatedManifestFile = flutterProject.ios.flutterPluginSwiftPackageManifest;
generatedManifestFile.createSync(recursive: true);
await processPodsIfNeeded(
flutterProject.ios,
@ -254,7 +256,9 @@ void main() {
'Swift Package Manager does not yet support this command. '
'CocoaPods will be used instead.\n',
);
expect(flutterProject.ios.flutterPluginSwiftPackageManifest.existsSync(), isFalse);
expect(generatedManifestFile, exists);
const String emptyDependencies = 'dependencies: [\n \n ],\n';
expect(generatedManifestFile.readAsStringSync(), contains(emptyDependencies));
},
overrides: <Type, Generator>{
FileSystem: () => fs,
@ -412,7 +416,9 @@ void main() {
setUpProject(flutterProject, fs);
createFakePlugins(flutterProject, fs, <String>['plugin_one', 'plugin_two']);
flutterProject.macos.usesSwiftPackageManager = true;
flutterProject.macos.flutterPluginSwiftPackageManifest.createSync(recursive: true);
final File generatedManifestFile =
flutterProject.macos.flutterPluginSwiftPackageManifest;
generatedManifestFile.createSync(recursive: true);
await processPodsIfNeeded(
flutterProject.macos,
@ -427,7 +433,10 @@ void main() {
'Swift Package Manager does not yet support this command. '
'CocoaPods will be used instead.\n',
);
expect(flutterProject.macos.flutterPluginSwiftPackageManifest.existsSync(), isFalse);
expect(generatedManifestFile, exists);
const String emptyDependencies = 'dependencies: [\n \n ],\n';
expect(generatedManifestFile.readAsStringSync(), contains(emptyDependencies));
},
overrides: <Type, Generator>{
FileSystem: () => fs,
@ -517,6 +526,9 @@ class FakeMacOSProject extends Fake implements MacOSProject {
@override
bool usesSwiftPackageManager = false;
@override
bool get flutterPluginSwiftPackageInProjectSettings => usesSwiftPackageManager;
}
class FakeIosProject extends Fake implements IosProject {
@ -555,6 +567,9 @@ class FakeIosProject extends Fake implements IosProject {
@override
bool usesSwiftPackageManager = false;
@override
bool get flutterPluginSwiftPackageInProjectSettings => usesSwiftPackageManager;
}
class FakeAndroidProject extends Fake implements AndroidProject {

View File

@ -507,19 +507,21 @@ void main() {
expect(fileSystem.directory(appDirectoryPath).childDirectory('.ios'), isNot(exists));
// TODO(loic-sharma): A Swift package manifest should not be generated.
// https://github.com/flutter/flutter/issues/146957
// expect(
// fileSystem
// .directory(appDirectoryPath)
// .childDirectory('ios')
// .childDirectory('Flutter')
// .childDirectory('ephemeral')
// .childDirectory('Packages')
// .childDirectory('FlutterGeneratedPluginSwiftPackage')
// .childFile('Package.swift'),
// isFalse,
// );
// Verify the generated Swift Package Manager manifest file has no dependencies.
final File generatedManifestFile = fileSystem
.directory(appDirectoryPath)
.childDirectory('ios')
.childDirectory('Flutter')
.childDirectory('ephemeral')
.childDirectory('Packages')
.childDirectory('FlutterGeneratedPluginSwiftPackage')
.childFile('Package.swift');
expect(generatedManifestFile, exists);
final String generatedManifest = generatedManifestFile.readAsStringSync();
const String expected = 'dependencies: [\n \n ],\n';
expect(generatedManifest, contains(expected));
expect(
fileSystem