Move iOS codesigning into assemble build target (#77664)
This commit is contained in:
parent
3569536e84
commit
7b1aec70ae
@ -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
|
|||||||
-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() {
|
|||||||
|
|
||||||
# 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';
|
|||||||
/// 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';
|
|||||||
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 {
|
|||||||
.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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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 {
|
|||||||
}
|
}
|
||||||
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 {
|
|||||||
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 {
|
|||||||
.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 {
|
|||||||
.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 {
|
|||||||
/// 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,
|
|||||||
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,
|
|||||||
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() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
await const DebugIosApplicationBundle().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',
|
||||||
|
'--timestamp=none',
|
||||||
|
frameworkDirectoryBinary.path,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
await const DebugIosApplicationBundle().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');
|
||||||
@ -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() {
|
|||||||
.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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
'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() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
processManager.addCommand(
|
processManager.addCommands(<FakeCommand>[
|
||||||
FakeCommand(command: <String>[
|
FakeCommand(command: <String>[
|
||||||
'rsync',
|
'rsync',
|
||||||
'-av',
|
'-av',
|
||||||
@ -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() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
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() {
|
|||||||
'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() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
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() {
|
|||||||
'arm64',
|
'arm64',
|
||||||
'armv7',
|
'armv7',
|
||||||
]),
|
]),
|
||||||
);
|
|
||||||
|
|
||||||
processManager.addCommand(
|
|
||||||
FakeCommand(command: <String>[
|
FakeCommand(command: <String>[
|
||||||
'lipo',
|
'lipo',
|
||||||
'-output',
|
'-output',
|
||||||
@ -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() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
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() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
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() {
|
|||||||
'arm64',
|
'arm64',
|
||||||
'armv7',
|
'armv7',
|
||||||
]),
|
]),
|
||||||
);
|
|
||||||
|
|
||||||
processManager.addCommand(
|
|
||||||
FakeCommand(command: <String>[
|
FakeCommand(command: <String>[
|
||||||
'lipo',
|
'lipo',
|
||||||
'-output',
|
'-output',
|
||||||
@ -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() {
|
|||||||
|
|
||||||
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() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
|
|
||||||
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',
|
||||||
|
'--sign',
|
||||||
|
'ABC123',
|
||||||
|
'--timestamp=none',
|
||||||
binary.path,
|
binary.path,
|
||||||
], stdout: 'Non-fat file:'),
|
], exitCode: 1, stderr: 'codesign error'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
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>[
|
||||||
'lipo',
|
'codesign',
|
||||||
binary.path,
|
'--force',
|
||||||
'-verify_arch',
|
'--sign',
|
||||||
'arm64',
|
'ABC123',
|
||||||
]),
|
'--timestamp=none',
|
||||||
FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'bitcode_strip',
|
|
||||||
binary.path,
|
|
||||||
'-m',
|
|
||||||
'-o',
|
|
||||||
binary.path,
|
binary.path,
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
|
@ -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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user