Revert "Revert "Allow any iOS app to be added to an existing host app (#70647)" (#70739)" (#70740)
This reverts commit aab9a76ee4cd97199e9d21118a0a3cfbda80b899.
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 cbd8b6d..d35ed54 100644
--- a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
+++ b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
@@ -17,392 +17,439 @@
section('Create module project');
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
- final Directory projectDir = Directory(path.join(tempDir.path, 'hello'));
try {
await inDirectory(tempDir, () async {
+ section('Test module template');
+
+ final Directory moduleProjectDir =
+ Directory(path.join(tempDir.path, 'hello_module'));
await flutter(
'create',
- options: <String>['--org', 'io.flutter.devicelab', '--template', 'module', 'hello'],
- );
- });
-
- section('Add plugins');
-
- final File pubspec = File(path.join(projectDir.path, 'pubspec.yaml'));
- String content = pubspec.readAsStringSync();
- content = content.replaceFirst(
- '\ndependencies:\n',
- '\ndependencies:\n device_info: 0.4.1\n package_info: 0.4.0+9\n',
- );
- pubspec.writeAsStringSync(content, flush: true);
- await inDirectory(projectDir, () async {
- await flutter(
- 'packages',
- options: <String>['get'],
- );
- });
-
- // First, build the module in Debug to copy the debug version of Flutter.framework.
- // This proves "flutter build ios-framework" re-copies the relevant Flutter.framework,
- // otherwise building plugins with bitcode will fail linking because the debug version
- // of Flutter.framework does not contain bitcode.
- await inDirectory(projectDir, () async {
- await flutter(
- 'build',
options: <String>[
- 'ios',
- '--debug',
- '--no-codesign',
+ '--org',
+ 'io.flutter.devicelab',
+ '--template',
+ 'module',
+ 'hello_module'
],
);
- });
- // This builds all build modes' frameworks by default
- section('Build frameworks');
+ await _testBuildIosFramework(moduleProjectDir, isModule: true);
- const String outputDirectoryName = 'flutter-frameworks';
+ section('Test app template');
- await inDirectory(projectDir, () async {
+ final Directory projectDir =
+ Directory(path.join(tempDir.path, 'hello_project'));
await flutter(
- 'build',
- options: <String>[
- 'ios-framework',
- '--universal',
- '--output=$outputDirectoryName'
- ],
+ 'create',
+ options: <String>['--org', 'io.flutter.devicelab', 'hello_project'],
);
+
+ await _testBuildIosFramework(projectDir);
});
- final String outputPath = path.join(projectDir.path, outputDirectoryName);
-
- section('Check debug build has Dart snapshot as asset');
-
- checkFileExists(path.join(
- outputPath,
- 'Debug',
- 'App.framework',
- 'flutter_assets',
- 'vm_snapshot_data',
- ));
-
- section('Check debug build has no Dart AOT');
-
- // There's still an App.framework with a dylib, but it's empty.
- checkFileExists(path.join(
- outputPath,
- 'Debug',
- 'App.framework',
- 'App',
- ));
-
- final String debugAppFrameworkPath = path.join(
- outputPath,
- 'Debug',
- 'App.framework',
- 'App',
- );
- final String aotSymbols = await dylibSymbols(debugAppFrameworkPath);
-
- if (aotSymbols.contains('architecture') ||
- aotSymbols.contains('_kDartVmSnapshot')) {
- throw TaskResult.failure('Debug App.framework contains AOT');
- }
- await _checkFrameworkArchs(debugAppFrameworkPath, 'Debug');
-
- // Xcode changed the name of this generated directory in Xcode 12.
- const String xcode11ArmDirectoryName = 'ios-armv7_arm64';
- const String xcode12ArmDirectoryName = 'ios-arm64_armv7';
-
- final String xcode11AppFrameworkDirectory = path.join(
- outputPath,
- 'Debug',
- 'App.xcframework',
- xcode11ArmDirectoryName,
- 'App.framework',
- 'App',
- );
- final String xcode12AppFrameworkDirectory = path.join(
- outputPath,
- 'Debug',
- 'App.xcframework',
- xcode12ArmDirectoryName,
- 'App.framework',
- 'App',
- );
-
- // This seemed easier than an explicit Xcode version check.
- String xcodeArmDirectoryName;
- if (exists(File(xcode11AppFrameworkDirectory))) {
- xcodeArmDirectoryName = xcode11ArmDirectoryName;
- } else if (exists(File(xcode12AppFrameworkDirectory))) {
- xcodeArmDirectoryName = xcode12ArmDirectoryName;
- } else {
- throw const FileSystemException('Expected App.framework binary to exist.');
- }
-
- checkFileExists(path.join(
- outputPath,
- 'Debug',
- 'App.xcframework',
- 'ios-x86_64-simulator',
- 'App.framework',
- 'App',
- ));
-
- section('Check profile, release builds has Dart AOT dylib');
-
- for (final String mode in <String>['Profile', 'Release']) {
- final String appFrameworkPath = path.join(
- outputPath,
- mode,
- 'App.framework',
- 'App',
- );
-
- await _checkFrameworkArchs(appFrameworkPath, mode);
- await _checkBitcode(appFrameworkPath, mode);
-
- final String aotSymbols = await dylibSymbols(appFrameworkPath);
-
- if (!aotSymbols.contains('_kDartVmSnapshot')) {
- throw TaskResult.failure('$mode App.framework missing Dart AOT');
- }
-
- checkFileNotExists(path.join(
- outputPath,
- mode,
- 'App.framework',
- 'flutter_assets',
- 'vm_snapshot_data',
- ));
-
- checkFileExists(path.join(
- outputPath,
- mode,
- 'App.xcframework',
- xcodeArmDirectoryName,
- 'App.framework',
- 'App',
- ));
-
- checkFileNotExists(path.join(
- outputPath,
- mode,
- 'App.xcframework',
- 'ios-x86_64-simulator',
- 'App.framework',
- 'App',
- ));
- }
-
- section("Check all modes' engine dylib");
-
- for (final String mode in <String>['Debug', 'Profile', 'Release']) {
- final String engineFrameworkPath = path.join(
- outputPath,
- mode,
- 'Flutter.framework',
- 'Flutter',
- );
-
- await _checkFrameworkArchs(engineFrameworkPath, mode);
- await _checkBitcode(engineFrameworkPath, mode);
-
- checkFileExists(path.join(
- outputPath,
- mode,
- 'Flutter.xcframework',
- xcodeArmDirectoryName,
- 'Flutter.framework',
- 'Flutter',
- ));
- final String simulatorFrameworkPath = path.join(
- outputPath,
- mode,
- 'Flutter.xcframework',
- 'ios-x86_64-simulator',
- 'Flutter.framework',
- 'Flutter',
- );
- if (mode == 'Debug') {
- checkFileExists(simulatorFrameworkPath);
- } else {
- checkFileNotExists(simulatorFrameworkPath);
- }
- }
-
- section("Check all modes' engine header");
-
- for (final String mode in <String>['Debug', 'Profile', 'Release']) {
- checkFileExists(path.join(outputPath, mode, 'Flutter.framework', 'Headers', 'Flutter.h'));
- }
-
- section('Check all modes have plugins');
-
- for (final String mode in <String>['Debug', 'Profile', 'Release']) {
- final String pluginFrameworkPath = path.join(
- outputPath,
- mode,
- 'device_info.framework',
- 'device_info',
- );
- await _checkFrameworkArchs(pluginFrameworkPath, mode);
- await _checkBitcode(pluginFrameworkPath, mode);
-
- checkFileExists(path.join(
- outputPath,
- mode,
- 'device_info.xcframework',
- xcodeArmDirectoryName,
- 'device_info.framework',
- 'device_info',
- ));
-
- checkFileExists(path.join(
- outputPath,
- mode,
- 'device_info.xcframework',
- xcodeArmDirectoryName,
- 'device_info.framework',
- 'Headers',
- 'DeviceInfoPlugin.h',
- ));
-
- final String simulatorFrameworkPath = path.join(
- outputPath,
- mode,
- 'device_info.xcframework',
- 'ios-x86_64-simulator',
- 'device_info.framework',
- 'device_info',
- );
-
- final String simulatorFrameworkHeaderPath = path.join(
- outputPath,
- mode,
- 'device_info.xcframework',
- 'ios-x86_64-simulator',
- 'device_info.framework',
- 'Headers',
- 'DeviceInfoPlugin.h',
- );
-
- if (mode == 'Debug') {
- checkFileExists(simulatorFrameworkPath);
- checkFileExists(simulatorFrameworkHeaderPath);
- } else {
- checkFileNotExists(simulatorFrameworkPath);
- checkFileNotExists(simulatorFrameworkHeaderPath);
- }
- }
-
- section('Check all modes have generated plugin registrant');
-
- for (final String mode in <String>['Debug', 'Profile', 'Release']) {
- final String registrantFrameworkPath = path.join(
- outputPath,
- mode,
- 'FlutterPluginRegistrant.framework',
- 'FlutterPluginRegistrant'
- );
-
- await _checkFrameworkArchs(registrantFrameworkPath, mode);
- await _checkBitcode(registrantFrameworkPath, mode);
-
- checkFileExists(path.join(
- outputPath,
- mode,
- 'FlutterPluginRegistrant.framework',
- 'Headers',
- 'GeneratedPluginRegistrant.h',
- ));
- checkFileExists(path.join(
- outputPath,
- mode,
- 'FlutterPluginRegistrant.xcframework',
- xcodeArmDirectoryName,
- 'FlutterPluginRegistrant.framework',
- 'Headers',
- 'GeneratedPluginRegistrant.h',
- ));
- final String simulatorHeaderPath = path.join(
- outputPath,
- mode,
- 'FlutterPluginRegistrant.xcframework',
- 'ios-x86_64-simulator',
- 'FlutterPluginRegistrant.framework',
- 'Headers',
- 'GeneratedPluginRegistrant.h',
- );
- if (mode == 'Debug') {
- checkFileExists(simulatorHeaderPath);
- } else {
- checkFileNotExists(simulatorHeaderPath);
- }
- }
-
- // This builds all build modes' frameworks by default
- section('Build podspec');
-
- const String cocoapodsOutputDirectoryName = 'flutter-frameworks-cocoapods';
-
- await inDirectory(projectDir, () async {
- await flutter(
- 'build',
- options: <String>[
- 'ios-framework',
- '--cocoapods',
- '--universal',
- '--force', // Allow podspec creation on master.
- '--output=$cocoapodsOutputDirectoryName'
- ],
- );
- });
-
- final String cocoapodsOutputPath = path.join(projectDir.path, cocoapodsOutputDirectoryName);
- for (final String mode in <String>['Debug', 'Profile', 'Release']) {
- checkFileExists(path.join(
- cocoapodsOutputPath,
- mode,
- 'Flutter.podspec',
- ));
-
- checkDirectoryExists(path.join(
- cocoapodsOutputPath,
- mode,
- 'App.framework',
- ));
-
- checkDirectoryExists(path.join(
- cocoapodsOutputPath,
- mode,
- 'FlutterPluginRegistrant.framework',
- ));
-
- checkDirectoryExists(path.join(
- cocoapodsOutputPath,
- mode,
- 'device_info.framework',
- ));
-
- checkDirectoryExists(path.join(
- cocoapodsOutputPath,
- mode,
- 'package_info.framework',
- ));
- }
-
return TaskResult.success(null);
} on TaskResult catch (taskResult) {
return taskResult;
} catch (e) {
return TaskResult.failure(e.toString());
} finally {
- rmTree(tempDir);
+ // rmTree(tempDir);
}
});
}
+Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = false}) async {
+ section('Add plugins');
+
+ final File pubspec = File(path.join(projectDir.path, 'pubspec.yaml'));
+ String content = pubspec.readAsStringSync();
+ content = content.replaceFirst(
+ '\ndependencies:\n',
+ '\ndependencies:\n device_info: 0.4.1\n package_info: 0.4.0+9\n',
+ );
+ pubspec.writeAsStringSync(content, flush: true);
+ await inDirectory(projectDir, () async {
+ await flutter(
+ 'packages',
+ options: <String>['get'],
+ );
+ });
+
+ // First, build the module in Debug to copy the debug version of Flutter.framework.
+ // This proves "flutter build ios-framework" re-copies the relevant Flutter.framework,
+ // otherwise building plugins with bitcode will fail linking because the debug version
+ // of Flutter.framework does not contain bitcode.
+ await inDirectory(projectDir, () async {
+ await flutter(
+ 'build',
+ options: <String>[
+ 'ios',
+ '--debug',
+ '--no-codesign',
+ ],
+ );
+ });
+
+ // This builds all build modes' frameworks by default
+ section('Build frameworks');
+
+ const String outputDirectoryName = 'flutter-frameworks';
+
+ await inDirectory(projectDir, () async {
+ await flutter(
+ 'build',
+ options: <String>[
+ 'ios-framework',
+ '--universal',
+ '--output=$outputDirectoryName'
+ ],
+ );
+ });
+
+ final String outputPath = path.join(projectDir.path, outputDirectoryName);
+
+ section('Check debug build has Dart snapshot as asset');
+
+ checkFileExists(path.join(
+ outputPath,
+ 'Debug',
+ 'App.framework',
+ 'flutter_assets',
+ 'vm_snapshot_data',
+ ));
+
+ section('Check debug build has no Dart AOT');
+
+ // There's still an App.framework with a dylib, but it's empty.
+ checkFileExists(path.join(
+ outputPath,
+ 'Debug',
+ 'App.framework',
+ 'App',
+ ));
+
+ final String debugAppFrameworkPath = path.join(
+ outputPath,
+ 'Debug',
+ 'App.framework',
+ 'App',
+ );
+ final String aotSymbols = await dylibSymbols(debugAppFrameworkPath);
+
+ if (aotSymbols.contains('architecture') ||
+ aotSymbols.contains('_kDartVmSnapshot')) {
+ throw TaskResult.failure('Debug App.framework contains AOT');
+ }
+ await _checkFrameworkArchs(debugAppFrameworkPath, 'Debug');
+
+ // Xcode changed the name of this generated directory in Xcode 12.
+ const String xcode11ArmDirectoryName = 'ios-armv7_arm64';
+ const String xcode12ArmDirectoryName = 'ios-arm64_armv7';
+
+ final String xcode11AppFrameworkDirectory = path.join(
+ outputPath,
+ 'Debug',
+ 'App.xcframework',
+ xcode11ArmDirectoryName,
+ 'App.framework',
+ 'App',
+ );
+ final String xcode12AppFrameworkDirectory = path.join(
+ outputPath,
+ 'Debug',
+ 'App.xcframework',
+ xcode12ArmDirectoryName,
+ 'App.framework',
+ 'App',
+ );
+
+ // This seemed easier than an explicit Xcode version check.
+ String xcodeArmDirectoryName;
+ if (exists(File(xcode11AppFrameworkDirectory))) {
+ xcodeArmDirectoryName = xcode11ArmDirectoryName;
+ } else if (exists(File(xcode12AppFrameworkDirectory))) {
+ xcodeArmDirectoryName = xcode12ArmDirectoryName;
+ } else {
+ throw const FileSystemException('Expected App.framework binary to exist.');
+ }
+
+ checkFileExists(path.join(
+ outputPath,
+ 'Debug',
+ 'App.xcframework',
+ 'ios-x86_64-simulator',
+ 'App.framework',
+ 'App',
+ ));
+
+ section('Check profile, release builds has Dart AOT dylib');
+
+ for (final String mode in <String>['Profile', 'Release']) {
+ final String appFrameworkPath = path.join(
+ outputPath,
+ mode,
+ 'App.framework',
+ 'App',
+ );
+
+ await _checkFrameworkArchs(appFrameworkPath, mode);
+ await _checkBitcode(appFrameworkPath, mode);
+
+ final String aotSymbols = await dylibSymbols(appFrameworkPath);
+
+ if (!aotSymbols.contains('_kDartVmSnapshot')) {
+ throw TaskResult.failure('$mode App.framework missing Dart AOT');
+ }
+
+ checkFileNotExists(path.join(
+ outputPath,
+ mode,
+ 'App.framework',
+ 'flutter_assets',
+ 'vm_snapshot_data',
+ ));
+
+ checkFileExists(path.join(
+ outputPath,
+ mode,
+ 'App.xcframework',
+ xcodeArmDirectoryName,
+ 'App.framework',
+ 'App',
+ ));
+
+ checkFileNotExists(path.join(
+ outputPath,
+ mode,
+ 'App.xcframework',
+ 'ios-x86_64-simulator',
+ 'App.framework',
+ 'App',
+ ));
+ }
+
+ section("Check all modes' engine dylib");
+
+ for (final String mode in <String>['Debug', 'Profile', 'Release']) {
+ final String engineFrameworkPath = path.join(
+ outputPath,
+ mode,
+ 'Flutter.framework',
+ 'Flutter',
+ );
+
+ await _checkFrameworkArchs(engineFrameworkPath, mode);
+ await _checkBitcode(engineFrameworkPath, mode);
+
+ checkFileExists(path.join(
+ outputPath,
+ mode,
+ 'Flutter.xcframework',
+ xcodeArmDirectoryName,
+ 'Flutter.framework',
+ 'Flutter',
+ ));
+ final String simulatorFrameworkPath = path.join(
+ outputPath,
+ mode,
+ 'Flutter.xcframework',
+ 'ios-x86_64-simulator',
+ 'Flutter.framework',
+ 'Flutter',
+ );
+ if (mode == 'Debug') {
+ checkFileExists(simulatorFrameworkPath);
+ } else {
+ checkFileNotExists(simulatorFrameworkPath);
+ }
+ }
+
+ section("Check all modes' engine header");
+
+ for (final String mode in <String>['Debug', 'Profile', 'Release']) {
+ checkFileExists(path.join(outputPath, mode, 'Flutter.framework', 'Headers', 'Flutter.h'));
+ }
+
+ section('Check all modes have plugins');
+
+ for (final String mode in <String>['Debug', 'Profile', 'Release']) {
+ final String pluginFrameworkPath = path.join(
+ outputPath,
+ mode,
+ 'device_info.framework',
+ 'device_info',
+ );
+ await _checkFrameworkArchs(pluginFrameworkPath, mode);
+ await _checkBitcode(pluginFrameworkPath, mode);
+
+ checkFileExists(path.join(
+ outputPath,
+ mode,
+ 'device_info.xcframework',
+ xcodeArmDirectoryName,
+ 'device_info.framework',
+ 'device_info',
+ ));
+
+ checkFileExists(path.join(
+ outputPath,
+ mode,
+ 'device_info.xcframework',
+ xcodeArmDirectoryName,
+ 'device_info.framework',
+ 'Headers',
+ 'DeviceInfoPlugin.h',
+ ));
+
+ final String simulatorFrameworkPath = path.join(
+ outputPath,
+ mode,
+ 'device_info.xcframework',
+ 'ios-x86_64-simulator',
+ 'device_info.framework',
+ 'device_info',
+ );
+
+ final String simulatorFrameworkHeaderPath = path.join(
+ outputPath,
+ mode,
+ 'device_info.xcframework',
+ 'ios-x86_64-simulator',
+ 'device_info.framework',
+ 'Headers',
+ 'DeviceInfoPlugin.h',
+ );
+
+ if (mode == 'Debug') {
+ checkFileExists(simulatorFrameworkPath);
+ checkFileExists(simulatorFrameworkHeaderPath);
+ } else {
+ checkFileNotExists(simulatorFrameworkPath);
+ checkFileNotExists(simulatorFrameworkHeaderPath);
+ }
+ }
+
+ section('Check all modes have generated plugin registrant');
+
+ for (final String mode in <String>['Debug', 'Profile', 'Release']) {
+ if (!isModule) {
+ continue;
+ }
+ final String registrantFrameworkPath = path.join(
+ outputPath,
+ mode,
+ 'FlutterPluginRegistrant.framework',
+ 'FlutterPluginRegistrant'
+ );
+
+ await _checkFrameworkArchs(registrantFrameworkPath, mode);
+ await _checkBitcode(registrantFrameworkPath, mode);
+
+ checkFileExists(path.join(
+ outputPath,
+ mode,
+ 'FlutterPluginRegistrant.framework',
+ 'Headers',
+ 'GeneratedPluginRegistrant.h',
+ ));
+ checkFileExists(path.join(
+ outputPath,
+ mode,
+ 'FlutterPluginRegistrant.xcframework',
+ xcodeArmDirectoryName,
+ 'FlutterPluginRegistrant.framework',
+ 'Headers',
+ 'GeneratedPluginRegistrant.h',
+ ));
+ final String simulatorHeaderPath = path.join(
+ outputPath,
+ mode,
+ 'FlutterPluginRegistrant.xcframework',
+ 'ios-x86_64-simulator',
+ 'FlutterPluginRegistrant.framework',
+ 'Headers',
+ 'GeneratedPluginRegistrant.h',
+ );
+ if (mode == 'Debug') {
+ checkFileExists(simulatorHeaderPath);
+ } else {
+ checkFileNotExists(simulatorHeaderPath);
+ }
+ }
+
+ // This builds all build modes' frameworks by default
+ section('Build podspec');
+
+ const String cocoapodsOutputDirectoryName = 'flutter-frameworks-cocoapods';
+
+ await inDirectory(projectDir, () async {
+ await flutter(
+ 'build',
+ options: <String>[
+ 'ios-framework',
+ '--cocoapods',
+ '--universal',
+ '--force', // Allow podspec creation on master.
+ '--output=$cocoapodsOutputDirectoryName'
+ ],
+ );
+ });
+
+ final String cocoapodsOutputPath = path.join(projectDir.path, cocoapodsOutputDirectoryName);
+ for (final String mode in <String>['Debug', 'Profile', 'Release']) {
+ checkFileExists(path.join(
+ cocoapodsOutputPath,
+ mode,
+ 'Flutter.podspec',
+ ));
+
+ checkDirectoryExists(path.join(
+ cocoapodsOutputPath,
+ mode,
+ 'App.framework',
+ ));
+
+ if (Directory(path.join(
+ cocoapodsOutputPath,
+ mode,
+ 'FlutterPluginRegistrant.framework',
+ )).existsSync() !=
+ isModule) {
+ throw TaskResult.failure(
+ 'Unexpected FlutterPluginRegistrant.framework.');
+ }
+
+ checkDirectoryExists(path.join(
+ cocoapodsOutputPath,
+ mode,
+ 'device_info.framework',
+ ));
+
+ checkDirectoryExists(path.join(
+ cocoapodsOutputPath,
+ mode,
+ 'package_info.framework',
+ ));
+ }
+
+ if (File(path.join(
+ outputPath,
+ 'GeneratedPluginRegistrant.h',
+ )).existsSync() ==
+ isModule) {
+ throw TaskResult.failure('Unexpected GeneratedPluginRegistrant.h.');
+ }
+
+ if (File(path.join(
+ outputPath,
+ 'GeneratedPluginRegistrant.m',
+ )).existsSync() ==
+ isModule) {
+ throw TaskResult.failure('Unexpected GeneratedPluginRegistrant.m.');
+ }
+}
+
Future<void> _checkFrameworkArchs(String frameworkPath, String mode) async {
checkFileExists(frameworkPath);
diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
index 48cfd18..1c73a36 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
@@ -113,7 +113,7 @@
final String name = 'ios-framework';
@override
- final String description = 'Produces a .framework directory for a Flutter module '
+ final String description = 'Produces .frameworks for a Flutter project '
'and its plugins for integration into existing, plain Xcode projects.\n'
'This can only be run on macOS hosts.';
@@ -144,10 +144,6 @@
Future<void> validateCommand() async {
await super.validateCommand();
_project = FlutterProject.current();
- if (!_project.isModule) {
- throwToolExit('Building frameworks for iOS is only supported from a module.');
- }
-
if (!_platform.isMacOS) {
throwToolExit('Building frameworks for iOS is only supported on the Mac.');
}
@@ -178,7 +174,7 @@
}
if (!_project.ios.existsSync()) {
- throwToolExit('Module does not support iOS');
+ throwToolExit('Project does not support iOS');
}
final Directory outputDirectory = globals.fs.directory(globals.fs.path.absolute(globals.fs.path.normalize(outputArgument)));
@@ -233,6 +229,23 @@
}
globals.printStatus('Frameworks written to ${outputDirectory.path}.');
+
+ if (!_project.isModule && hasPlugins(_project)) {
+ // Apps do not generate a FlutterPluginRegistrant.framework. Users will need
+ // to copy the GeneratedPluginRegistrant class to their project manually.
+ final File pluginRegistrantHeader = _project.ios.pluginRegistrantHeader;
+ final File pluginRegistrantImplementation =
+ _project.ios.pluginRegistrantImplementation;
+ pluginRegistrantHeader.copySync(
+ outputDirectory.childFile(pluginRegistrantHeader.basename).path);
+ pluginRegistrantImplementation.copySync(outputDirectory
+ .childFile(pluginRegistrantImplementation.basename)
+ .path);
+ globals.printStatus(
+ '\nCopy the ${globals.fs.path.basenameWithoutExtension(pluginRegistrantHeader.path)} class into your project.\n'
+ 'See https://flutter.dev/docs/development/add-to-app/ios/add-flutter-screen#create-a-flutterengine for more information.');
+ }
+
return FlutterCommandResult.success();
}
@@ -459,6 +472,7 @@
xcodeBuildConfiguration,
'SYMROOT=${iPhoneBuildOutput.path}',
'BITCODE_GENERATION_MODE=$bitcodeGenerationMode',
+ 'ENABLE_BITCODE=YES', // Support host apps with bitcode enabled.
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
];
@@ -483,6 +497,7 @@
'-configuration',
xcodeBuildConfiguration,
'SYMROOT=${simulatorBuildOutput.path}',
+ 'ENABLE_BITCODE=YES', // Support host apps with bitcode enabled.
'ARCHS=x86_64',
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart
index 543b0fa..3883862 100644
--- a/packages/flutter_tools/lib/src/plugins.dart
+++ b/packages/flutter_tools/lib/src/plugins.dart
@@ -897,36 +897,24 @@
'framework': 'Flutter',
'plugins': iosPlugins,
};
- final String registryDirectory = project.ios.pluginRegistrantHost.path;
if (project.isModule) {
- final String registryClassesDirectory = globals.fs.path.join(registryDirectory, 'Classes');
+ final String registryDirectory = project.ios.pluginRegistrantHost.path;
_renderTemplateToFile(
_pluginRegistrantPodspecTemplate,
context,
globals.fs.path.join(registryDirectory, 'FlutterPluginRegistrant.podspec'),
);
- _renderTemplateToFile(
- _objcPluginRegistryHeaderTemplate,
- context,
- globals.fs.path.join(registryClassesDirectory, 'GeneratedPluginRegistrant.h'),
- );
- _renderTemplateToFile(
- _objcPluginRegistryImplementationTemplate,
- context,
- globals.fs.path.join(registryClassesDirectory, 'GeneratedPluginRegistrant.m'),
- );
- } else {
- _renderTemplateToFile(
- _objcPluginRegistryHeaderTemplate,
- context,
- globals.fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.h'),
- );
- _renderTemplateToFile(
- _objcPluginRegistryImplementationTemplate,
- context,
- globals.fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.m'),
- );
}
+ _renderTemplateToFile(
+ _objcPluginRegistryHeaderTemplate,
+ context,
+ project.ios.pluginRegistrantHeader.path,
+ );
+ _renderTemplateToFile(
+ _objcPluginRegistryImplementationTemplate,
+ context,
+ project.ios.pluginRegistrantImplementation.path,
+ );
}
/// The relative path from a project's main CMake file to the plugin symlink
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index 9e36c46..1ee6b9d 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -665,15 +665,12 @@
)
);
if (framework.existsSync()) {
- final Directory engineDest = ephemeralDirectory
- .childDirectory('Flutter')
- .childDirectory('engine');
final File podspec = framework.parent.childFile('Flutter.podspec');
globals.fsUtils.copyDirectorySync(
framework,
- engineDest.childDirectory('Flutter.framework'),
+ engineCopyDirectory.childDirectory('Flutter.framework'),
);
- podspec.copySync(engineDest.childFile('Flutter.podspec').path);
+ podspec.copySync(engineCopyDirectory.childFile('Flutter.podspec').path);
}
}
@@ -704,6 +701,22 @@
: hostAppRoot.childDirectory(_hostAppProjectName);
}
+ File get pluginRegistrantHeader {
+ final Directory registryDirectory = isModule ? pluginRegistrantHost.childDirectory('Classes') : pluginRegistrantHost;
+ return registryDirectory.childFile('GeneratedPluginRegistrant.h');
+ }
+
+ File get pluginRegistrantImplementation {
+ final Directory registryDirectory = isModule ? pluginRegistrantHost.childDirectory('Classes') : pluginRegistrantHost;
+ return registryDirectory.childFile('GeneratedPluginRegistrant.m');
+ }
+
+ Directory get engineCopyDirectory {
+ return isModule
+ ? ephemeralDirectory.childDirectory('Flutter').childDirectory('engine')
+ : hostAppRoot.childDirectory('Flutter');
+ }
+
Future<void> _overwriteFromTemplate(String path, Directory target) async {
final Template template = await Template.fromName(
path,