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
ac52901c
Unverified
Commit
ac52901c
authored
Feb 03, 2022
by
Jenn Magder
Committed by
GitHub
Feb 03, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Export an IPA for distribution via "flutter build ipa" without --export-options-plist (#97672)
parent
6db09bb3
Changes
2
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
436 additions
and
99 deletions
+436
-99
build_ios.dart
packages/flutter_tools/lib/src/commands/build_ios.dart
+111
-14
build_ipa_test.dart
...er_tools/test/commands.shard/hermetic/build_ipa_test.dart
+325
-85
No files found.
packages/flutter_tools/lib/src/commands/build_ios.dart
View file @
ac52901c
...
...
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import
'package:file/file.dart'
;
import
'package:meta/meta.dart'
;
import
'../base/analyze_size.dart'
;
import
'../base/common.dart'
;
...
...
@@ -66,12 +67,24 @@ class BuildIOSCommand extends _BuildIOSSubCommand {
class
BuildIOSArchiveCommand
extends
_BuildIOSSubCommand
{
BuildIOSArchiveCommand
({
required
bool
verboseHelp
})
:
super
(
verboseHelp:
verboseHelp
)
{
argParser
.
addOption
(
'export-method'
,
defaultsTo:
'app-store'
,
allowed:
<
String
>[
'app-store'
,
'ad-hoc'
,
'development'
,
'enterprise'
],
help:
'Specify how the IPA will be distributed.'
,
allowedHelp:
<
String
,
String
>{
'app-store'
:
'Upload to the App Store.'
,
'ad-hoc'
:
'Test on designated devices that do not need to be registered with the Apple developer account. '
'Requires a distribution certificate.'
,
'development'
:
'Test only on development devices registered with the Apple developer account.'
,
'enterprise'
:
'Distribute an app registered with the Apple Developer Enterprise Program.'
,
},
);
argParser
.
addOption
(
'export-options-plist'
,
valueHelp:
'ExportOptions.plist'
,
// TODO(jmagman): Update help text with link to Flutter docs.
help:
'
Optionally e
xport an IPA with these options. See "xcodebuild -h" for available exportOptionsPlist keys.'
,
'
E
xport an IPA with these options. See "xcodebuild -h" for available exportOptionsPlist keys.'
,
);
}
...
...
@@ -82,7 +95,7 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
final
List
<
String
>
aliases
=
<
String
>[
'xcarchive'
];
@override
final
String
description
=
'Build an iOS archive bundle (Mac OS X host only).'
;
final
String
description
=
'Build an iOS archive bundle
and IPA for distribution
(Mac OS X host only).'
;
@override
final
XcodeBuildAction
xcodeBuildAction
=
XcodeBuildAction
.
archive
;
...
...
@@ -105,9 +118,16 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
.
childDirectory
(
'Applications'
);
@override
Future
<
FlutterCommandResult
>
run
Command
()
async
{
Future
<
void
>
validate
Command
()
async
{
final
String
?
exportOptions
=
exportOptionsPlist
;
if
(
exportOptions
!=
null
)
{
if
(
argResults
?.
wasParsed
(
'export-method'
)
==
true
)
{
throwToolExit
(
'"--export-options-plist" is not compatible with "--export-method". Either use "--export-options-plist" and '
'a plist describing how the IPA should be exported by Xcode, or use "--export-method" to create a new plist.
\n
'
'See "xcodebuild -h" for available exportOptionsPlist keys.'
);
}
final
FileSystemEntityType
type
=
globals
.
fs
.
typeSync
(
exportOptions
);
if
(
type
==
FileSystemEntityType
.
notFound
)
{
throwToolExit
(
...
...
@@ -117,14 +137,15 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
'"
$exportOptions
" is not a file. See "xcodebuild -h" for available keys.'
);
}
}
return
super
.
validateCommand
();
}
@override
Future
<
FlutterCommandResult
>
runCommand
()
async
{
final
FlutterCommandResult
xcarchiveResult
=
await
super
.
runCommand
();
final
BuildInfo
buildInfo
=
await
getBuildInfo
();
displayNullSafetyMode
(
buildInfo
);
if
(
exportOptions
==
null
)
{
return
xcarchiveResult
;
}
// xcarchive failed or not at expected location.
if
(
xcarchiveResult
.
exitStatus
!=
ExitStatus
.
success
)
{
globals
.
printStatus
(
'Skipping IPA'
);
...
...
@@ -135,9 +156,20 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
final
BuildableIOSApp
app
=
await
buildableIOSApp
;
Status
?
status
;
RunResult
?
result
;
final
String
outputPath
=
globals
.
fs
.
path
.
absolute
(
app
.
ipaOutputPath
);
final
String
relativeOutputPath
=
app
.
ipaOutputPath
;
final
String
absoluteOutputPath
=
globals
.
fs
.
path
.
absolute
(
relativeOutputPath
);
final
String
absoluteArchivePath
=
globals
.
fs
.
path
.
absolute
(
app
.
archiveBundleOutputPath
);
final
String
exportMethod
=
stringArg
(
'export-method'
)!;
final
bool
isAppStoreUpload
=
exportMethod
==
'app-store'
;
File
?
generatedExportPlist
;
try
{
status
=
globals
.
logger
.
startProgress
(
'Building IPA...'
);
final
String
exportMethodDisplayName
=
isAppStoreUpload
?
'App Store'
:
exportMethod
;
status
=
globals
.
logger
.
startProgress
(
'Building
$exportMethodDisplayName
IPA...'
);
String
?
exportOptions
=
exportOptionsPlist
;
if
(
exportOptions
==
null
)
{
generatedExportPlist
=
_createExportPlist
();
exportOptions
=
generatedExportPlist
.
path
;
}
result
=
await
globals
.
processUtils
.
run
(
<
String
>[
...
...
@@ -149,14 +181,15 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
'-allowProvisioningUpdates'
,
],
'-archivePath'
,
globals
.
fs
.
path
.
absolute
(
app
.
archiveBundleOutputPath
)
,
absoluteArchivePath
,
'-exportPath'
,
o
utputPath
,
absoluteO
utputPath
,
'-exportOptionsPlist'
,
globals
.
fs
.
path
.
absolute
(
exportOptions
),
],
);
}
finally
{
generatedExportPlist
?.
deleteSync
();
status
?.
stop
();
}
...
...
@@ -171,13 +204,72 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
LineSplitter
.
split
(
result
.
stderr
)
.
where
((
String
line
)
=>
line
.
contains
(
'error: '
))
.
forEach
(
errorMessage
.
writeln
);
throwToolExit
(
'Encountered error while building IPA:
\n
$errorMessage
'
);
globals
.
printError
(
'Encountered error while creating the IPA:'
);
globals
.
printError
(
errorMessage
.
toString
());
globals
.
printError
(
'Try distributing the app in Xcode: "open
$absoluteArchivePath
"'
);
// Even though the IPA step didn't succeed, the xcarchive did.
// Still count this as success since the user has been instructed about how to
// recover in Xcode.
return
FlutterCommandResult
.
success
();
}
globals
.
printStatus
(
'Built IPA to
$outputPath
.'
);
globals
.
printStatus
(
'Built IPA to
$absoluteOutputPath
.'
);
if
(
isAppStoreUpload
)
{
globals
.
printStatus
(
'To upload to the App Store either:'
);
globals
.
printStatus
(
'1. Drag and drop the "
$relativeOutputPath
/*.ipa" bundle into the Apple Transport macOS app https://apps.apple.com/us/app/transporter/id1450874784'
,
indent:
4
,
);
globals
.
printStatus
(
'2. Run "xcrun altool --upload-app --type ios -f
$relativeOutputPath
/*.ipa --apiKey your_api_key --apiIssuer your_issuer_id".'
,
indent:
4
,
);
globals
.
printStatus
(
'See "man altool" for details about how to authenticate with the App Store Connect API key.'
,
indent:
7
,
);
}
return
FlutterCommandResult
.
success
();
}
File
_createExportPlist
()
{
// Create the plist to be passed into xcodebuild -exportOptionsPlist.
final
StringBuffer
plistContents
=
StringBuffer
(
'''
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
'''
);
plistContents
.
write
(
'''
<string>
${stringArg('export-method')}
</string>
'''
);
if
(
xcodeBuildResult
?.
xcodeBuildExecution
?.
buildSettings
[
'ENABLE_BITCODE'
]
!=
'YES'
)
{
// Bitcode is off by default in Flutter iOS apps.
plistContents
.
write
(
'''
<key>uploadBitcode</key>
<false/>
</dict>
</plist>
'''
);
}
else
{
plistContents
.
write
(
'''
</dict>
</plist>
'''
);
}
final
File
tempPlist
=
globals
.
fs
.
systemTempDirectory
.
createTempSync
(
'flutter_build_ios.'
).
childFile
(
'ExportOptions.plist'
);
tempPlist
.
writeAsStringSync
(
plistContents
.
toString
());
return
tempPlist
;
}
}
abstract
class
_BuildIOSSubCommand
extends
BuildSubCommand
{
...
...
@@ -208,6 +300,10 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand {
};
XcodeBuildAction
get
xcodeBuildAction
;
/// The result of the Xcode build command. Null until it finishes.
@protected
XcodeBuildResult
?
xcodeBuildResult
;
EnvironmentType
get
environmentType
;
bool
get
configOnly
;
bool
get
shouldCodesign
;
...
...
@@ -271,6 +367,7 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand {
buildAction:
xcodeBuildAction
,
deviceID:
globals
.
deviceManager
?.
specifiedDeviceId
,
);
xcodeBuildResult
=
result
;
if
(!
result
.
success
)
{
await
diagnoseXcodeBuildFailure
(
result
,
globals
.
flutterUsage
,
globals
.
logger
);
...
...
packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart
View file @
ac52901c
This diff is collapsed.
Click to expand it.
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