diff --git a/packages/shorebird_cli/lib/src/commands/release/release_ios_command.dart b/packages/shorebird_cli/lib/src/commands/release/release_ios_command.dart
index 191769f3..50b5b5bb 100644
--- a/packages/shorebird_cli/lib/src/commands/release/release_ios_command.dart
+++ b/packages/shorebird_cli/lib/src/commands/release/release_ios_command.dart
@@ -20,36 +20,6 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
const exportMethodArgName = 'export-method';
const exportOptionsPlistArgName = 'export-options-plist';
-/// {@template export_method}
-/// The method used to export the IPA.
-/// {@endtemplate}
-enum ExportMethod {
- appStore('app-store', 'Upload to the App Store'),
- adHoc(
- 'ad-hoc',
- '''
-Test on designated devices that do not need to be registered with the Apple developer account.
- Requires a distribution certificate.''',
- ),
- development(
- 'development',
- '''Test only on development devices registered with the Apple developer account.''',
- ),
- enterprise(
- 'enterprise',
- 'Distribute an app registered with the Apple Developer Enterprise Program.',
- );
-
- /// {@macro export_method}
- const ExportMethod(this.argName, this.description);
-
- /// The command-line argument name for this export method.
- final String argName;
-
- /// A description of this method and how/when it should be used.
- final String description;
-}
-
/// {@template release_ios_command}
/// `shorebird release ios`
/// Create new app releases for iOS.
@@ -140,16 +110,22 @@ make smaller updates to your app.
);
return ExitCode.usage.code;
}
- final exportOptionsPlist = exportPlistArg != null
- ? File(exportPlistArg)
- : _createExportOptionsPlist(
- exportMethod: results[exportMethodArgName] as String,
- );
- try {
- _validateExportOptionsPlist(exportOptionsPlist);
- } catch (error) {
- logger.err('$error');
- return ExitCode.usage.code;
+
+ final File? exportOptionsPlist;
+ if (exportPlistArg != null) {
+ exportOptionsPlist = File(exportPlistArg);
+ try {
+ _validateExportOptionsPlist(exportOptionsPlist);
+ } catch (error) {
+ logger.err('$error');
+ return ExitCode.usage.code;
+ }
+ } else if (results.wasParsed(exportMethodArgName)) {
+ final exportMethod =
+ ExportMethod.values.byName(results[exportMethodArgName] as String);
+ exportOptionsPlist = createExportOptionsPlist(exportMethod: exportMethod);
+ } else {
+ exportOptionsPlist = null;
}
const releasePlatform = ReleasePlatform.ios;
@@ -339,36 +315,4 @@ ${styleBold.wrap('Make sure to uncheck "Manage Version and Build Number", or els
);
}
}
-
- /// Creates an ExportOptions.plist file, which is used to tell xcodebuild to
- /// not manage the app version and build number. If we don't do this, then
- /// xcodebuild will increment the build number if it detects an App Store
- /// Connect build with the same version and build number. This is a problem
- /// for us when patching, as patches need to have the same version and build
- /// number as the release they are patching.
- /// See
- /// https://developer.apple.com/forums/thread/690647?answerId=689925022#689925022
- File _createExportOptionsPlist({required String exportMethod}) {
- final plistContents = '''
-
-
-
-
- manageAppVersionAndBuildNumber
-
- signingStyle
- automatic
- uploadBitcode
-
- method
- $exportMethod
-
-
-''';
- final tempDir = Directory.systemTemp.createTempSync();
- final exportPlistFile = File(p.join(tempDir.path, 'ExportOptions.plist'))
- ..createSync(recursive: true)
- ..writeAsStringSync(plistContents);
- return exportPlistFile;
- }
}
diff --git a/packages/shorebird_cli/lib/src/shorebird_build_mixin.dart b/packages/shorebird_cli/lib/src/shorebird_build_mixin.dart
index 35e2c761..c747b729 100644
--- a/packages/shorebird_cli/lib/src/shorebird_build_mixin.dart
+++ b/packages/shorebird_cli/lib/src/shorebird_build_mixin.dart
@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:collection/collection.dart';
import 'package:mason_logger/mason_logger.dart';
+import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/engine_config.dart';
import 'package:shorebird_cli/src/logger.dart';
@@ -42,6 +43,36 @@ class BuildException implements Exception {
final String message;
}
+/// {@template export_method}
+/// The method used to export the IPA.
+/// {@endtemplate}
+enum ExportMethod {
+ appStore('app-store', 'Upload to the App Store'),
+ adHoc(
+ 'ad-hoc',
+ '''
+Test on designated devices that do not need to be registered with the Apple developer account.
+ Requires a distribution certificate.''',
+ ),
+ development(
+ 'development',
+ '''Test only on development devices registered with the Apple developer account.''',
+ ),
+ enterprise(
+ 'enterprise',
+ 'Distribute an app registered with the Apple Developer Enterprise Program.',
+ );
+
+ /// {@macro export_method}
+ const ExportMethod(this.argName, this.description);
+
+ /// The command-line argument name for this export method.
+ final String argName;
+
+ /// A description of this method and how/when it should be used.
+ final String description;
+}
+
mixin ShorebirdBuildMixin on ShorebirdCommand {
// This exists only so tests can get the full list.
static const allAndroidArchitectures = {
@@ -199,8 +230,8 @@ mixin ShorebirdBuildMixin on ShorebirdCommand {
if (flavor != null) '--flavor=$flavor',
if (target != null) '--target=$target',
if (!codesign) '--no-codesign',
- if (codesign && exportOptionsPlist != null)
- '--export-options-plist=${exportOptionsPlist.path}',
+ if (codesign)
+ '''--export-options-plist=${(exportOptionsPlist ?? createExportOptionsPlist()).path}''',
...results.rest,
];
@@ -231,6 +262,40 @@ mixin ShorebirdBuildMixin on ShorebirdCommand {
});
}
+ /// Creates an ExportOptions.plist file, which is used to tell xcodebuild to
+ /// not manage the app version and build number. If we don't do this, then
+ /// xcodebuild will increment the build number if it detects an App Store
+ /// Connect build with the same version and build number. This is a problem
+ /// for us when patching, as patches need to have the same version and build
+ /// number as the release they are patching.
+ /// See
+ /// https://developer.apple.com/forums/thread/690647?answerId=689925022#689925022
+ File createExportOptionsPlist({
+ ExportMethod exportMethod = ExportMethod.appStore,
+ }) {
+ final plistContents = '''
+
+
+
+
+ manageAppVersionAndBuildNumber
+
+ signingStyle
+ automatic
+ uploadBitcode
+
+ method
+ ${exportMethod.argName}
+
+
+''';
+ final tempDir = Directory.systemTemp.createTempSync();
+ final exportPlistFile = File(p.join(tempDir.path, 'ExportOptions.plist'))
+ ..createSync(recursive: true)
+ ..writeAsStringSync(plistContents);
+ return exportPlistFile;
+ }
+
/// Builds a release iOS framework (.xcframework) for the current project.
Future buildIosFramework() async {
return _runShorebirdBuildCommand(() async {
diff --git a/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart b/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart
index bb5408fc..9e78d82a 100644
--- a/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart
+++ b/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart
@@ -1225,6 +1225,22 @@ Please re-run the release command for this version or create a new release.'''),
patchArtifactBundles: any(named: 'patchArtifactBundles'),
),
).called(1);
+
+ // Verify that an export options plist was provided to the build ipa
+ // command.
+ const exportOptionsPlistArgName = 'export-options-plist';
+ final capturedArgs = verify(
+ () => shorebirdProcess.run(
+ 'flutter',
+ captureAny(),
+ runInShell: any(named: 'runInShell'),
+ ),
+ ).captured.first as List;
+ final exportOptionsPlistArg = capturedArgs
+ .whereType()
+ .firstWhereOrNull((arg) => arg.contains(exportOptionsPlistArgName));
+ expect(exportOptionsPlistArg, isNotNull);
+
expect(exitCode, ExitCode.success.code);
});
diff --git a/packages/shorebird_cli/test/src/commands/release/release_ios_command_test.dart b/packages/shorebird_cli/test/src/commands/release/release_ios_command_test.dart
index c3521251..59b521be 100644
--- a/packages/shorebird_cli/test/src/commands/release/release_ios_command_test.dart
+++ b/packages/shorebird_cli/test/src/commands/release/release_ios_command_test.dart
@@ -17,6 +17,7 @@ import 'package:shorebird_cli/src/doctor.dart';
import 'package:shorebird_cli/src/logger.dart';
import 'package:shorebird_cli/src/os/operating_system_interface.dart';
import 'package:shorebird_cli/src/platform.dart';
+import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
import 'package:shorebird_cli/src/shorebird_env.dart';
import 'package:shorebird_cli/src/shorebird_flutter.dart';
import 'package:shorebird_cli/src/shorebird_process.dart';