diff --git a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart index fc9c07f32f..655764fcf1 100644 --- a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart +++ b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart @@ -151,7 +151,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals section('Check debug build has no Dart AOT'); - final String aotSymbols = await dumpSymbolTable(debugAppFrameworkPath); + final String aotSymbols = await _dylibSymbols(debugAppFrameworkPath); if (aotSymbols.contains('architecture') || aotSymbols.contains('_kDartVmSnapshot')) { @@ -172,7 +172,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals await _checkDylib(appFrameworkPath); - final String aotSymbols = await dumpSymbolTable(appFrameworkPath); + final String aotSymbols = await _dylibSymbols(appFrameworkPath); if (!aotSymbols.contains('_kDartVmSnapshot')) { throw TaskResult.failure('$mode App.framework missing Dart AOT'); @@ -562,7 +562,7 @@ Future _testBuildMacOSFramework(Directory projectDir) async { section('Check debug build has no Dart AOT'); - final String aotSymbols = await dumpSymbolTable(debugAppFrameworkPath); + final String aotSymbols = await _dylibSymbols(debugAppFrameworkPath); if (aotSymbols.contains('architecture') || aotSymbols.contains('_kDartVmSnapshot')) { @@ -583,7 +583,7 @@ Future _testBuildMacOSFramework(Directory projectDir) async { await _checkDylib(appFrameworkPath); - final String aotSymbols = await dumpSymbolTable(appFrameworkPath); + final String aotSymbols = await _dylibSymbols(appFrameworkPath); if (!aotSymbols.contains('_kDartVmSnapshot')) { throw TaskResult.failure('$mode App.framework missing Dart AOT'); @@ -939,6 +939,15 @@ Future _checkStatic(String pathToLibrary) async { } } +Future _dylibSymbols(String pathToDylib) { + return eval('nm', [ + '-g', + pathToDylib, + '-arch', + 'arm64', + ]); +} + Future _linksOnFlutter(String pathToBinary) async { final String loadCommands = await eval('otool', [ '-l', diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index 98865c9236..b45ca54ae6 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -703,7 +703,13 @@ Future _isAppAotBuild(Directory app) async { 'App', ); - final String symbolTable = await dumpSymbolTable(binary); + final String symbolTable = await eval( + 'nm', + [ + '-gU', + binary, + ], + ); return symbolTable.contains('kDartIsolateSnapshotInstructions'); } diff --git a/dev/devicelab/bin/tasks/plugin_dependencies_test.dart b/dev/devicelab/bin/tasks/plugin_dependencies_test.dart index baae2f6bf6..bf74614c3c 100644 --- a/dev/devicelab/bin/tasks/plugin_dependencies_test.dart +++ b/dev/devicelab/bin/tasks/plugin_dependencies_test.dart @@ -6,7 +6,6 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter_devicelab/framework/framework.dart'; -import 'package:flutter_devicelab/framework/ios.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/utils.dart'; import 'package:path/path.dart' as path; @@ -210,7 +209,6 @@ public class DummyPluginAClass { final String flutterPluginsDependenciesFileContent = flutterPluginsDependenciesFile.readAsStringSync(); final Map jsonContent = json.decode(flutterPluginsDependenciesFileContent) as Map; - final bool swiftPackageManagerEnabled = jsonContent['swift_package_manager_enabled'] as bool? ?? false; // Verify the dependencyGraph object is valid. The rest of the contents of this file are not relevant to the // dependency graph and are tested by unit tests. @@ -304,35 +302,28 @@ public class DummyPluginAClass { return TaskResult.failure('Failed to build plugin A example iOS app'); } - if (swiftPackageManagerEnabled) { - // Check plugins are built statically if using SwiftPM. - final String executable = path.join(appBundle.path, 'Runner'); - final String symbols = await dumpSymbolTable(executable); + checkDirectoryExists(path.join( + appBundle.path, + 'Frameworks', + 'plugin_a.framework', + )); + checkDirectoryExists(path.join( + appBundle.path, + 'Frameworks', + 'plugin_b.framework', + )); + checkDirectoryExists(path.join( + appBundle.path, + 'Frameworks', + 'plugin_c.framework', + )); - final bool foundA = symbols.contains('plugin_a'); - final bool foundB = symbols.contains('plugin_b'); - final bool foundC = symbols.contains('plugin_c'); - final bool foundD = symbols.contains('plugin_d'); - - if (!foundA || !foundB || !foundC) { - return TaskResult.failure( - 'Failed to find plugins_a, plugin_b, or plugin_c symbols in the app' - ); - } - - if (foundD) { - return TaskResult.failure( - 'Found Android plugin_d symbols in iOS app' - ); - } - } else { - // Check plugins are built dynamically if using CocoaPods. - checkDirectoryExists(path.join(appBundle.path, 'Frameworks', 'plugin_a.framework')); - checkDirectoryExists(path.join(appBundle.path, 'Frameworks', 'plugin_b.framework')); - checkDirectoryExists(path.join(appBundle.path, 'Frameworks', 'plugin_c.framework')); - - checkDirectoryNotExists(path.join(appBundle.path, 'Frameworks', 'plugin_d.framework')); - } + // Plugin D is Android only and should not be embedded. + checkDirectoryNotExists(path.join( + appBundle.path, + 'Frameworks', + 'plugin_d.framework', + )); } return TaskResult.success(null); diff --git a/dev/devicelab/lib/framework/ios.dart b/dev/devicelab/lib/framework/ios.dart index 7fc35606eb..e50573e9b8 100644 --- a/dev/devicelab/lib/framework/ios.dart +++ b/dev/devicelab/lib/framework/ios.dart @@ -308,17 +308,3 @@ File? _createDisabledSandboxEntitlementFile( return disabledSandboxEntitlementFile; } - -/// Returns global (external) symbol table entries, delimited by new lines. -Future dumpSymbolTable(String filePath) { - return eval( - 'nm', - [ - '--extern-only', - '--just-symbol-name', - filePath, - '-arch', - 'arm64', - ], - ); -} diff --git a/dev/devicelab/lib/tasks/plugin_tests.dart b/dev/devicelab/lib/tasks/plugin_tests.dart index c41cb40470..fe6cb4449b 100644 --- a/dev/devicelab/lib/tasks/plugin_tests.dart +++ b/dev/devicelab/lib/tasks/plugin_tests.dart @@ -77,11 +77,6 @@ class PluginTest { final _FlutterProject app = await _FlutterProject.create(tempDir, options, buildTarget, name: 'plugintestapp', template: 'app', environment: appCreateEnvironment); try { - if (cocoapodsTransitiveFlutterDependency) { - section('Disable Swift Package Manager'); - await app.disableSwiftPackageManager(); - } - section('Add plugins'); await app.addPlugin('plugintest', pluginPath: path.join('..', 'plugintest')); @@ -152,20 +147,6 @@ class _FlutterProject { return _FlutterProject(Directory(path.join(rootPath)), 'example'); } - Future disableSwiftPackageManager() async { - final File pubspec = pubspecFile; - String content = await pubspec.readAsString(); - content = content.replaceFirst( - '# The following section is specific to Flutter packages.\n' - 'flutter:\n', - '# The following section is specific to Flutter packages.\n' - 'flutter:\n' - '\n' - ' disable-swift-package-manager: true\n' - ); - await pubspec.writeAsString(content, flush: true); - } - Future addPlugin(String plugin, {String? pluginPath}) async { final File pubspec = pubspecFile; String content = await pubspec.readAsString(); @@ -263,14 +244,9 @@ class $dartPluginClass { await podspec.writeAsString(podspecContent, flush: true); // Make PlugintestPlugin.swift compile on iOS and macOS with target conditionals. - // If SwiftPM is disabled, the file will be in `darwin/Classes/`. - // Otherwise, the file will be in `darwin//Sources//`. final String pluginClass = '${name[0].toUpperCase()}${name.substring(1)}Plugin'; print('pluginClass: $pluginClass'); - File pluginRegister = File(path.join(darwinDir.path, 'Classes', '$pluginClass.swift')); - if (!pluginRegister.existsSync()) { - pluginRegister = File(path.join(darwinDir.path, name, 'Sources', name, '$pluginClass.swift')); - } + final File pluginRegister = File(path.join(darwinDir.path, 'Classes', '$pluginClass.swift')); final String pluginRegisterContent = ''' #if os(macOS) import FlutterMacOS @@ -518,55 +494,42 @@ s.dependency 'AppAuth', '1.6.0' } if (validateNativeBuildProject) { - final File generatedSwiftManifest = File(path.join( - rootPath, - target, - 'Flutter', - 'ephemeral', - 'Packages', - 'FlutterGeneratedPluginSwiftPackage', - 'Package.swift' - )); - final bool swiftPackageManagerEnabled = generatedSwiftManifest.existsSync(); + final File podsProject = File(path.join(rootPath, target, 'Pods', 'Pods.xcodeproj', 'project.pbxproj')); + if (!podsProject.existsSync()) { + throw TaskResult.failure('Xcode Pods project file missing at ${podsProject.path}'); + } - if (!swiftPackageManagerEnabled) { - final File podsProject = File(path.join(rootPath, target, 'Pods', 'Pods.xcodeproj', 'project.pbxproj')); - if (!podsProject.existsSync()) { - throw TaskResult.failure('Xcode Pods project file missing at ${podsProject.path}'); + final String podsProjectContent = podsProject.readAsStringSync(); + if (target == 'ios') { + // Plugins with versions lower than the app version should not have IPHONEOS_DEPLOYMENT_TARGET set. + // The plugintest plugin target should not have IPHONEOS_DEPLOYMENT_TARGET set since it has been lowered + // in _reduceDarwinPluginMinimumVersion to 10, which is below the target version of 11. + if (podsProjectContent.contains('IPHONEOS_DEPLOYMENT_TARGET = 10')) { + throw TaskResult.failure('Plugin build setting IPHONEOS_DEPLOYMENT_TARGET not removed'); } - - final String podsProjectContent = podsProject.readAsStringSync(); - if (target == 'ios') { - // Plugins with versions lower than the app version should not have IPHONEOS_DEPLOYMENT_TARGET set. - // The plugintest plugin target should not have IPHONEOS_DEPLOYMENT_TARGET set since it has been lowered - // in _reduceDarwinPluginMinimumVersion to 10, which is below the target version of 11. - if (podsProjectContent.contains('IPHONEOS_DEPLOYMENT_TARGET = 10')) { - throw TaskResult.failure('Plugin build setting IPHONEOS_DEPLOYMENT_TARGET not removed'); - } - // Transitive dependency AppAuth targeting too-low 8.0 was not fixed. - if (podsProjectContent.contains('IPHONEOS_DEPLOYMENT_TARGET = 8')) { - throw TaskResult.failure('Transitive dependency build setting IPHONEOS_DEPLOYMENT_TARGET=8 not removed'); - } - if (!podsProjectContent.contains(r'"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386";')) { - throw TaskResult.failure(r'EXCLUDED_ARCHS is not "$(inherited) i386"'); - } - } else if (target == 'macos') { - // Same for macOS deployment target, but 10.8. - // The plugintest target should not have MACOSX_DEPLOYMENT_TARGET set. - if (podsProjectContent.contains('MACOSX_DEPLOYMENT_TARGET = 10.8')) { - throw TaskResult.failure('Plugin build setting MACOSX_DEPLOYMENT_TARGET not removed'); - } - // Transitive dependency AppAuth targeting too-low 10.9 was not fixed. - if (podsProjectContent.contains('MACOSX_DEPLOYMENT_TARGET = 10.9')) { - throw TaskResult.failure('Transitive dependency build setting MACOSX_DEPLOYMENT_TARGET=10.9 not removed'); - } + // Transitive dependency AppAuth targeting too-low 8.0 was not fixed. + if (podsProjectContent.contains('IPHONEOS_DEPLOYMENT_TARGET = 8')) { + throw TaskResult.failure('Transitive dependency build setting IPHONEOS_DEPLOYMENT_TARGET=8 not removed'); } + if (!podsProjectContent.contains(r'"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386";')) { + throw TaskResult.failure(r'EXCLUDED_ARCHS is not "$(inherited) i386"'); + } + } else if (target == 'macos') { + // Same for macOS deployment target, but 10.8. + // The plugintest target should not have MACOSX_DEPLOYMENT_TARGET set. + if (podsProjectContent.contains('MACOSX_DEPLOYMENT_TARGET = 10.8')) { + throw TaskResult.failure('Plugin build setting MACOSX_DEPLOYMENT_TARGET not removed'); + } + // Transitive dependency AppAuth targeting too-low 10.9 was not fixed. + if (podsProjectContent.contains('MACOSX_DEPLOYMENT_TARGET = 10.9')) { + throw TaskResult.failure('Transitive dependency build setting MACOSX_DEPLOYMENT_TARGET=10.9 not removed'); + } + } - if (localEngine != null) { - final RegExp localEngineSearchPath = RegExp('FRAMEWORK_SEARCH_PATHS\\s*=[^;]*${localEngine.path}'); - if (!localEngineSearchPath.hasMatch(podsProjectContent)) { - throw TaskResult.failure('FRAMEWORK_SEARCH_PATHS does not contain the --local-engine path'); - } + if (localEngine != null) { + final RegExp localEngineSearchPath = RegExp('FRAMEWORK_SEARCH_PATHS\\s*=[^;]*${localEngine.path}'); + if (!localEngineSearchPath.hasMatch(podsProjectContent)) { + throw TaskResult.failure('FRAMEWORK_SEARCH_PATHS does not contain the --local-engine path'); } } } diff --git a/packages/flutter_tools/lib/src/features.dart b/packages/flutter_tools/lib/src/features.dart index 44e40a9b3d..7a8a209f5c 100644 --- a/packages/flutter_tools/lib/src/features.dart +++ b/packages/flutter_tools/lib/src/features.dart @@ -186,7 +186,6 @@ const Feature swiftPackageManager = Feature( environmentOverride: 'SWIFT_PACKAGE_MANAGER', master: FeatureChannelSetting( available: true, - enabledByDefault: true, ), ); diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 11734f1be7..ae42a58736 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -693,7 +693,7 @@ void main() { ), }); - testUsingContext('kotlin/swift plugin project without Swift Package Manager', () async { + testUsingContext('kotlin/swift plugin project', () async { return _createProject( projectDir, ['--no-pub', '--template=plugin', '-a', 'kotlin', '--ios-language', 'swift', '--platforms', 'ios,android'], @@ -718,9 +718,6 @@ void main() { 'ios/Classes/FlutterProjectPlugin.m', ], ); - }, overrides: { - // Test flags disable Swift Package Manager. - FeatureFlags: () => TestFeatureFlags(), }); testUsingContext('swift plugin project with Swift Package Manager', () async { @@ -1947,7 +1944,7 @@ void main() { ); }); - testUsingContext('can re-gen plugin ios/ and example/ folders, reusing custom org, without Swift Package Manager', () async { + testUsingContext('can re-gen plugin ios/ and example/ folders, reusing custom org', () async { await _createProject( projectDir, [ @@ -1972,7 +1969,6 @@ void main() { unexpectedPaths: [ 'example/android/app/src/main/java/com/example/flutter_project_example/MainActivity.java', 'android/src/main/java/com/example/flutter_project/FlutterProjectPlugin.java', - 'ios/flutter_project/Sources/flutter_project/include/flutter_project/FlutterProjectPlugin.h', ], ); final FlutterProject project = FlutterProject.fromDirectory(projectDir); @@ -1980,48 +1976,6 @@ void main() { await project.example.ios.productBundleIdentifier(BuildInfo.debug), 'com.bar.foo.flutterProjectExample', ); - }, overrides: { - // Test flags disable Swift Package Manager. - FeatureFlags: () => TestFeatureFlags(), - }); - - testUsingContext('can re-gen plugin ios/ and example/ folders, reusing custom org, with Swift Package Manager', () async { - await _createProject( - projectDir, - [ - '--no-pub', - '--template=plugin', - '--org', 'com.bar.foo', - '-i', 'objc', - '-a', 'java', - '--platforms', 'ios,android', - ], - [], - ); - projectDir.childDirectory('example').deleteSync(recursive: true); - projectDir.childDirectory('ios').deleteSync(recursive: true); - await _createProject( - projectDir, - ['--no-pub', '--template=plugin', '-i', 'objc', '-a', 'java', '--platforms', 'ios,android'], - [ - 'example/android/app/src/main/java/com/bar/foo/flutter_project_example/MainActivity.java', - 'ios/flutter_project/Sources/flutter_project/include/flutter_project/FlutterProjectPlugin.h', - ], - unexpectedPaths: [ - 'example/android/app/src/main/java/com/example/flutter_project_example/MainActivity.java', - 'android/src/main/java/com/example/flutter_project/FlutterProjectPlugin.java', - 'ios/Classes/FlutterProjectPlugin.h', - ], - ); - final FlutterProject project = FlutterProject.fromDirectory(projectDir); - expect( - await project.example.ios.productBundleIdentifier(BuildInfo.debug), - 'com.bar.foo.flutterProjectExample', - ); - }, overrides: { - FeatureFlags: () => TestFeatureFlags( - isSwiftPackageManagerEnabled: true, - ), }); testUsingContext('fails to re-gen without specified org when org is ambiguous', () async { diff --git a/packages/flutter_tools/test/general.shard/features_test.dart b/packages/flutter_tools/test/general.shard/features_test.dart index 423e237ce1..994ae392d6 100644 --- a/packages/flutter_tools/test/general.shard/features_test.dart +++ b/packages/flutter_tools/test/general.shard/features_test.dart @@ -404,7 +404,7 @@ void main() { }); test('${swiftPackageManager.name} availability and default enabled', () { - expect(swiftPackageManager.master.enabledByDefault, true); + expect(swiftPackageManager.master.enabledByDefault, false); expect(swiftPackageManager.master.available, true); expect(swiftPackageManager.beta.enabledByDefault, false); expect(swiftPackageManager.beta.available, false); diff --git a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart index f2eeb885bb..da5b6a55db 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart @@ -87,7 +87,6 @@ void main() { late File outputFlutterFrameworkBinary; late Directory outputAppFramework; late File outputAppFrameworkBinary; - late File outputRunnerBinary; late File outputPluginFrameworkBinary; late Directory buildPath; late Directory buildAppFrameworkDsym; @@ -123,10 +122,6 @@ void main() { outputAppFramework = frameworkDirectory.childDirectory('App.framework'); outputAppFrameworkBinary = outputAppFramework.childFile('App'); - outputRunnerBinary = outputApp.childFile('Runner'); - - // Exists only if the plugin is built as a dynamic framework. - // This is is the default for CocoaPods but not Swift Package Manager. outputPluginFrameworkBinary = frameworkDirectory.childDirectory('hello.framework').childFile('hello'); buildPath = fileSystem.directory(fileSystem.path.join( @@ -146,18 +141,7 @@ void main() { printOnFailure(buildResult.stderr.toString()); expect(buildResult.exitCode, 0); - // Plugins are built either as a static library (SwiftPM's default) - // or as a dynamic library (CocoaPods's default). - // If built as a dynamic library, the plugin will have a .framework. - // If built as static library, the plugin's symbols will be in the - // Runner binary. - final bool helloDynamic = outputPluginFrameworkBinary.existsSync(); - final bool helloStatic = AppleTestUtils - .getExportedSymbols(outputRunnerBinary.path) - .any((String symbol) => symbol.contains('HelloPlugin') && symbol.contains('handle')); - - // Plugin is a dynamic xor static framework. - expect(helloDynamic != helloStatic, isTrue); + expect(outputPluginFrameworkBinary, exists); expect(outputAppFrameworkBinary, exists); expect(outputAppFramework.childFile('Info.plist'), exists); @@ -316,19 +300,6 @@ void main() { ); expect(buildSimulator.exitCode, 0); - // Plugins are built either as a static library (SwiftPM's default) - // or as a dynamic library (CocoaPods's default). - // If built as a dynamic library, the plugin will have a .framework. - // If built as static library, the plugin's symbols will be in the - // Runner binary. - final File runnerBinary = fileSystem.file(fileSystem.path.join( - projectRoot, - 'build', - 'ios', - 'iphonesimulator', - 'Runner.app', - 'Runner', - )); final File pluginFrameworkBinary = fileSystem.file(fileSystem.path.join( projectRoot, 'build', @@ -339,21 +310,12 @@ void main() { 'hello.framework', 'hello', )); - final bool helloDynamic = pluginFrameworkBinary.existsSync(); - final bool helloStatic = AppleTestUtils - .getExportedSymbols(runnerBinary.path) - .any((String symbol) => symbol.contains('HelloPlugin') && symbol.contains('handle')); - - // Plugin is a dynamic xor static framework. - expect(helloDynamic != helloStatic, isTrue); - - if (helloDynamic) { - final ProcessResult archs = processManager.runSync( - ['file', pluginFrameworkBinary.path], - ); - expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library x86_64')); - expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64')); - } + expect(pluginFrameworkBinary, exists); + final ProcessResult archs = processManager.runSync( + ['file', pluginFrameworkBinary.path], + ); + expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library x86_64')); + expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64')); }); testWithoutContext('build for simulator with all available architectures', () {