From 7f37964707aa1af4b39ee8c6ffc06609583475fc Mon Sep 17 00:00:00 2001 From: belier Date: Mon, 1 Dec 2025 15:04:33 +0800 Subject: [PATCH 1/2] Add support for building no-codesign ipa --- .../lib/src/builders/ios/app_builder_ios.dart | 19 +++++++---- .../src/builders/ios/build_ios_result.dart | 7 ++-- .../src/makers/ipa/app_package_maker_ipa.dart | 33 +++++++++++++++++-- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/packages/flutter_app_builder/lib/src/builders/ios/app_builder_ios.dart b/packages/flutter_app_builder/lib/src/builders/ios/app_builder_ios.dart index 8069af37..110d9611 100644 --- a/packages/flutter_app_builder/lib/src/builders/ios/app_builder_ios.dart +++ b/packages/flutter_app_builder/lib/src/builders/ios/app_builder_ios.dart @@ -15,19 +15,26 @@ class AppBuilderIos extends AppBuilder { @override BuildResultResolver get resultResolver => BuildIosResultResolver(); + String _buildSubcommand = 'ipa'; + @override - String get buildSubcommand => 'ipa'; + String get buildSubcommand => _buildSubcommand; @override Future build({ required Map arguments, Map? environment, }) { - if (!arguments.containsKey('export-options-plist') && - !arguments.containsKey('export-method')) { - throw BuildError( - 'Missing `export-options-plist` or `export-method` build argument.', - ); + if (arguments.containsKey('no-codesign')) { + _buildSubcommand = 'ios'; + } else { + _buildSubcommand = 'ipa'; + if (!arguments.containsKey('export-options-plist') && + !arguments.containsKey('export-method')) { + throw BuildError( + 'Missing `export-options-plist` or `export-method` build argument.', + ); + } } return super.build( arguments: arguments, diff --git a/packages/flutter_app_builder/lib/src/builders/ios/build_ios_result.dart b/packages/flutter_app_builder/lib/src/builders/ios/build_ios_result.dart index fcbf55ac..f6278998 100644 --- a/packages/flutter_app_builder/lib/src/builders/ios/build_ios_result.dart +++ b/packages/flutter_app_builder/lib/src/builders/ios/build_ios_result.dart @@ -9,7 +9,8 @@ class BuildIosResultResolver extends BuildResultResolver { @override BuildResult resolve(BuildConfig config, {Duration? duration}) { final r = BuildIosResult(config); - final String pattern = '${r.outputDirectory.path}/**.ipa'; + final suffix = config.arguments.containsKey('no-codesign') ? 'app' : 'ipa'; + final String pattern = '${r.outputDirectory.path}/**.$suffix'; List entities = Glob(pattern).listSync(); List pkgFiles = (entities.map((e) => File(e.path)).toList()) ..sort((a, b) => b.lastModifiedSync().compareTo(a.lastModifiedSync())); @@ -23,7 +24,9 @@ class BuildIosResult extends BuildResult { @override Directory get outputDirectory { - String path = 'build/ios/ipa'; + String path = config.arguments.containsKey('no-codesign') + ? 'build/ios/iphoneos' + : 'build/ios/ipa'; return Directory(path); } } diff --git a/packages/flutter_app_packager/lib/src/makers/ipa/app_package_maker_ipa.dart b/packages/flutter_app_packager/lib/src/makers/ipa/app_package_maker_ipa.dart index f6ba1025..4f153d6a 100644 --- a/packages/flutter_app_packager/lib/src/makers/ipa/app_package_maker_ipa.dart +++ b/packages/flutter_app_packager/lib/src/makers/ipa/app_package_maker_ipa.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter_app_packager/src/api/app_package_maker.dart'; +import 'package:shell_executor/shell_executor.dart'; class AppPackageMakerIpa extends AppPackageMaker { @override @@ -11,9 +12,35 @@ class AppPackageMakerIpa extends AppPackageMaker { String get packageFormat => 'ipa'; @override - Future make(MakeConfig config) { - File pkgFile = config.buildOutputFiles.first; - pkgFile.copySync(config.outputFile.path); + Future make(MakeConfig config) async { + final pkgFile = config.buildOutputFiles.first; + final isApp = pkgFile.path.endsWith('.app'); + if (isApp) { + // pkgFilePath build/ios/iphoneos/Runner.app + final iphoneosDirectory = pkgFile.parent; + final iosDirectory = iphoneosDirectory.parent; + final payloadDirectory = Directory('${iosDirectory.path}/Payload'); + final ipaFile = File('${iphoneosDirectory.path}/Runner.ipa}'); + try { + await $('cp', ['-RH', iphoneosDirectory.path, payloadDirectory.path]); + await $( + 'zip', + [ + '-r9', + ipaFile.path.replaceFirst('${iosDirectory.path}/', ''), + 'Payload', + ], + workingDirectory: iosDirectory.path, + ); + } catch (error) { + rethrow; + } finally { + payloadDirectory.deleteSync(recursive: true); + } + ipaFile.copySync(config.outputFile.path); + } else { + pkgFile.copySync(config.outputFile.path); + } return Future.value(resultResolver.resolve(config)); } } From 6b72eb5d007808658a3c3a34f48734a23709e830 Mon Sep 17 00:00:00 2001 From: belier Date: Mon, 1 Dec 2025 15:24:18 +0800 Subject: [PATCH 2/2] fix ipaFile path --- .../lib/src/makers/ipa/app_package_maker_ipa.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_app_packager/lib/src/makers/ipa/app_package_maker_ipa.dart b/packages/flutter_app_packager/lib/src/makers/ipa/app_package_maker_ipa.dart index 4f153d6a..a7cb21eb 100644 --- a/packages/flutter_app_packager/lib/src/makers/ipa/app_package_maker_ipa.dart +++ b/packages/flutter_app_packager/lib/src/makers/ipa/app_package_maker_ipa.dart @@ -20,7 +20,7 @@ class AppPackageMakerIpa extends AppPackageMaker { final iphoneosDirectory = pkgFile.parent; final iosDirectory = iphoneosDirectory.parent; final payloadDirectory = Directory('${iosDirectory.path}/Payload'); - final ipaFile = File('${iphoneosDirectory.path}/Runner.ipa}'); + final ipaFile = File('${iphoneosDirectory.path}/Runner.ipa'); try { await $('cp', ['-RH', iphoneosDirectory.path, payloadDirectory.path]); await $(