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
6ceb418b
Unverified
Commit
6ceb418b
authored
Feb 02, 2022
by
Jenn Magder
Committed by
GitHub
Feb 02, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Export an IPA for distribution via "flutter build ipa" without --export-options-plist (#97243)
parent
a599c23b
Changes
2
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
347 additions
and
99 deletions
+347
-99
build_ios.dart
packages/flutter_tools/lib/src/commands/build_ios.dart
+106
-14
build_ipa_test.dart
...er_tools/test/commands.shard/hermetic/build_ipa_test.dart
+241
-85
No files found.
packages/flutter_tools/lib/src/commands/build_ios.dart
View file @
6ceb418b
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
// found in the LICENSE file.
// found in the LICENSE file.
import
'package:file/file.dart'
;
import
'package:file/file.dart'
;
import
'package:meta/meta.dart'
;
import
'../base/analyze_size.dart'
;
import
'../base/analyze_size.dart'
;
import
'../base/common.dart'
;
import
'../base/common.dart'
;
...
@@ -66,12 +67,23 @@ class BuildIOSCommand extends _BuildIOSSubCommand {
...
@@ -66,12 +67,23 @@ class BuildIOSCommand extends _BuildIOSSubCommand {
class
BuildIOSArchiveCommand
extends
_BuildIOSSubCommand
{
class
BuildIOSArchiveCommand
extends
_BuildIOSSubCommand
{
BuildIOSArchiveCommand
({
required
bool
verboseHelp
})
BuildIOSArchiveCommand
({
required
bool
verboseHelp
})
:
super
(
verboseHelp:
verboseHelp
)
{
:
super
(
verboseHelp:
verboseHelp
)
{
argParser
.
addOption
(
'export-method'
,
defaultsTo:
'app-store'
,
allowed:
<
String
>[
'app-store'
,
'ad-hoc'
,
'development'
],
help:
'Specify how the IPA will be distributed.'
,
allowedHelp:
<
String
,
String
>{
'app-store'
:
'Upload to the App Store.'
,
'ad-hoc'
:
'Distribute to designated devices that do not need to be registered with the Apple developer account. '
'Requires a distribution certificate.'
,
'development'
:
'Distribute only to development devices registered with the Apple developer account.'
,
},
);
argParser
.
addOption
(
argParser
.
addOption
(
'export-options-plist'
,
'export-options-plist'
,
valueHelp:
'ExportOptions.plist'
,
valueHelp:
'ExportOptions.plist'
,
// TODO(jmagman): Update help text with link to Flutter docs.
help:
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 +94,7 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
...
@@ -82,7 +94,7 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
final
List
<
String
>
aliases
=
<
String
>[
'xcarchive'
];
final
List
<
String
>
aliases
=
<
String
>[
'xcarchive'
];
@override
@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
@override
final
XcodeBuildAction
xcodeBuildAction
=
XcodeBuildAction
.
archive
;
final
XcodeBuildAction
xcodeBuildAction
=
XcodeBuildAction
.
archive
;
...
@@ -105,9 +117,16 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
...
@@ -105,9 +117,16 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
.
childDirectory
(
'Applications'
);
.
childDirectory
(
'Applications'
);
@override
@override
Future
<
FlutterCommandResult
>
run
Command
()
async
{
Future
<
void
>
validate
Command
()
async
{
final
String
?
exportOptions
=
exportOptionsPlist
;
final
String
?
exportOptions
=
exportOptionsPlist
;
if
(
exportOptions
!=
null
)
{
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
);
final
FileSystemEntityType
type
=
globals
.
fs
.
typeSync
(
exportOptions
);
if
(
type
==
FileSystemEntityType
.
notFound
)
{
if
(
type
==
FileSystemEntityType
.
notFound
)
{
throwToolExit
(
throwToolExit
(
...
@@ -117,14 +136,15 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
...
@@ -117,14 +136,15 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
'"
$exportOptions
" is not a file. See "xcodebuild -h" for available keys.'
);
'"
$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
FlutterCommandResult
xcarchiveResult
=
await
super
.
runCommand
();
final
BuildInfo
buildInfo
=
await
getBuildInfo
();
final
BuildInfo
buildInfo
=
await
getBuildInfo
();
displayNullSafetyMode
(
buildInfo
);
displayNullSafetyMode
(
buildInfo
);
if
(
exportOptions
==
null
)
{
return
xcarchiveResult
;
}
// xcarchive failed or not at expected location.
// xcarchive failed or not at expected location.
if
(
xcarchiveResult
.
exitStatus
!=
ExitStatus
.
success
)
{
if
(
xcarchiveResult
.
exitStatus
!=
ExitStatus
.
success
)
{
globals
.
printStatus
(
'Skipping IPA'
);
globals
.
printStatus
(
'Skipping IPA'
);
...
@@ -135,9 +155,20 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
...
@@ -135,9 +155,20 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
final
BuildableIOSApp
app
=
await
buildableIOSApp
;
final
BuildableIOSApp
app
=
await
buildableIOSApp
;
Status
?
status
;
Status
?
status
;
RunResult
?
result
;
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
{
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
(
result
=
await
globals
.
processUtils
.
run
(
<
String
>[
<
String
>[
...
@@ -149,14 +180,15 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
...
@@ -149,14 +180,15 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
'-allowProvisioningUpdates'
,
'-allowProvisioningUpdates'
,
],
],
'-archivePath'
,
'-archivePath'
,
globals
.
fs
.
path
.
absolute
(
app
.
archiveBundleOutputPath
)
,
absoluteArchivePath
,
'-exportPath'
,
'-exportPath'
,
o
utputPath
,
absoluteO
utputPath
,
'-exportOptionsPlist'
,
'-exportOptionsPlist'
,
globals
.
fs
.
path
.
absolute
(
exportOptions
),
globals
.
fs
.
path
.
absolute
(
exportOptions
),
],
],
);
);
}
finally
{
}
finally
{
generatedExportPlist
?.
deleteSync
();
status
?.
stop
();
status
?.
stop
();
}
}
...
@@ -171,13 +203,68 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
...
@@ -171,13 +203,68 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
LineSplitter
.
split
(
result
.
stderr
)
LineSplitter
.
split
(
result
.
stderr
)
.
where
((
String
line
)
=>
line
.
contains
(
'error: '
))
.
where
((
String
line
)
=>
line
.
contains
(
'error: '
))
.
forEach
(
errorMessage
.
writeln
);
.
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
"'
);
throwToolExit
(
null
);
}
}
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
();
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
{
abstract
class
_BuildIOSSubCommand
extends
BuildSubCommand
{
...
@@ -208,6 +295,10 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand {
...
@@ -208,6 +295,10 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand {
};
};
XcodeBuildAction
get
xcodeBuildAction
;
XcodeBuildAction
get
xcodeBuildAction
;
/// The result of the Xcode build command. Null until it finishes.
@protected
XcodeBuildResult
?
xcodeBuildResult
;
EnvironmentType
get
environmentType
;
EnvironmentType
get
environmentType
;
bool
get
configOnly
;
bool
get
configOnly
;
bool
get
shouldCodesign
;
bool
get
shouldCodesign
;
...
@@ -271,6 +362,7 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand {
...
@@ -271,6 +362,7 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand {
buildAction:
xcodeBuildAction
,
buildAction:
xcodeBuildAction
,
deviceID:
globals
.
deviceManager
?.
specifiedDeviceId
,
deviceID:
globals
.
deviceManager
?.
specifiedDeviceId
,
);
);
xcodeBuildResult
=
result
;
if
(!
result
.
success
)
{
if
(!
result
.
success
)
{
await
diagnoseXcodeBuildFailure
(
result
,
globals
.
flutterUsage
,
globals
.
logger
);
await
diagnoseXcodeBuildFailure
(
result
,
globals
.
flutterUsage
,
globals
.
logger
);
...
...
packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart
View file @
6ceb418b
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