Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
dffddf00
Unverified
Commit
dffddf00
authored
Jun 02, 2022
by
Jenn Magder
Committed by
GitHub
Jun 02, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor BuildIOSFrameworkCommand with common darwin baseclass (#105194)
parent
8dbc3884
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
211 additions
and
99 deletions
+211
-99
podhelper.rb
packages/flutter_tools/bin/podhelper.rb
+6
-6
build_ios_framework.dart
...s/flutter_tools/lib/src/commands/build_ios_framework.dart
+126
-93
build_darwin_framework_test.dart
.../commands.shard/hermetic/build_darwin_framework_test.dart
+79
-0
No files found.
packages/flutter_tools/bin/podhelper.rb
View file @
dffddf00
...
...
@@ -177,9 +177,9 @@ def flutter_install_ios_engine_pod(ios_application_path = nil)
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = '
High-performance, high-fidelity mobile
apps.'
s.homepage = 'https://flutter.
io
'
s.license = { :type => '
MIT
' }
s.summary = '
A UI toolkit for beautiful and fast
apps.'
s.homepage = 'https://flutter.
dev
'
s.license = { :type => '
BSD
' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
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|
s.name = 'FlutterMacOS'
s.version = '1.0.0'
s.summary = '
High-performance, high-fidelity mobile
apps.'
s.homepage = 'https://flutter.
io
'
s.license = { :type => '
MIT
' }
s.summary = '
A UI toolkit for beautiful and fast
apps.'
s.homepage = 'https://flutter.
dev
'
s.license = { :type => '
BSD
' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.osx.deployment_target = '10.11'
...
...
packages/flutter_tools/lib/src/commands/build_ios_framework.dart
View file @
dffddf00
...
...
@@ -3,10 +3,12 @@
// found in the LICENSE file.
import
'package:meta/meta.dart'
;
import
'package:process/process.dart'
;
import
'../artifacts.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/platform.dart'
;
import
'../base/process.dart'
;
...
...
@@ -23,18 +25,14 @@ import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommand
import
'../version.dart'
;
import
'build.dart'
;
/// 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
BuildSubCommand
{
BuildIOSFrameworkCommand
({
abstract
class
BuildFrameworkCommand
extends
BuildSubCommand
{
BuildFrameworkCommand
({
// Instantiating FlutterVersion kicks off networking, so delay until it's needed, but allow test injection.
@visibleForTesting
FlutterVersion
?
flutterVersion
,
required
BuildSystem
buildSystem
,
required
bool
verboseHelp
,
Cache
?
cache
,
Platform
?
platform
Platform
?
platform
,
})
:
_injectedFlutterVersion
=
flutterVersion
,
_buildSystem
=
buildSystem
,
_injectedCache
=
cache
,
...
...
@@ -42,7 +40,6 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
super
(
verboseHelp:
verboseHelp
)
{
addTreeShakeIconsFlag
();
usesTargetOption
();
usesFlavorOption
();
usesPubOption
();
usesDartDefineOption
();
addSplitDebugInfoOption
();
...
...
@@ -67,16 +64,6 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
help:
'Whether to produce a framework for the release build configuration. '
'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'
,
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
;
@protected
BuildSystem
get
buildSystem
=>
_buildSystem
??
globals
.
buildSystem
;
Cache
get
_cache
=>
_injectedCache
??
globals
.
cache
;
@protected
Cache
get
cache
=>
_injectedCache
??
globals
.
cache
;
final
Cache
?
_injectedCache
;
Platform
get
_platform
=>
_injectedPlatform
??
globals
.
platform
;
@protected
Platform
get
platform
=>
_injectedPlatform
??
globals
.
platform
;
final
Platform
?
_injectedPlatform
;
// 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
;
@override
bool
get
reportNullSafety
=>
false
;
@override
final
String
name
=
'ios-framework'
;
@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
();
@protected
late
final
FlutterProject
project
=
FlutterProject
.
current
();
Future
<
List
<
BuildInfo
>>
getBuildInfos
()
async
{
final
List
<
BuildInfo
>
buildInfos
=
<
BuildInfo
>[];
...
...
@@ -143,7 +122,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
}
@override
bool
get
supported
=>
_
platform
.
isMacOS
;
bool
get
supported
=>
platform
.
isMacOS
;
@override
Future
<
void
>
validateCommand
()
async
{
...
...
@@ -152,14 +131,94 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
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
)
{
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
Future
<
FlutterCommandResult
>
runCommand
()
async
{
final
String
outputArgument
=
stringArgDeprecated
(
'output'
)
...
...
@@ -169,7 +228,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
throwToolExit
(
'--output is required.'
);
}
if
(!
_
project
.
ios
.
existsSync
())
{
if
(!
project
.
ios
.
existsSync
())
{
throwToolExit
(
'Project does not support iOS'
);
}
...
...
@@ -177,7 +236,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
final
List
<
BuildInfo
>
buildInfos
=
await
getBuildInfos
();
displayNullSafetyMode
(
buildInfos
.
first
);
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...'
);
final
String
xcodeBuildConfiguration
=
sentenceCase
(
getNameForBuildMode
(
buildInfo
.
mode
));
final
Directory
modeDirectory
=
outputDirectory
.
childDirectory
(
xcodeBuildConfiguration
);
...
...
@@ -202,9 +261,9 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
buildInfo
,
modeDirectory
,
iPhoneBuildOutput
,
simulatorBuildOutput
);
// Build and copy plugins.
await
processPodsIfNeeded
(
_
project
.
ios
,
getIosBuildDirectory
(),
buildInfo
.
mode
);
if
(
hasPlugins
(
_
project
))
{
await
_producePlugins
(
buildInfo
.
mode
,
xcodeBuildConfiguration
,
iPhoneBuildOutput
,
simulatorBuildOutput
,
modeDirectory
,
outputDirectory
);
await
processPodsIfNeeded
(
project
.
ios
,
getIosBuildDirectory
(),
buildInfo
.
mode
);
if
(
hasPlugins
(
project
))
{
await
_producePlugins
(
buildInfo
.
mode
,
xcodeBuildConfiguration
,
iPhoneBuildOutput
,
simulatorBuildOutput
,
modeDirectory
);
}
final
Status
status
=
globals
.
logger
.
startProgress
(
...
...
@@ -225,12 +284,12 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
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
// to copy the GeneratedPluginRegistrant class to their project manually.
final
File
pluginRegistrantHeader
=
_
project
.
ios
.
pluginRegistrantHeader
;
final
File
pluginRegistrantHeader
=
project
.
ios
.
pluginRegistrantHeader
;
final
File
pluginRegistrantImplementation
=
_
project
.
ios
.
pluginRegistrantImplementation
;
project
.
ios
.
pluginRegistrantImplementation
;
pluginRegistrantHeader
.
copySync
(
outputDirectory
.
childFile
(
pluginRegistrantHeader
.
basename
).
path
);
pluginRegistrantImplementation
.
copySync
(
outputDirectory
...
...
@@ -250,10 +309,10 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
void
produceFlutterPodspec
(
BuildMode
mode
,
Directory
modeDirectory
,
{
bool
force
=
false
})
{
final
Status
status
=
globals
.
logger
.
startProgress
(
' ├─Creating Flutter.podspec...'
);
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
))
{
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.
...
...
@@ -262,7 +321,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
// new artifacts when the source URL changes.
final
int
minorHotfixVersion
=
(
gitTagVersion
.
z
??
0
)
*
100
+
(
gitTagVersion
.
hotfix
??
0
);
final
File
license
=
_
cache
.
getLicenseFile
();
final
File
license
=
cache
.
getLicenseFile
();
if
(!
license
.
existsSync
())
{
throwToolExit
(
'Could not find license at
${license.path}
'
);
}
...
...
@@ -272,7 +331,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
final
String
podspecContents
=
'''
Pod::Spec.new do |s|
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.description = <<-DESC
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
}
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
.
platform
=
:
ios
,
'11.0'
s
.
vendored_frameworks
=
'Flutter.xcframework'
...
...
@@ -356,7 +415,7 @@ end
final Environment environment = Environment(
projectDir: globals.fs.currentDirectory,
outputDir: outputBuildDirectory,
buildDir:
_
project.dartTool.childDirectory('
flutter_build
'),
buildDir: project.dartTool.childDirectory('
flutter_build
'),
cacheDir: globals.cache.getRoot(),
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
defines: <String, String>{
...
...
@@ -401,7 +460,12 @@ end
status.stop();
}
await _produceXCFramework(frameworks, '
App
', outputDirectory);
await BuildFrameworkCommand.produceXCFramework(
frameworks,
'
App
',
outputDirectory,
globals.processManager,
);
}
Future<void> _producePlugins(
...
...
@@ -410,7 +474,6 @@ end
Directory iPhoneBuildOutput,
Directory simulatorBuildOutput,
Directory modeDirectory,
Directory outputDirectory,
) async {
final Status status = globals.logger.startProgress(
'
├─
Building
plugins
...
'
...
...
@@ -437,7 +500,7 @@ end
RunResult buildPluginsResult = await globals.processUtils.run(
pluginsBuildCommand,
workingDirectory:
_
project.ios.hostAppRoot.childDirectory('
Pods
').path,
workingDirectory: project.ios.hostAppRoot.childDirectory('
Pods
').path,
);
if (buildPluginsResult.exitCode != 0) {
...
...
@@ -464,7 +527,7 @@ end
buildPluginsResult = await globals.processUtils.run(
pluginsBuildCommand,
workingDirectory:
_
project.ios.hostAppRoot
workingDirectory: project.ios.hostAppRoot
.childDirectory('
Pods
')
.path,
);
...
...
@@ -500,46 +563,16 @@ end
.childDirectory(podFrameworkName),
];
await _produceXCFramework(frameworks, binaryName, modeDirectory);
await BuildFrameworkCommand.produceXCFramework(
frameworks,
binaryName,
modeDirectory,
globals.processManager,
);
}
}
} finally {
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
}
');
}
}
}
packages/flutter_tools/test/commands.shard/hermetic/build_
ios
_framework_test.dart
→
packages/flutter_tools/test/commands.shard/hermetic/build_
darwin
_framework_test.dart
View file @
dffddf00
...
...
@@ -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
);
});
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment