Unverified Commit 802d872d authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Revert "Export an IPA for distribution via "flutter build ipa" without...

Revert "Export an IPA for distribution via "flutter build ipa" without --export-options-plist" (#97616)
parent dff9126d
...@@ -19,8 +19,6 @@ Future<void> main() async { ...@@ -19,8 +19,6 @@ Future<void> main() async {
await inDirectory(flutterProject.rootPath, () async { await inDirectory(flutterProject.rootPath, () async {
await flutter('build', options: <String>[ await flutter('build', options: <String>[
'xcarchive', 'xcarchive',
'--export-method',
'development',
]); ]);
}); });
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// 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';
...@@ -67,23 +66,12 @@ class BuildIOSCommand extends _BuildIOSSubCommand { ...@@ -67,23 +66,12 @@ 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:
'Export an IPA with these options. See "xcodebuild -h" for available exportOptionsPlist keys.', 'Optionally export an IPA with these options. See "xcodebuild -h" for available exportOptionsPlist keys.',
); );
} }
...@@ -94,7 +82,7 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { ...@@ -94,7 +82,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 and IPA for distribution (Mac OS X host only).'; final String description = 'Build an iOS archive bundle (Mac OS X host only).';
@override @override
final XcodeBuildAction xcodeBuildAction = XcodeBuildAction.archive; final XcodeBuildAction xcodeBuildAction = XcodeBuildAction.archive;
...@@ -117,16 +105,9 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { ...@@ -117,16 +105,9 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
.childDirectory('Applications'); .childDirectory('Applications');
@override @override
Future<void> validateCommand() async { Future<FlutterCommandResult> runCommand() 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(
...@@ -136,15 +117,14 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { ...@@ -136,15 +117,14 @@ 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');
...@@ -155,20 +135,9 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { ...@@ -155,20 +135,9 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
final BuildableIOSApp app = await buildableIOSApp; final BuildableIOSApp app = await buildableIOSApp;
Status? status; Status? status;
RunResult? result; RunResult? result;
final String relativeOutputPath = app.ipaOutputPath; final String outputPath = globals.fs.path.absolute(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 {
final String exportMethodDisplayName = isAppStoreUpload ? 'App Store' : exportMethod; status = globals.logger.startProgress('Building IPA...');
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>[
...@@ -180,15 +149,14 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { ...@@ -180,15 +149,14 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
'-allowProvisioningUpdates', '-allowProvisioningUpdates',
], ],
'-archivePath', '-archivePath',
absoluteArchivePath, globals.fs.path.absolute(app.archiveBundleOutputPath),
'-exportPath', '-exportPath',
absoluteOutputPath, outputPath,
'-exportOptionsPlist', '-exportOptionsPlist',
globals.fs.path.absolute(exportOptions), globals.fs.path.absolute(exportOptions),
], ],
); );
} finally { } finally {
generatedExportPlist?.deleteSync();
status?.stop(); status?.stop();
} }
...@@ -203,68 +171,13 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { ...@@ -203,68 +171,13 @@ 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 $absoluteOutputPath.'); globals.printStatus('Built IPA to $outputPath.');
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 {
...@@ -295,10 +208,6 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand { ...@@ -295,10 +208,6 @@ 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;
...@@ -362,7 +271,6 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand { ...@@ -362,7 +271,6 @@ 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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment