mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Refactor BuildIOSFrameworkCommand with common darwin baseclass (#105194)
This commit is contained in:
parent
8dbc3884d9
commit
dffddf00a2
@ -177,9 +177,9 @@ def flutter_install_ios_engine_pod(ios_application_path = nil)
|
|||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'Flutter'
|
s.name = 'Flutter'
|
||||||
s.version = '1.0.0'
|
s.version = '1.0.0'
|
||||||
s.summary = 'High-performance, high-fidelity mobile apps.'
|
s.summary = 'A UI toolkit for beautiful and fast apps.'
|
||||||
s.homepage = 'https://flutter.io'
|
s.homepage = 'https://flutter.dev'
|
||||||
s.license = { :type => 'MIT' }
|
s.license = { :type => 'BSD' }
|
||||||
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
|
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
|
||||||
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
|
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
|
||||||
s.ios.deployment_target = '11.0'
|
s.ios.deployment_target = '11.0'
|
||||||
@ -215,9 +215,9 @@ def flutter_install_macos_engine_pod(mac_application_path = nil)
|
|||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'FlutterMacOS'
|
s.name = 'FlutterMacOS'
|
||||||
s.version = '1.0.0'
|
s.version = '1.0.0'
|
||||||
s.summary = 'High-performance, high-fidelity mobile apps.'
|
s.summary = 'A UI toolkit for beautiful and fast apps.'
|
||||||
s.homepage = 'https://flutter.io'
|
s.homepage = 'https://flutter.dev'
|
||||||
s.license = { :type => 'MIT' }
|
s.license = { :type => 'BSD' }
|
||||||
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
|
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
|
||||||
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
|
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
|
||||||
s.osx.deployment_target = '10.11'
|
s.osx.deployment_target = '10.11'
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:process/process.dart';
|
||||||
|
|
||||||
import '../artifacts.dart';
|
import '../artifacts.dart';
|
||||||
import '../base/common.dart';
|
import '../base/common.dart';
|
||||||
import '../base/file_system.dart';
|
import '../base/file_system.dart';
|
||||||
|
import '../base/io.dart';
|
||||||
import '../base/logger.dart';
|
import '../base/logger.dart';
|
||||||
import '../base/platform.dart';
|
import '../base/platform.dart';
|
||||||
import '../base/process.dart';
|
import '../base/process.dart';
|
||||||
@ -23,18 +25,14 @@ import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommand
|
|||||||
import '../version.dart';
|
import '../version.dart';
|
||||||
import 'build.dart';
|
import 'build.dart';
|
||||||
|
|
||||||
/// Produces a .framework for integration into a host iOS app. The .framework
|
abstract class BuildFrameworkCommand extends BuildSubCommand {
|
||||||
/// contains the Flutter engine and framework code as well as plugins. It can
|
BuildFrameworkCommand({
|
||||||
/// be integrated into plain Xcode projects without using or other package
|
|
||||||
/// managers.
|
|
||||||
class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|
||||||
BuildIOSFrameworkCommand({
|
|
||||||
// Instantiating FlutterVersion kicks off networking, so delay until it's needed, but allow test injection.
|
// Instantiating FlutterVersion kicks off networking, so delay until it's needed, but allow test injection.
|
||||||
@visibleForTesting FlutterVersion? flutterVersion,
|
@visibleForTesting FlutterVersion? flutterVersion,
|
||||||
required BuildSystem buildSystem,
|
required BuildSystem buildSystem,
|
||||||
required bool verboseHelp,
|
required bool verboseHelp,
|
||||||
Cache? cache,
|
Cache? cache,
|
||||||
Platform? platform
|
Platform? platform,
|
||||||
}) : _injectedFlutterVersion = flutterVersion,
|
}) : _injectedFlutterVersion = flutterVersion,
|
||||||
_buildSystem = buildSystem,
|
_buildSystem = buildSystem,
|
||||||
_injectedCache = cache,
|
_injectedCache = cache,
|
||||||
@ -42,7 +40,6 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
super(verboseHelp: verboseHelp) {
|
super(verboseHelp: verboseHelp) {
|
||||||
addTreeShakeIconsFlag();
|
addTreeShakeIconsFlag();
|
||||||
usesTargetOption();
|
usesTargetOption();
|
||||||
usesFlavorOption();
|
|
||||||
usesPubOption();
|
usesPubOption();
|
||||||
usesDartDefineOption();
|
usesDartDefineOption();
|
||||||
addSplitDebugInfoOption();
|
addSplitDebugInfoOption();
|
||||||
@ -67,16 +64,6 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
help: 'Whether to produce a framework for the release build configuration. '
|
help: 'Whether to produce a framework for the release build configuration. '
|
||||||
'By default, all build configurations are built.'
|
'By default, all build configurations are built.'
|
||||||
)
|
)
|
||||||
..addFlag('universal',
|
|
||||||
help: '(deprecated) Produce universal frameworks that include all valid architectures.',
|
|
||||||
hide: !verboseHelp,
|
|
||||||
)
|
|
||||||
..addFlag('xcframework',
|
|
||||||
help: 'Produce xcframeworks that include all valid architectures.',
|
|
||||||
negatable: false,
|
|
||||||
defaultsTo: true,
|
|
||||||
hide: !verboseHelp,
|
|
||||||
)
|
|
||||||
..addFlag('cocoapods',
|
..addFlag('cocoapods',
|
||||||
help: 'Produce a Flutter.podspec instead of an engine Flutter.xcframework (recommended if host app uses CocoaPods).',
|
help: 'Produce a Flutter.podspec instead of an engine Flutter.xcframework (recommended if host app uses CocoaPods).',
|
||||||
)
|
)
|
||||||
@ -96,35 +83,27 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final BuildSystem? _buildSystem;
|
final BuildSystem? _buildSystem;
|
||||||
|
@protected
|
||||||
BuildSystem get buildSystem => _buildSystem ?? globals.buildSystem;
|
BuildSystem get buildSystem => _buildSystem ?? globals.buildSystem;
|
||||||
|
|
||||||
Cache get _cache => _injectedCache ?? globals.cache;
|
@protected
|
||||||
|
Cache get cache => _injectedCache ?? globals.cache;
|
||||||
final Cache? _injectedCache;
|
final Cache? _injectedCache;
|
||||||
|
|
||||||
Platform get _platform => _injectedPlatform ?? globals.platform;
|
@protected
|
||||||
|
Platform get platform => _injectedPlatform ?? globals.platform;
|
||||||
final Platform? _injectedPlatform;
|
final Platform? _injectedPlatform;
|
||||||
|
|
||||||
// FlutterVersion.instance kicks off git processing which can sometimes fail, so don't try it until needed.
|
// FlutterVersion.instance kicks off git processing which can sometimes fail, so don't try it until needed.
|
||||||
FlutterVersion get _flutterVersion => _injectedFlutterVersion ?? globals.flutterVersion;
|
@protected
|
||||||
|
FlutterVersion get flutterVersion => _injectedFlutterVersion ?? globals.flutterVersion;
|
||||||
final FlutterVersion? _injectedFlutterVersion;
|
final FlutterVersion? _injectedFlutterVersion;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get reportNullSafety => false;
|
bool get reportNullSafety => false;
|
||||||
|
|
||||||
@override
|
@protected
|
||||||
final String name = 'ios-framework';
|
late final FlutterProject project = FlutterProject.current();
|
||||||
|
|
||||||
@override
|
|
||||||
final String description = 'Produces .xcframeworks for a Flutter project '
|
|
||||||
'and its plugins for integration into existing, plain Xcode projects.\n'
|
|
||||||
'This can only be run on macOS hosts.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
|
||||||
DevelopmentArtifact.iOS,
|
|
||||||
};
|
|
||||||
|
|
||||||
late final FlutterProject _project = FlutterProject.current();
|
|
||||||
|
|
||||||
Future<List<BuildInfo>> getBuildInfos() async {
|
Future<List<BuildInfo>> getBuildInfos() async {
|
||||||
final List<BuildInfo> buildInfos = <BuildInfo>[];
|
final List<BuildInfo> buildInfos = <BuildInfo>[];
|
||||||
@ -143,7 +122,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get supported => _platform.isMacOS;
|
bool get supported => platform.isMacOS;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> validateCommand() async {
|
Future<void> validateCommand() async {
|
||||||
@ -152,14 +131,94 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
throwToolExit('Building frameworks for iOS is only supported on the Mac.');
|
throwToolExit('Building frameworks for iOS is only supported on the Mac.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boolArgDeprecated('universal')) {
|
|
||||||
throwToolExit('--universal has been deprecated, only XCFrameworks are supported.');
|
|
||||||
}
|
|
||||||
if ((await getBuildInfos()).isEmpty) {
|
if ((await getBuildInfos()).isEmpty) {
|
||||||
throwToolExit('At least one of "--debug" or "--profile", or "--release" is required.');
|
throwToolExit('At least one of "--debug" or "--profile", or "--release" is required.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<void> produceXCFramework(
|
||||||
|
Iterable<Directory> frameworks,
|
||||||
|
String frameworkBinaryName,
|
||||||
|
Directory outputDirectory,
|
||||||
|
ProcessManager processManager,
|
||||||
|
) async {
|
||||||
|
final List<String> xcframeworkCommand = <String>[
|
||||||
|
'xcrun',
|
||||||
|
'xcodebuild',
|
||||||
|
'-create-xcframework',
|
||||||
|
for (Directory framework in frameworks) ...<String>[
|
||||||
|
'-framework',
|
||||||
|
framework.path,
|
||||||
|
...framework.parent
|
||||||
|
.listSync()
|
||||||
|
.where((FileSystemEntity entity) =>
|
||||||
|
entity.basename.endsWith('bcsymbolmap') || entity.basename.endsWith('dSYM'))
|
||||||
|
.map((FileSystemEntity entity) => <String>['-debug-symbols', entity.path])
|
||||||
|
.expand<String>((List<String> parameter) => parameter),
|
||||||
|
],
|
||||||
|
'-output',
|
||||||
|
outputDirectory.childDirectory('$frameworkBinaryName.xcframework').path,
|
||||||
|
];
|
||||||
|
|
||||||
|
final ProcessResult xcframeworkResult = await processManager.run(
|
||||||
|
xcframeworkCommand,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (xcframeworkResult.exitCode != 0) {
|
||||||
|
throwToolExit('Unable to create $frameworkBinaryName.xcframework: ${xcframeworkResult.stderr}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Produces a .framework for integration into a host iOS app. The .framework
|
||||||
|
/// contains the Flutter engine and framework code as well as plugins. It can
|
||||||
|
/// be integrated into plain Xcode projects without using or other package
|
||||||
|
/// managers.
|
||||||
|
class BuildIOSFrameworkCommand extends BuildFrameworkCommand {
|
||||||
|
BuildIOSFrameworkCommand({
|
||||||
|
super.flutterVersion,
|
||||||
|
required super.buildSystem,
|
||||||
|
required bool verboseHelp,
|
||||||
|
super.cache,
|
||||||
|
super.platform,
|
||||||
|
}) : super(verboseHelp: verboseHelp) {
|
||||||
|
usesFlavorOption();
|
||||||
|
|
||||||
|
argParser
|
||||||
|
..addFlag('universal',
|
||||||
|
help: '(deprecated) Produce universal frameworks that include all valid architectures.',
|
||||||
|
hide: !verboseHelp,
|
||||||
|
)
|
||||||
|
..addFlag('xcframework',
|
||||||
|
help: 'Produce xcframeworks that include all valid architectures.',
|
||||||
|
negatable: false,
|
||||||
|
defaultsTo: true,
|
||||||
|
hide: !verboseHelp,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String name = 'ios-framework';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String description = 'Produces .xcframeworks for a Flutter project '
|
||||||
|
'and its plugins for integration into existing, plain iOS Xcode projects.\n'
|
||||||
|
'This can only be run on macOS hosts.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
||||||
|
DevelopmentArtifact.iOS,
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> validateCommand() async {
|
||||||
|
await super.validateCommand();
|
||||||
|
|
||||||
|
if (boolArgDeprecated('universal')) {
|
||||||
|
throwToolExit('--universal has been deprecated, only XCFrameworks are supported.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<FlutterCommandResult> runCommand() async {
|
Future<FlutterCommandResult> runCommand() async {
|
||||||
final String outputArgument = stringArgDeprecated('output')
|
final String outputArgument = stringArgDeprecated('output')
|
||||||
@ -169,7 +228,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
throwToolExit('--output is required.');
|
throwToolExit('--output is required.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_project.ios.existsSync()) {
|
if (!project.ios.existsSync()) {
|
||||||
throwToolExit('Project does not support iOS');
|
throwToolExit('Project does not support iOS');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +236,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
final List<BuildInfo> buildInfos = await getBuildInfos();
|
final List<BuildInfo> buildInfos = await getBuildInfos();
|
||||||
displayNullSafetyMode(buildInfos.first);
|
displayNullSafetyMode(buildInfos.first);
|
||||||
for (final BuildInfo buildInfo in buildInfos) {
|
for (final BuildInfo buildInfo in buildInfos) {
|
||||||
final String? productBundleIdentifier = await _project.ios.productBundleIdentifier(buildInfo);
|
final String? productBundleIdentifier = await project.ios.productBundleIdentifier(buildInfo);
|
||||||
globals.printStatus('Building frameworks for $productBundleIdentifier in ${getNameForBuildMode(buildInfo.mode)} mode...');
|
globals.printStatus('Building frameworks for $productBundleIdentifier in ${getNameForBuildMode(buildInfo.mode)} mode...');
|
||||||
final String xcodeBuildConfiguration = sentenceCase(getNameForBuildMode(buildInfo.mode));
|
final String xcodeBuildConfiguration = sentenceCase(getNameForBuildMode(buildInfo.mode));
|
||||||
final Directory modeDirectory = outputDirectory.childDirectory(xcodeBuildConfiguration);
|
final Directory modeDirectory = outputDirectory.childDirectory(xcodeBuildConfiguration);
|
||||||
@ -202,9 +261,9 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
buildInfo, modeDirectory, iPhoneBuildOutput, simulatorBuildOutput);
|
buildInfo, modeDirectory, iPhoneBuildOutput, simulatorBuildOutput);
|
||||||
|
|
||||||
// Build and copy plugins.
|
// Build and copy plugins.
|
||||||
await processPodsIfNeeded(_project.ios, getIosBuildDirectory(), buildInfo.mode);
|
await processPodsIfNeeded(project.ios, getIosBuildDirectory(), buildInfo.mode);
|
||||||
if (hasPlugins(_project)) {
|
if (hasPlugins(project)) {
|
||||||
await _producePlugins(buildInfo.mode, xcodeBuildConfiguration, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory, outputDirectory);
|
await _producePlugins(buildInfo.mode, xcodeBuildConfiguration, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Status status = globals.logger.startProgress(
|
final Status status = globals.logger.startProgress(
|
||||||
@ -225,12 +284,12 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
|
|
||||||
globals.printStatus('Frameworks written to ${outputDirectory.path}.');
|
globals.printStatus('Frameworks written to ${outputDirectory.path}.');
|
||||||
|
|
||||||
if (!_project.isModule && hasPlugins(_project)) {
|
if (!project.isModule && hasPlugins(project)) {
|
||||||
// Apps do not generate a FlutterPluginRegistrant.framework. Users will need
|
// Apps do not generate a FlutterPluginRegistrant.framework. Users will need
|
||||||
// to copy the GeneratedPluginRegistrant class to their project manually.
|
// to copy the GeneratedPluginRegistrant class to their project manually.
|
||||||
final File pluginRegistrantHeader = _project.ios.pluginRegistrantHeader;
|
final File pluginRegistrantHeader = project.ios.pluginRegistrantHeader;
|
||||||
final File pluginRegistrantImplementation =
|
final File pluginRegistrantImplementation =
|
||||||
_project.ios.pluginRegistrantImplementation;
|
project.ios.pluginRegistrantImplementation;
|
||||||
pluginRegistrantHeader.copySync(
|
pluginRegistrantHeader.copySync(
|
||||||
outputDirectory.childFile(pluginRegistrantHeader.basename).path);
|
outputDirectory.childFile(pluginRegistrantHeader.basename).path);
|
||||||
pluginRegistrantImplementation.copySync(outputDirectory
|
pluginRegistrantImplementation.copySync(outputDirectory
|
||||||
@ -250,10 +309,10 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
void produceFlutterPodspec(BuildMode mode, Directory modeDirectory, { bool force = false }) {
|
void produceFlutterPodspec(BuildMode mode, Directory modeDirectory, { bool force = false }) {
|
||||||
final Status status = globals.logger.startProgress(' ├─Creating Flutter.podspec...');
|
final Status status = globals.logger.startProgress(' ├─Creating Flutter.podspec...');
|
||||||
try {
|
try {
|
||||||
final GitTagVersion gitTagVersion = _flutterVersion.gitTagVersion;
|
final GitTagVersion gitTagVersion = flutterVersion.gitTagVersion;
|
||||||
if (!force && (gitTagVersion.x == null || gitTagVersion.y == null || gitTagVersion.z == null || gitTagVersion.commits != 0)) {
|
if (!force && (gitTagVersion.x == null || gitTagVersion.y == null || gitTagVersion.z == null || gitTagVersion.commits != 0)) {
|
||||||
throwToolExit(
|
throwToolExit(
|
||||||
'--cocoapods is only supported on the dev, beta, or stable channels. Detected version is ${_flutterVersion.frameworkVersion}');
|
'--cocoapods is only supported on the dev, beta, or stable channels. Detected version is ${flutterVersion.frameworkVersion}');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Podspecs use semantic versioning, which don't support hotfixes.
|
// Podspecs use semantic versioning, which don't support hotfixes.
|
||||||
@ -262,7 +321,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
// new artifacts when the source URL changes.
|
// new artifacts when the source URL changes.
|
||||||
final int minorHotfixVersion = (gitTagVersion.z ?? 0) * 100 + (gitTagVersion.hotfix ?? 0);
|
final int minorHotfixVersion = (gitTagVersion.z ?? 0) * 100 + (gitTagVersion.hotfix ?? 0);
|
||||||
|
|
||||||
final File license = _cache.getLicenseFile();
|
final File license = cache.getLicenseFile();
|
||||||
if (!license.existsSync()) {
|
if (!license.existsSync()) {
|
||||||
throwToolExit('Could not find license at ${license.path}');
|
throwToolExit('Could not find license at ${license.path}');
|
||||||
}
|
}
|
||||||
@ -272,7 +331,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
final String podspecContents = '''
|
final String podspecContents = '''
|
||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'Flutter'
|
s.name = 'Flutter'
|
||||||
s.version = '${gitTagVersion.x}.${gitTagVersion.y}.$minorHotfixVersion' # ${_flutterVersion.frameworkVersion}
|
s.version = '${gitTagVersion.x}.${gitTagVersion.y}.$minorHotfixVersion' # ${flutterVersion.frameworkVersion}
|
||||||
s.summary = 'A UI toolkit for beautiful and fast apps.'
|
s.summary = 'A UI toolkit for beautiful and fast apps.'
|
||||||
s.description = <<-DESC
|
s.description = <<-DESC
|
||||||
Flutter is Google's UI toolkit for building beautiful, fast apps for mobile, web, desktop, and embedded devices from a single codebase.
|
Flutter is Google's UI toolkit for building beautiful, fast apps for mobile, web, desktop, and embedded devices from a single codebase.
|
||||||
@ -285,7 +344,7 @@ $licenseSource
|
|||||||
LICENSE
|
LICENSE
|
||||||
}
|
}
|
||||||
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
|
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
|
||||||
s.source = { :http => '${_cache.storageBaseUrl}/flutter_infra_release/flutter/${_cache.engineRevision}/$artifactsMode/artifacts.zip' }
|
s.source = { :http => '${cache.storageBaseUrl}/flutter_infra_release/flutter/${cache.engineRevision}/$artifactsMode/artifacts.zip' }
|
||||||
s.documentation_url = 'https://flutter.dev/docs'
|
s.documentation_url = 'https://flutter.dev/docs'
|
||||||
s.platform = :ios, '11.0'
|
s.platform = :ios, '11.0'
|
||||||
s.vendored_frameworks = 'Flutter.xcframework'
|
s.vendored_frameworks = 'Flutter.xcframework'
|
||||||
@ -356,7 +415,7 @@ end
|
|||||||
final Environment environment = Environment(
|
final Environment environment = Environment(
|
||||||
projectDir: globals.fs.currentDirectory,
|
projectDir: globals.fs.currentDirectory,
|
||||||
outputDir: outputBuildDirectory,
|
outputDir: outputBuildDirectory,
|
||||||
buildDir: _project.dartTool.childDirectory('flutter_build'),
|
buildDir: project.dartTool.childDirectory('flutter_build'),
|
||||||
cacheDir: globals.cache.getRoot(),
|
cacheDir: globals.cache.getRoot(),
|
||||||
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
|
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
|
||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
@ -401,7 +460,12 @@ end
|
|||||||
status.stop();
|
status.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
await _produceXCFramework(frameworks, 'App', outputDirectory);
|
await BuildFrameworkCommand.produceXCFramework(
|
||||||
|
frameworks,
|
||||||
|
'App',
|
||||||
|
outputDirectory,
|
||||||
|
globals.processManager,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _producePlugins(
|
Future<void> _producePlugins(
|
||||||
@ -410,7 +474,6 @@ end
|
|||||||
Directory iPhoneBuildOutput,
|
Directory iPhoneBuildOutput,
|
||||||
Directory simulatorBuildOutput,
|
Directory simulatorBuildOutput,
|
||||||
Directory modeDirectory,
|
Directory modeDirectory,
|
||||||
Directory outputDirectory,
|
|
||||||
) async {
|
) async {
|
||||||
final Status status = globals.logger.startProgress(
|
final Status status = globals.logger.startProgress(
|
||||||
' ├─Building plugins...'
|
' ├─Building plugins...'
|
||||||
@ -437,7 +500,7 @@ end
|
|||||||
|
|
||||||
RunResult buildPluginsResult = await globals.processUtils.run(
|
RunResult buildPluginsResult = await globals.processUtils.run(
|
||||||
pluginsBuildCommand,
|
pluginsBuildCommand,
|
||||||
workingDirectory: _project.ios.hostAppRoot.childDirectory('Pods').path,
|
workingDirectory: project.ios.hostAppRoot.childDirectory('Pods').path,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (buildPluginsResult.exitCode != 0) {
|
if (buildPluginsResult.exitCode != 0) {
|
||||||
@ -464,7 +527,7 @@ end
|
|||||||
|
|
||||||
buildPluginsResult = await globals.processUtils.run(
|
buildPluginsResult = await globals.processUtils.run(
|
||||||
pluginsBuildCommand,
|
pluginsBuildCommand,
|
||||||
workingDirectory: _project.ios.hostAppRoot
|
workingDirectory: project.ios.hostAppRoot
|
||||||
.childDirectory('Pods')
|
.childDirectory('Pods')
|
||||||
.path,
|
.path,
|
||||||
);
|
);
|
||||||
@ -500,46 +563,16 @@ end
|
|||||||
.childDirectory(podFrameworkName),
|
.childDirectory(podFrameworkName),
|
||||||
];
|
];
|
||||||
|
|
||||||
await _produceXCFramework(frameworks, binaryName, modeDirectory);
|
await BuildFrameworkCommand.produceXCFramework(
|
||||||
|
frameworks,
|
||||||
|
binaryName,
|
||||||
|
modeDirectory,
|
||||||
|
globals.processManager,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
status.stop();
|
status.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _produceXCFramework(Iterable<Directory> frameworks,
|
|
||||||
String frameworkBinaryName, Directory outputDirectory) async {
|
|
||||||
if (!boolArgDeprecated('xcframework')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final List<String> xcframeworkCommand = <String>[
|
|
||||||
...globals.xcode!.xcrunCommand(),
|
|
||||||
'xcodebuild',
|
|
||||||
'-create-xcframework',
|
|
||||||
for (Directory framework in frameworks) ...<String>[
|
|
||||||
'-framework',
|
|
||||||
framework.path,
|
|
||||||
...framework.parent
|
|
||||||
.listSync()
|
|
||||||
.where((FileSystemEntity entity) =>
|
|
||||||
entity.basename.endsWith('bcsymbolmap') ||
|
|
||||||
entity.basename.endsWith('dSYM'))
|
|
||||||
.map((FileSystemEntity entity) =>
|
|
||||||
<String>['-debug-symbols', entity.path])
|
|
||||||
.expand<String>((List<String> parameter) => parameter),
|
|
||||||
],
|
|
||||||
'-output',
|
|
||||||
outputDirectory.childDirectory('$frameworkBinaryName.xcframework').path,
|
|
||||||
];
|
|
||||||
|
|
||||||
final RunResult xcframeworkResult = await globals.processUtils.run(
|
|
||||||
xcframeworkCommand,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (xcframeworkResult.exitCode != 0) {
|
|
||||||
throwToolExit(
|
|
||||||
'Unable to create $frameworkBinaryName.xcframework: ${xcframeworkResult.stderr}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -271,4 +271,83 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('XCFrameworks', () {
|
||||||
|
MemoryFileSystem fileSystem;
|
||||||
|
FakeProcessManager fakeProcessManager;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
fileSystem = MemoryFileSystem.test();
|
||||||
|
fakeProcessManager = FakeProcessManager.empty();
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('created', () async {
|
||||||
|
final Directory frameworkA = fileSystem.directory('FrameworkA.framework')..createSync();
|
||||||
|
final Directory frameworkB = fileSystem.directory('FrameworkB.framework')..createSync();
|
||||||
|
final Directory output = fileSystem.directory('output');
|
||||||
|
|
||||||
|
fakeProcessManager.addCommand(FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'xcrun',
|
||||||
|
'xcodebuild',
|
||||||
|
'-create-xcframework',
|
||||||
|
'-framework',
|
||||||
|
frameworkA.path,
|
||||||
|
'-framework',
|
||||||
|
frameworkB.path,
|
||||||
|
'-output',
|
||||||
|
output.childDirectory('Combine.xcframework').path,
|
||||||
|
],
|
||||||
|
));
|
||||||
|
await BuildFrameworkCommand.produceXCFramework(
|
||||||
|
<Directory>[frameworkA, frameworkB],
|
||||||
|
'Combine',
|
||||||
|
output,
|
||||||
|
fakeProcessManager,
|
||||||
|
);
|
||||||
|
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('created with symbols', () async {
|
||||||
|
final Directory parentA = fileSystem.directory('FrameworkA')..createSync();
|
||||||
|
final File bcsymbolmapA = parentA.childFile('ABC123.bcsymbolmap')..createSync();
|
||||||
|
final File dSYMA = parentA.childFile('FrameworkA.framework.dSYM')..createSync();
|
||||||
|
final Directory frameworkA = parentA.childDirectory('FrameworkA.framework')..createSync();
|
||||||
|
|
||||||
|
final Directory parentB = fileSystem.directory('FrameworkB')..createSync();
|
||||||
|
final File bcsymbolmapB = parentB.childFile('ZYX987.bcsymbolmap')..createSync();
|
||||||
|
final File dSYMB = parentB.childFile('FrameworkB.framework.dSYM')..createSync();
|
||||||
|
final Directory frameworkB = parentB.childDirectory('FrameworkB.framework')..createSync();
|
||||||
|
final Directory output = fileSystem.directory('output');
|
||||||
|
|
||||||
|
fakeProcessManager.addCommand(FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'xcrun',
|
||||||
|
'xcodebuild',
|
||||||
|
'-create-xcframework',
|
||||||
|
'-framework',
|
||||||
|
frameworkA.path,
|
||||||
|
'-debug-symbols',
|
||||||
|
bcsymbolmapA.path,
|
||||||
|
'-debug-symbols',
|
||||||
|
dSYMA.path,
|
||||||
|
'-framework',
|
||||||
|
frameworkB.path,
|
||||||
|
'-debug-symbols',
|
||||||
|
bcsymbolmapB.path,
|
||||||
|
'-debug-symbols',
|
||||||
|
dSYMB.path,
|
||||||
|
'-output',
|
||||||
|
output.childDirectory('Combine.xcframework').path,
|
||||||
|
],
|
||||||
|
));
|
||||||
|
await BuildFrameworkCommand.produceXCFramework(
|
||||||
|
<Directory>[frameworkA, frameworkB],
|
||||||
|
'Combine',
|
||||||
|
output,
|
||||||
|
fakeProcessManager,
|
||||||
|
);
|
||||||
|
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user