Unverified Commit 7b1aec70 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Move iOS codesigning into assemble build target (#77664)

parent 3569536e
...@@ -165,6 +165,11 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr ...@@ -165,6 +165,11 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr
code_size_directory="-dCodeSizeDirectory=${CODE_SIZE_DIRECTORY}" code_size_directory="-dCodeSizeDirectory=${CODE_SIZE_DIRECTORY}"
fi fi
local codesign_identity_flag=""
if [[ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" && "${CODE_SIGNING_REQUIRED:-}" != "NO" ]]; then
codesign_identity_flag="-dCodesignIdentity=${EXPANDED_CODE_SIGN_IDENTITY}"
fi
RunCommand "${FLUTTER_ROOT}/bin/flutter" \ RunCommand "${FLUTTER_ROOT}/bin/flutter" \
${verbose_flag} \ ${verbose_flag} \
${flutter_engine_flag} \ ${flutter_engine_flag} \
...@@ -183,6 +188,7 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr ...@@ -183,6 +188,7 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr
-dTrackWidgetCreation="${TRACK_WIDGET_CREATION}" \ -dTrackWidgetCreation="${TRACK_WIDGET_CREATION}" \
-dDartObfuscation="${DART_OBFUSCATION}" \ -dDartObfuscation="${DART_OBFUSCATION}" \
-dEnableBitcode="${bitcode_flag}" \ -dEnableBitcode="${bitcode_flag}" \
"${codesign_identity_flag}" \
${bundle_sksl_path} \ ${bundle_sksl_path} \
${code_size_directory} \ ${code_size_directory} \
--ExtraGenSnapshotOptions="${EXTRA_GEN_SNAPSHOT_OPTIONS}" \ --ExtraGenSnapshotOptions="${EXTRA_GEN_SNAPSHOT_OPTIONS}" \
...@@ -214,15 +220,7 @@ EmbedFlutterFrameworks() { ...@@ -214,15 +220,7 @@ EmbedFlutterFrameworks() {
# Embed the actual Flutter.framework that the Flutter app expects to run against, # Embed the actual Flutter.framework that the Flutter app expects to run against,
# which could be a local build or an arch/type specific build. # which could be a local build or an arch/type specific build.
RunCommand rsync -av --delete --filter "- .DS_Store" "${BUILT_PRODUCTS_DIR}/Flutter.framework" "${xcode_frameworks_dir}/"
# Copy Xcode behavior and don't copy over headers or modules.
RunCommand rsync -av --delete --filter "- .DS_Store" --filter "- Headers" --filter "- Modules" "${BUILT_PRODUCTS_DIR}/Flutter.framework" "${xcode_frameworks_dir}/"
# Sign the binaries we moved.
if [[ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" ]]; then
RunCommand codesign --force --verbose --sign "${EXPANDED_CODE_SIGN_IDENTITY}" -- "${xcode_frameworks_dir}/App.framework/App"
RunCommand codesign --force --verbose --sign "${EXPANDED_CODE_SIGN_IDENTITY}" -- "${xcode_frameworks_dir}/Flutter.framework/Flutter"
fi
AddObservatoryBonjourService AddObservatoryBonjourService
} }
......
...@@ -80,6 +80,12 @@ const String kDartObfuscation = 'DartObfuscation'; ...@@ -80,6 +80,12 @@ const String kDartObfuscation = 'DartObfuscation';
/// An output directory where one or more code-size measurements may be written. /// An output directory where one or more code-size measurements may be written.
const String kCodeSizeDirectory = 'CodeSizeDirectory'; const String kCodeSizeDirectory = 'CodeSizeDirectory';
/// SHA identifier of the Apple developer code signing identity.
///
/// Same as EXPANDED_CODE_SIGN_IDENTITY Xcode build setting.
/// Also discoverable via `security find-identity -p codesigning`.
const String kCodesignIdentity = 'CodesignIdentity';
/// Copies the pre-built flutter bundle. /// Copies the pre-built flutter bundle.
// This is a one-off rule for implementing build bundle in terms of assemble. // This is a one-off rule for implementing build bundle in terms of assemble.
class CopyFlutterBundle extends Target { class CopyFlutterBundle extends Target {
......
...@@ -11,7 +11,6 @@ import '../../base/build.dart'; ...@@ -11,7 +11,6 @@ import '../../base/build.dart';
import '../../base/common.dart'; import '../../base/common.dart';
import '../../base/file_system.dart'; import '../../base/file_system.dart';
import '../../base/io.dart'; import '../../base/io.dart';
import '../../base/process.dart';
import '../../build_info.dart'; import '../../build_info.dart';
import '../../globals.dart' as globals hide fs, logger, processManager, artifacts; import '../../globals.dart' as globals hide fs, logger, processManager, artifacts;
import '../../macos/xcode.dart'; import '../../macos/xcode.dart';
...@@ -231,14 +230,11 @@ class DebugUniversalFramework extends Target { ...@@ -231,14 +230,11 @@ class DebugUniversalFramework extends Target {
.childDirectory('App.framework') .childDirectory('App.framework')
.childFile('App'); .childFile('App');
environment.buildDir.createSync(recursive: true); environment.buildDir.createSync(recursive: true);
final RunResult createFrameworkResult = await createStubAppFramework( await _createStubAppFramework(
output, output,
environment.defines[kSdkRoot], environment,
iosArchNames, iosArchNames,
); );
if (createFrameworkResult.exitCode != 0) {
throw Exception('Failed to create App.framework.');
}
} }
} }
...@@ -283,18 +279,19 @@ abstract class UnpackIOS extends Target { ...@@ -283,18 +279,19 @@ abstract class UnpackIOS extends Target {
if (environment.defines[kBitcodeFlag] == null) { if (environment.defines[kBitcodeFlag] == null) {
throw MissingDefineException(kBitcodeFlag, name); throw MissingDefineException(kBitcodeFlag, name);
} }
await _copyFramework(environment); _copyFramework(environment);
final File frameworkBinary = environment.outputDir.childDirectory('Flutter.framework').childFile('Flutter'); final File frameworkBinary = environment.outputDir.childDirectory('Flutter.framework').childFile('Flutter');
final String frameworkBinaryPath = frameworkBinary.path; final String frameworkBinaryPath = frameworkBinary.path;
if (!frameworkBinary.existsSync()) { if (!frameworkBinary.existsSync()) {
throw Exception('Binary $frameworkBinaryPath does not exist, cannot thin'); throw Exception('Binary $frameworkBinaryPath does not exist, cannot thin');
} }
await _thinFramework(environment, frameworkBinaryPath); _thinFramework(environment, frameworkBinaryPath);
await _bitcodeStripFramework(environment, frameworkBinaryPath); _bitcodeStripFramework(environment, frameworkBinaryPath);
_signFramework(environment, frameworkBinaryPath, buildMode);
} }
Future<void> _copyFramework(Environment environment) async { void _copyFramework(Environment environment) {
final Directory sdkRoot = environment.fileSystem.directory(environment.defines[kSdkRoot]); final Directory sdkRoot = environment.fileSystem.directory(environment.defines[kSdkRoot]);
final EnvironmentType environmentType = environmentTypeFromSdkroot(sdkRoot); final EnvironmentType environmentType = environmentTypeFromSdkroot(sdkRoot);
final String basePath = environment.artifacts.getArtifactPath( final String basePath = environment.artifacts.getArtifactPath(
...@@ -322,7 +319,7 @@ abstract class UnpackIOS extends Target { ...@@ -322,7 +319,7 @@ abstract class UnpackIOS extends Target {
} }
/// Destructively thin Flutter.framework to include only the specified architectures. /// Destructively thin Flutter.framework to include only the specified architectures.
Future<void> _thinFramework(Environment environment, String frameworkBinaryPath) async { void _thinFramework(Environment environment, String frameworkBinaryPath) {
final String archs = environment.defines[kIosArchs]; final String archs = environment.defines[kIosArchs];
final List<String> archList = archs.split(' ').toList(); final List<String> archList = archs.split(' ').toList();
final ProcessResult infoResult = environment.processManager.runSync(<String>[ final ProcessResult infoResult = environment.processManager.runSync(<String>[
...@@ -368,7 +365,7 @@ abstract class UnpackIOS extends Target { ...@@ -368,7 +365,7 @@ abstract class UnpackIOS extends Target {
} }
/// Destructively strip bitcode from the framework, if needed. /// Destructively strip bitcode from the framework, if needed.
Future<void> _bitcodeStripFramework(Environment environment, String frameworkBinaryPath) async { void _bitcodeStripFramework(Environment environment, String frameworkBinaryPath) {
if (environment.defines[kBitcodeFlag] == 'true') { if (environment.defines[kBitcodeFlag] == 'true') {
return; return;
} }
...@@ -460,6 +457,7 @@ abstract class IosAssetBundle extends Target { ...@@ -460,6 +457,7 @@ abstract class IosAssetBundle extends Target {
} }
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework'); final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework');
final String frameworkBinaryPath = frameworkDirectory.childFile('App').path;
final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets'); final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets');
frameworkDirectory.createSync(recursive: true); frameworkDirectory.createSync(recursive: true);
assetDirectory.createSync(); assetDirectory.createSync();
...@@ -470,7 +468,7 @@ abstract class IosAssetBundle extends Target { ...@@ -470,7 +468,7 @@ abstract class IosAssetBundle extends Target {
environment.buildDir environment.buildDir
.childDirectory('App.framework') .childDirectory('App.framework')
.childFile('App') .childFile('App')
.copySync(frameworkDirectory.childFile('App').path); .copySync(frameworkBinaryPath);
final String vmSnapshotData = environment.artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug); final String vmSnapshotData = environment.artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug);
final String isolateSnapshotData = environment.artifacts.getArtifactPath(Artifact.isolateSnapshotData, mode: BuildMode.debug); final String isolateSnapshotData = environment.artifacts.getArtifactPath(Artifact.isolateSnapshotData, mode: BuildMode.debug);
...@@ -482,7 +480,7 @@ abstract class IosAssetBundle extends Target { ...@@ -482,7 +480,7 @@ abstract class IosAssetBundle extends Target {
.copySync(assetDirectory.childFile('isolate_snapshot_data').path); .copySync(assetDirectory.childFile('isolate_snapshot_data').path);
} else { } else {
environment.buildDir.childDirectory('App.framework').childFile('App') environment.buildDir.childDirectory('App.framework').childFile('App')
.copySync(frameworkDirectory.childFile('App').path); .copySync(frameworkBinaryPath);
} }
// Copy the assets. // Copy the assets.
...@@ -512,6 +510,8 @@ abstract class IosAssetBundle extends Target { ...@@ -512,6 +510,8 @@ abstract class IosAssetBundle extends Target {
.copySync(environment.outputDir .copySync(environment.outputDir
.childDirectory('App.framework') .childDirectory('App.framework')
.childFile('Info.plist').path); .childFile('Info.plist').path);
_signFramework(environment, frameworkBinaryPath, buildMode);
} }
} }
...@@ -576,7 +576,7 @@ class ReleaseIosApplicationBundle extends IosAssetBundle { ...@@ -576,7 +576,7 @@ class ReleaseIosApplicationBundle extends IosAssetBundle {
/// This framework needs to exist for the Xcode project to link/bundle, /// This framework needs to exist for the Xcode project to link/bundle,
/// but it isn't actually executed. To generate something valid, we compile a trivial /// but it isn't actually executed. To generate something valid, we compile a trivial
/// constant. /// constant.
Future<RunResult> createStubAppFramework(File outputFile, String sdkRoot, Future<void> _createStubAppFramework(File outputFile, Environment environment,
Set<String> iosArchNames) async { Set<String> iosArchNames) async {
try { try {
outputFile.createSync(recursive: true); outputFile.createSync(recursive: true);
...@@ -592,7 +592,8 @@ Future<RunResult> createStubAppFramework(File outputFile, String sdkRoot, ...@@ -592,7 +592,8 @@ Future<RunResult> createStubAppFramework(File outputFile, String sdkRoot,
static const int Moo = 88; static const int Moo = 88;
'''); ''');
return await globals.xcode.clang(<String>[ final String sdkRoot = environment.defines[kSdkRoot];
await globals.xcode.clang(<String>[
'-x', '-x',
'c', 'c',
for (String arch in iosArchNames) ...<String>['-arch', arch], for (String arch in iosArchNames) ...<String>['-arch', arch],
...@@ -616,4 +617,27 @@ Future<RunResult> createStubAppFramework(File outputFile, String sdkRoot, ...@@ -616,4 +617,27 @@ Future<RunResult> createStubAppFramework(File outputFile, String sdkRoot,
throwToolExit('Failed to create App.framework stub at ${outputFile.path}: $e'); throwToolExit('Failed to create App.framework stub at ${outputFile.path}: $e');
} }
} }
_signFramework(environment, outputFile.path, BuildMode.debug);
}
void _signFramework(Environment environment, String binaryPath, BuildMode buildMode) {
final String codesignIdentity = environment.defines[kCodesignIdentity];
if (codesignIdentity == null || codesignIdentity.isEmpty) {
return;
}
final ProcessResult result = environment.processManager.runSync(<String>[
'codesign',
'--force',
'--sign',
codesignIdentity,
if (buildMode != BuildMode.release) ...<String>[
// Mimic Xcode's timestamp codesigning behavior on non-release binaries.
'--timestamp=none',
],
binaryPath,
]);
if (result.exitCode != 0) {
throw Exception('Failed to codesign $binaryPath with identity $codesignIdentity.\n${result.stderr}');
}
} }
...@@ -95,6 +95,7 @@ void main() { ...@@ -95,6 +95,7 @@ void main() {
); );
await const DebugUniversalFramework().build(environment); await const DebugUniversalFramework().build(environment);
expect(processManager.hasRemainingExpectations, isFalse);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => processManager, ProcessManager: () => processManager,
...@@ -104,6 +105,7 @@ void main() { ...@@ -104,6 +105,7 @@ void main() {
testUsingContext('DebugIosApplicationBundle', () async { testUsingContext('DebugIosApplicationBundle', () async {
environment.inputs[kBundleSkSLPath] = 'bundle.sksl'; environment.inputs[kBundleSkSLPath] = 'bundle.sksl';
environment.defines[kBuildMode] = 'debug'; environment.defines[kBuildMode] = 'debug';
environment.defines[kCodesignIdentity] = 'ABC123';
// Precompiled dart data // Precompiled dart data
fileSystem.file(artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug)) fileSystem.file(artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug))
...@@ -120,7 +122,7 @@ void main() { ...@@ -120,7 +122,7 @@ void main() {
environment.buildDir.childFile('app.dill').createSync(recursive: true); environment.buildDir.childFile('app.dill').createSync(recursive: true);
// Stub framework // Stub framework
environment.buildDir environment.buildDir
.childDirectory('App.framework') .childDirectory('App.framework')
.childFile('App') .childFile('App')
.createSync(recursive: true); .createSync(recursive: true);
// sksl bundle // sksl bundle
...@@ -134,10 +136,23 @@ void main() { ...@@ -134,10 +136,23 @@ void main() {
} }
)); ));
final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework');
final File frameworkDirectoryBinary = frameworkDirectory.childFile('App');
processManager.addCommand(
FakeCommand(command: <String>[
'codesign',
'--force',
'--sign',
'ABC123',
'--timestamp=none',
frameworkDirectoryBinary.path,
]),
);
await const DebugIosApplicationBundle().build(environment); await const DebugIosApplicationBundle().build(environment);
expect(processManager.hasRemainingExpectations, isFalse);
final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework'); expect(frameworkDirectoryBinary, exists);
expect(frameworkDirectory.childFile('App'), exists);
expect(frameworkDirectory.childFile('Info.plist'), exists); expect(frameworkDirectory.childFile('Info.plist'), exists);
final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets'); final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets');
...@@ -151,6 +166,7 @@ void main() { ...@@ -151,6 +166,7 @@ void main() {
testUsingContext('ReleaseIosApplicationBundle', () async { testUsingContext('ReleaseIosApplicationBundle', () async {
environment.defines[kBuildMode] = 'release'; environment.defines[kBuildMode] = 'release';
environment.defines[kCodesignIdentity] = 'ABC123';
// Project info // Project info
fileSystem.file('pubspec.yaml').writeAsStringSync('name: hello'); fileSystem.file('pubspec.yaml').writeAsStringSync('name: hello');
...@@ -165,10 +181,23 @@ void main() { ...@@ -165,10 +181,23 @@ void main() {
.childFile('App') .childFile('App')
.createSync(recursive: true); .createSync(recursive: true);
await const ReleaseIosApplicationBundle().build(environment);
final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework'); final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework');
expect(frameworkDirectory.childFile('App'), exists); final File frameworkDirectoryBinary = frameworkDirectory.childFile('App');
processManager.addCommand(
FakeCommand(command: <String>[
'codesign',
'--force',
'--sign',
'ABC123',
frameworkDirectoryBinary.path,
]),
);
await const ReleaseIosApplicationBundle().build(environment);
expect(processManager.hasRemainingExpectations, isFalse);
expect(frameworkDirectoryBinary, exists);
expect(frameworkDirectory.childFile('Info.plist'), exists); expect(frameworkDirectory.childFile('Info.plist'), exists);
final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets'); final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets');
...@@ -205,6 +234,7 @@ void main() { ...@@ -205,6 +234,7 @@ void main() {
contains('release/profile builds are only supported for physical devices.'), contains('release/profile builds are only supported for physical devices.'),
) )
)); ));
expect(processManager.hasRemainingExpectations, isFalse);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => processManager, ProcessManager: () => processManager,
...@@ -233,19 +263,25 @@ void main() { ...@@ -233,19 +263,25 @@ void main() {
contains('required define SdkRoot but it was not provided'), contains('required define SdkRoot but it was not provided'),
) )
)); ));
expect(processManager.hasRemainingExpectations, isFalse);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => processManager, ProcessManager: () => processManager,
Platform: () => macPlatform, Platform: () => macPlatform,
}); });
group('copy, thin, and bitcode strip engine Flutter.framework', () { group('copies Flutter.framework', () {
Directory outputDir; Directory outputDir;
File binary;
FakeCommand copyPhysicalFrameworkCommand; FakeCommand copyPhysicalFrameworkCommand;
FakeCommand lipoCommandNonFatResult;
FakeCommand lipoVerifyArm64Command;
FakeCommand bitcodeStripCommand;
setUp(() { setUp(() {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
outputDir = fileSystem.directory('output'); outputDir = fileSystem.directory('output');
binary = outputDir.childDirectory('Flutter.framework').childFile('Flutter');
copyPhysicalFrameworkCommand = FakeCommand(command: <String>[ copyPhysicalFrameworkCommand = FakeCommand(command: <String>[
'rsync', 'rsync',
'-av', '-av',
...@@ -255,10 +291,31 @@ void main() { ...@@ -255,10 +291,31 @@ void main() {
'Artifact.flutterFramework.TargetPlatform.ios.debug.EnvironmentType.physical', 'Artifact.flutterFramework.TargetPlatform.ios.debug.EnvironmentType.physical',
outputDir.path, outputDir.path,
]); ]);
lipoCommandNonFatResult = FakeCommand(command: <String>[
'lipo',
'-info',
binary.path,
], stdout: 'Non-fat file:');
lipoVerifyArm64Command = FakeCommand(command: <String>[
'lipo',
binary.path,
'-verify_arch',
'arm64',
]);
bitcodeStripCommand = FakeCommand(command: <String>[
'xcrun',
'bitcode_strip',
binary.path,
'-m',
'-o',
binary.path,
]);
}); });
testWithoutContext('iphonesimulator', () async { testWithoutContext('iphonesimulator', () async {
final File binary = outputDir.childDirectory('Flutter.framework').childFile('Flutter');
final Environment environment = Environment.test( final Environment environment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
processManager: processManager, processManager: processManager,
...@@ -273,7 +330,7 @@ void main() { ...@@ -273,7 +330,7 @@ void main() {
}, },
); );
processManager.addCommand( processManager.addCommands(<FakeCommand>[
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'rsync', 'rsync',
'-av', '-av',
...@@ -285,24 +342,14 @@ void main() { ...@@ -285,24 +342,14 @@ void main() {
], ],
onRun: () => binary.createSync(recursive: true), onRun: () => binary.createSync(recursive: true),
), ),
); lipoCommandNonFatResult,
processManager.addCommand(
FakeCommand(command: <String>[
'lipo',
'-info',
binary.path,
], stdout: 'Non-fat file:'),
);
processManager.addCommand(
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'lipo',
binary.path, binary.path,
'-verify_arch', '-verify_arch',
'x86_64', 'x86_64',
]), ]),
); ]);
await const DebugUnpackIOS().build(environment); await const DebugUnpackIOS().build(environment);
expect(logger.traceText, contains('Skipping lipo for non-fat file output/Flutter.framework/Flutter')); expect(logger.traceText, contains('Skipping lipo for non-fat file output/Flutter.framework/Flutter'));
...@@ -334,7 +381,7 @@ void main() { ...@@ -334,7 +381,7 @@ void main() {
}); });
testWithoutContext('fails when requested archs missing from framework', () async { testWithoutContext('fails when requested archs missing from framework', () async {
final File binary = outputDir.childDirectory('Flutter.framework').childFile('Flutter')..createSync(recursive: true); binary.createSync(recursive: true);
final Environment environment = Environment.test( final Environment environment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
...@@ -350,16 +397,13 @@ void main() { ...@@ -350,16 +397,13 @@ void main() {
}, },
); );
processManager.addCommand(copyPhysicalFrameworkCommand); processManager.addCommands(<FakeCommand>[
processManager.addCommand( copyPhysicalFrameworkCommand,
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'lipo',
'-info', '-info',
binary.path, binary.path,
], stdout: 'Architectures in the fat file:'), ], stdout: 'Architectures in the fat file:'),
);
processManager.addCommand(
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'lipo',
binary.path, binary.path,
...@@ -367,7 +411,7 @@ void main() { ...@@ -367,7 +411,7 @@ void main() {
'arm64', 'arm64',
'armv7', 'armv7',
], exitCode: 1), ], exitCode: 1),
); ]);
await expectLater( await expectLater(
const DebugUnpackIOS().build(environment), const DebugUnpackIOS().build(environment),
...@@ -379,7 +423,7 @@ void main() { ...@@ -379,7 +423,7 @@ void main() {
}); });
testWithoutContext('fails when lipo extract fails', () async { testWithoutContext('fails when lipo extract fails', () async {
final File binary = outputDir.childDirectory('Flutter.framework').childFile('Flutter')..createSync(recursive: true); binary.createSync(recursive: true);
final Environment environment = Environment.test( final Environment environment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
...@@ -395,16 +439,13 @@ void main() { ...@@ -395,16 +439,13 @@ void main() {
}, },
); );
processManager.addCommand(copyPhysicalFrameworkCommand); processManager.addCommands(<FakeCommand>[
processManager.addCommand( copyPhysicalFrameworkCommand,
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'lipo',
'-info', '-info',
binary.path, binary.path,
], stdout: 'Architectures in the fat file:'), ], stdout: 'Architectures in the fat file:'),
);
processManager.addCommand(
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'lipo',
binary.path, binary.path,
...@@ -412,9 +453,6 @@ void main() { ...@@ -412,9 +453,6 @@ void main() {
'arm64', 'arm64',
'armv7', 'armv7',
]), ]),
);
processManager.addCommand(
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'lipo',
'-output', '-output',
...@@ -426,7 +464,7 @@ void main() { ...@@ -426,7 +464,7 @@ void main() {
binary.path, binary.path,
], exitCode: 1, ], exitCode: 1,
stderr: 'lipo error'), stderr: 'lipo error'),
); ]);
await expectLater( await expectLater(
const DebugUnpackIOS().build(environment), const DebugUnpackIOS().build(environment),
...@@ -438,7 +476,7 @@ void main() { ...@@ -438,7 +476,7 @@ void main() {
}); });
testWithoutContext('skips thin framework', () async { testWithoutContext('skips thin framework', () async {
final File binary = outputDir.childDirectory('Flutter.framework').childFile('Flutter')..createSync(recursive: true); binary.createSync(recursive: true);
final Environment environment = Environment.test( final Environment environment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
...@@ -454,23 +492,11 @@ void main() { ...@@ -454,23 +492,11 @@ void main() {
}, },
); );
processManager.addCommand(copyPhysicalFrameworkCommand); processManager.addCommands(<FakeCommand>[
processManager.addCommand( copyPhysicalFrameworkCommand,
FakeCommand(command: <String>[ lipoCommandNonFatResult,
'lipo', lipoVerifyArm64Command,
'-info', ]);
binary.path,
], stdout: 'Non-fat file:'),
);
processManager.addCommand(
FakeCommand(command: <String>[
'lipo',
binary.path,
'-verify_arch',
'arm64',
]),
);
await const DebugUnpackIOS().build(environment); await const DebugUnpackIOS().build(environment);
expect(logger.traceText, contains('Skipping lipo for non-fat file output/Flutter.framework/Flutter')); expect(logger.traceText, contains('Skipping lipo for non-fat file output/Flutter.framework/Flutter'));
...@@ -479,7 +505,7 @@ void main() { ...@@ -479,7 +505,7 @@ void main() {
}); });
testWithoutContext('thins fat framework', () async { testWithoutContext('thins fat framework', () async {
final File binary = outputDir.childDirectory('Flutter.framework').childFile('Flutter')..createSync(recursive: true); binary.createSync(recursive: true);
final Environment environment = Environment.test( final Environment environment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
...@@ -495,16 +521,13 @@ void main() { ...@@ -495,16 +521,13 @@ void main() {
}, },
); );
processManager.addCommand(copyPhysicalFrameworkCommand); processManager.addCommands(<FakeCommand>[
processManager.addCommand( copyPhysicalFrameworkCommand,
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'lipo',
'-info', '-info',
binary.path, binary.path,
], stdout: 'Architectures in the fat file:'), ], stdout: 'Architectures in the fat file:'),
);
processManager.addCommand(
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'lipo',
binary.path, binary.path,
...@@ -512,9 +535,6 @@ void main() { ...@@ -512,9 +535,6 @@ void main() {
'arm64', 'arm64',
'armv7', 'armv7',
]), ]),
);
processManager.addCommand(
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'lipo',
'-output', '-output',
...@@ -525,14 +545,14 @@ void main() { ...@@ -525,14 +545,14 @@ void main() {
'armv7', 'armv7',
binary.path, binary.path,
]), ]),
); ]);
await const DebugUnpackIOS().build(environment); await const DebugUnpackIOS().build(environment);
expect(processManager.hasRemainingExpectations, isFalse); expect(processManager.hasRemainingExpectations, isFalse);
}); });
testWithoutContext('fails when bitcode strip fails', () async { testWithoutContext('fails when bitcode strip fails', () async {
final File binary = outputDir.childDirectory('Flutter.framework').childFile('Flutter')..createSync(recursive: true); binary.createSync(recursive: true);
final Environment environment = Environment.test( final Environment environment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
...@@ -550,17 +570,8 @@ void main() { ...@@ -550,17 +570,8 @@ void main() {
processManager.addCommands(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
copyPhysicalFrameworkCommand, copyPhysicalFrameworkCommand,
FakeCommand(command: <String>[ lipoCommandNonFatResult,
'lipo', lipoVerifyArm64Command,
'-info',
binary.path,
], stdout: 'Non-fat file:'),
FakeCommand(command: <String>[
'lipo',
binary.path,
'-verify_arch',
'arm64',
]),
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'xcrun', 'xcrun',
'bitcode_strip', 'bitcode_strip',
...@@ -583,7 +594,7 @@ void main() { ...@@ -583,7 +594,7 @@ void main() {
}); });
testWithoutContext('strips framework', () async { testWithoutContext('strips framework', () async {
final File binary = outputDir.childDirectory('Flutter.framework').childFile('Flutter')..createSync(recursive: true); binary.createSync(recursive: true);
final Environment environment = Environment.test( final Environment environment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
...@@ -601,23 +612,88 @@ void main() { ...@@ -601,23 +612,88 @@ void main() {
processManager.addCommands(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
copyPhysicalFrameworkCommand, copyPhysicalFrameworkCommand,
lipoCommandNonFatResult,
lipoVerifyArm64Command,
bitcodeStripCommand,
]);
await const DebugUnpackIOS().build(environment);
expect(processManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('fails when codesign fails', () async {
binary.createSync(recursive: true);
final Environment environment = Environment.test(
fileSystem.currentDirectory,
processManager: processManager,
artifacts: artifacts,
logger: logger,
fileSystem: fileSystem,
outputDir: outputDir,
defines: <String, String>{
kIosArchs: 'arm64',
kSdkRoot: 'path/to/iPhoneOS.sdk',
kBitcodeFlag: '',
kCodesignIdentity: 'ABC123',
},
);
processManager.addCommands(<FakeCommand>[
copyPhysicalFrameworkCommand,
lipoCommandNonFatResult,
lipoVerifyArm64Command,
bitcodeStripCommand,
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'lipo', 'codesign',
'-info', '--force',
binary.path, '--sign',
], stdout: 'Non-fat file:'), 'ABC123',
FakeCommand(command: <String>[ '--timestamp=none',
'lipo',
binary.path, binary.path,
'-verify_arch', ], exitCode: 1, stderr: 'codesign error'),
'arm64', ]);
]),
await expectLater(
const DebugUnpackIOS().build(environment),
throwsA(isA<Exception>().having(
(Exception exception) => exception.toString(),
'description',
contains('Failed to codesign output/Flutter.framework/Flutter with identity ABC123.\ncodesign error'),
)));
expect(processManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('codesigns framework', () async {
binary.createSync(recursive: true);
final Environment environment = Environment.test(
fileSystem.currentDirectory,
processManager: processManager,
artifacts: artifacts,
logger: logger,
fileSystem: fileSystem,
outputDir: outputDir,
defines: <String, String>{
kIosArchs: 'arm64',
kSdkRoot: 'path/to/iPhoneOS.sdk',
kBitcodeFlag: '',
kCodesignIdentity: 'ABC123',
},
);
processManager.addCommands(<FakeCommand>[
copyPhysicalFrameworkCommand,
lipoCommandNonFatResult,
lipoVerifyArm64Command,
bitcodeStripCommand,
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'xcrun', 'codesign',
'bitcode_strip', '--force',
binary.path, '--sign',
'-m', 'ABC123',
'-o', '--timestamp=none',
binary.path, binary.path,
]), ]),
]); ]);
......
...@@ -119,9 +119,6 @@ void main() { ...@@ -119,9 +119,6 @@ void main() {
expect(vmSnapshot.existsSync(), buildMode == BuildMode.debug); expect(vmSnapshot.existsSync(), buildMode == BuildMode.debug);
expect(outputFlutterFramework.childDirectory('Headers'), isNot(exists));
expect(outputFlutterFramework.childDirectory('Modules'), isNot(exists));
// Archiving should contain a bitcode blob, but not building. // Archiving should contain a bitcode blob, but not building.
// This mimics Xcode behavior and prevents a developer from having to install a // This mimics Xcode behavior and prevents a developer from having to install a
// 300+MB app. // 300+MB app.
......
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