mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
This reverts commit aab9a76ee4
.
This commit is contained in:
parent
aab9a76ee4
commit
be2e7bb1c0
@ -17,392 +17,439 @@ Future<void> main() async {
|
|||||||
section('Create module project');
|
section('Create module project');
|
||||||
|
|
||||||
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
|
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
|
||||||
final Directory projectDir = Directory(path.join(tempDir.path, 'hello'));
|
|
||||||
try {
|
try {
|
||||||
await inDirectory(tempDir, () async {
|
await inDirectory(tempDir, () async {
|
||||||
|
section('Test module template');
|
||||||
|
|
||||||
|
final Directory moduleProjectDir =
|
||||||
|
Directory(path.join(tempDir.path, 'hello_module'));
|
||||||
await flutter(
|
await flutter(
|
||||||
'create',
|
'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>[
|
options: <String>[
|
||||||
'ios',
|
'--org',
|
||||||
'--debug',
|
'io.flutter.devicelab',
|
||||||
'--no-codesign',
|
'--template',
|
||||||
|
'module',
|
||||||
|
'hello_module'
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
// This builds all build modes' frameworks by default
|
await _testBuildIosFramework(moduleProjectDir, isModule: true);
|
||||||
section('Build frameworks');
|
|
||||||
|
|
||||||
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(
|
await flutter(
|
||||||
'build',
|
'create',
|
||||||
options: <String>[
|
options: <String>['--org', 'io.flutter.devicelab', 'hello_project'],
|
||||||
'ios-framework',
|
|
||||||
'--universal',
|
|
||||||
'--output=$outputDirectoryName'
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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);
|
return TaskResult.success(null);
|
||||||
} on TaskResult catch (taskResult) {
|
} on TaskResult catch (taskResult) {
|
||||||
return taskResult;
|
return taskResult;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return TaskResult.failure(e.toString());
|
return TaskResult.failure(e.toString());
|
||||||
} finally {
|
} 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 {
|
Future<void> _checkFrameworkArchs(String frameworkPath, String mode) async {
|
||||||
checkFileExists(frameworkPath);
|
checkFileExists(frameworkPath);
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
final String name = 'ios-framework';
|
final String name = 'ios-framework';
|
||||||
|
|
||||||
@override
|
@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'
|
'and its plugins for integration into existing, plain Xcode projects.\n'
|
||||||
'This can only be run on macOS hosts.';
|
'This can only be run on macOS hosts.';
|
||||||
|
|
||||||
@ -144,10 +144,6 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
Future<void> validateCommand() async {
|
Future<void> validateCommand() async {
|
||||||
await super.validateCommand();
|
await super.validateCommand();
|
||||||
_project = FlutterProject.current();
|
_project = FlutterProject.current();
|
||||||
if (!_project.isModule) {
|
|
||||||
throwToolExit('Building frameworks for iOS is only supported from a module.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_platform.isMacOS) {
|
if (!_platform.isMacOS) {
|
||||||
throwToolExit('Building frameworks for iOS is only supported on the Mac.');
|
throwToolExit('Building frameworks for iOS is only supported on the Mac.');
|
||||||
}
|
}
|
||||||
@ -178,7 +174,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!_project.ios.existsSync()) {
|
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)));
|
final Directory outputDirectory = globals.fs.directory(globals.fs.path.absolute(globals.fs.path.normalize(outputArgument)));
|
||||||
@ -233,6 +229,23 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
globals.printStatus('Frameworks written to ${outputDirectory.path}.');
|
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();
|
return FlutterCommandResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,6 +472,7 @@ end
|
|||||||
xcodeBuildConfiguration,
|
xcodeBuildConfiguration,
|
||||||
'SYMROOT=${iPhoneBuildOutput.path}',
|
'SYMROOT=${iPhoneBuildOutput.path}',
|
||||||
'BITCODE_GENERATION_MODE=$bitcodeGenerationMode',
|
'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.
|
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
|
||||||
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
||||||
];
|
];
|
||||||
@ -483,6 +497,7 @@ end
|
|||||||
'-configuration',
|
'-configuration',
|
||||||
xcodeBuildConfiguration,
|
xcodeBuildConfiguration,
|
||||||
'SYMROOT=${simulatorBuildOutput.path}',
|
'SYMROOT=${simulatorBuildOutput.path}',
|
||||||
|
'ENABLE_BITCODE=YES', // Support host apps with bitcode enabled.
|
||||||
'ARCHS=x86_64',
|
'ARCHS=x86_64',
|
||||||
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
|
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
|
||||||
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
||||||
|
@ -897,36 +897,24 @@ Future<void> _writeIOSPluginRegistrant(FlutterProject project, List<Plugin> plug
|
|||||||
'framework': 'Flutter',
|
'framework': 'Flutter',
|
||||||
'plugins': iosPlugins,
|
'plugins': iosPlugins,
|
||||||
};
|
};
|
||||||
final String registryDirectory = project.ios.pluginRegistrantHost.path;
|
|
||||||
if (project.isModule) {
|
if (project.isModule) {
|
||||||
final String registryClassesDirectory = globals.fs.path.join(registryDirectory, 'Classes');
|
final String registryDirectory = project.ios.pluginRegistrantHost.path;
|
||||||
_renderTemplateToFile(
|
_renderTemplateToFile(
|
||||||
_pluginRegistrantPodspecTemplate,
|
_pluginRegistrantPodspecTemplate,
|
||||||
context,
|
context,
|
||||||
globals.fs.path.join(registryDirectory, 'FlutterPluginRegistrant.podspec'),
|
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
|
/// The relative path from a project's main CMake file to the plugin symlink
|
||||||
|
@ -665,15 +665,12 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (framework.existsSync()) {
|
if (framework.existsSync()) {
|
||||||
final Directory engineDest = ephemeralDirectory
|
|
||||||
.childDirectory('Flutter')
|
|
||||||
.childDirectory('engine');
|
|
||||||
final File podspec = framework.parent.childFile('Flutter.podspec');
|
final File podspec = framework.parent.childFile('Flutter.podspec');
|
||||||
globals.fsUtils.copyDirectorySync(
|
globals.fsUtils.copyDirectorySync(
|
||||||
framework,
|
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 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
|
|||||||
: hostAppRoot.childDirectory(_hostAppProjectName);
|
: 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 {
|
Future<void> _overwriteFromTemplate(String path, Directory target) async {
|
||||||
final Template template = await Template.fromName(
|
final Template template = await Template.fromName(
|
||||||
path,
|
path,
|
||||||
|
Loading…
Reference in New Issue
Block a user