Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Avoid using watchOS SDK in CI tests #94190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
241 changes: 13 additions & 228 deletions dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:convert';
import 'dart:io';

import 'package:flutter_devicelab/common.dart';
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/ios.dart';
import 'package:flutter_devicelab/framework/task_result.dart';
Expand All @@ -16,8 +14,6 @@ Future<void> main() async {
await task(() async {
section('Copy test Flutter App with watchOS Companion');

String? watchDeviceID;
String? phoneDeviceID;
final Directory tempDir = Directory.systemTemp
.createTempSync('flutter_ios_app_with_extensions_test.');
final Directory projectDir =
Expand All @@ -32,11 +28,23 @@ Future<void> main() async {

section('Create release build');

// This only builds the iOS app, not the companion watchOS app. The watchOS app
// has been removed as a build dependency and is not embedded in the app to avoid
// requiring the watchOS being available in CI.
// Instead, validate the tool detects that there is a watch companion, and omits
// the "-sdk iphoneos" option, which fails to build the watchOS app.
// See https://github.com/flutter/flutter/pull/94190.
await inDirectory(projectDir, () async {
await flutter(
final String buildOutput = await evalFlutter(
'build',
options: <String>['ios', '--no-codesign', '--release', '--verbose'],
);
if (!buildOutput.contains('Watch companion app found')) {
throw TaskResult.failure('Did not detect watch companion');
}
if (buildOutput.contains('-sdk iphoneos -destination')) {
throw TaskResult.failure('-sdk must be omitted for app with watch companion');
}
});

final String appBundle = Directory(path.join(
Expand Down Expand Up @@ -64,228 +72,17 @@ Future<void> main() async {
await _checkFlutterFrameworkArchs(appFrameworkPath);
await _checkFlutterFrameworkArchs(flutterFrameworkPath);

// Check the watch extension framework added in the Podfile
// is in place with the expected watch archs.
final String watchExtensionFrameworkPath = path.join(
appBundle,
'Watch',
'watch.app',
'PlugIns',
'watch Extension.appex',
'Frameworks',
'EFQRCode.framework',
'EFQRCode',
);
unawaited(_checkWatchExtensionFrameworkArchs(watchExtensionFrameworkPath));

section('Clean build');

await inDirectory(projectDir, () async {
await flutter('clean');
});

section('Create debug build');

await inDirectory(projectDir, () async {
await flutter(
'build',
options: <String>['ios', '--debug', '--no-codesign', '--verbose'],
);
});

checkDirectoryExists(appBundle);
await _checkFlutterFrameworkArchs(appFrameworkPath);
await _checkFlutterFrameworkArchs(flutterFrameworkPath);
unawaited(_checkWatchExtensionFrameworkArchs(watchExtensionFrameworkPath));

section('Clean build');

await inDirectory(projectDir, () async {
await flutter('clean');
});

section('Run app on simulator device');

// Xcode 11.4 simctl create makes the runtime argument optional, and defaults to latest.
// TODO(jmagman): Remove runtime parsing when devicelab upgrades to Xcode 11.4 https://github.com/flutter/flutter/issues/54889
final String availableRuntimes = await eval(
'xcrun',
<String>[
'simctl',
'list',
'runtimes',
],
workingDirectory: flutterDirectory.path,
);

// Example simctl list:
// == Runtimes ==
// iOS 10.3 (10.3.1 - 14E8301) - com.apple.CoreSimulator.SimRuntime.iOS-10-3
// iOS 13.4 (13.4 - 17E255) - com.apple.CoreSimulator.SimRuntime.iOS-13-4
// tvOS 13.4 (13.4 - 17L255) - com.apple.CoreSimulator.SimRuntime.tvOS-13-4
// watchOS 6.2 (6.2 - 17T256) - com.apple.CoreSimulator.SimRuntime.watchOS-6-2
String? iOSSimRuntime;
String? watchSimRuntime;

final RegExp iOSRuntimePattern = RegExp(r'iOS .*\) - (.*)');
final RegExp watchOSRuntimePattern = RegExp(r'watchOS .*\) - (.*)');

for (final String runtime in LineSplitter.split(availableRuntimes)) {
// These seem to be in order, so allow matching multiple lines so it grabs
// the last (hopefully latest) one.
final RegExpMatch? iOSRuntimeMatch = iOSRuntimePattern.firstMatch(runtime);
if (iOSRuntimeMatch != null) {
iOSSimRuntime = iOSRuntimeMatch.group(1)!.trim();
continue;
}
final RegExpMatch? watchOSRuntimeMatch = watchOSRuntimePattern.firstMatch(runtime);
if (watchOSRuntimeMatch != null) {
watchSimRuntime = watchOSRuntimeMatch.group(1)!.trim();
}
}
if (iOSSimRuntime == null || watchSimRuntime == null) {
String message;
if (iOSSimRuntime != null) {
message = 'Found "$iOSSimRuntime", but no watchOS simulator runtime found.';
} else if (watchSimRuntime != null) {
message = 'Found "$watchSimRuntime", but no iOS simulator runtime found.';
} else {
message = 'watchOS and iOS simulator runtimes not found.';
}
return TaskResult.failure('$message Available runtimes:\n$availableRuntimes');
}

// Create iOS simulator.
phoneDeviceID = await eval(
'xcrun',
<String>[
'simctl',
'create',
'TestFlutteriPhoneWithWatch',
'com.apple.CoreSimulator.SimDeviceType.iPhone-11',
iOSSimRuntime,
],
workingDirectory: flutterDirectory.path,
);

// Create watchOS simulator.
watchDeviceID = await eval(
'xcrun',
<String>[
'simctl',
'create',
'TestFlutterWatch',
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-44mm',
watchSimRuntime,
],
workingDirectory: flutterDirectory.path,
);

// Pair watch with phone.
await eval(
'xcrun',
<String>['simctl', 'pair', watchDeviceID, phoneDeviceID],
workingDirectory: flutterDirectory.path,
);

// Boot simulator devices.
await eval(
'xcrun',
<String>['simctl', 'bootstatus', phoneDeviceID, '-b'],
workingDirectory: flutterDirectory.path,
);
await eval(
'xcrun',
<String>['simctl', 'bootstatus', watchDeviceID, '-b'],
workingDirectory: flutterDirectory.path,
);

// Start app on simulated device.
final Process process = await startProcess(
path.join(flutterDirectory.path, 'bin', 'flutter'),
<String>['run', '-d', phoneDeviceID],
workingDirectory: projectDir.path);

process.stdout
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.listen((String line) {
print('stdout: $line');
// Wait for app startup to complete and quit immediately afterwards.
if (line.startsWith('An Observatory debugger')) {
process.stdin.write('q');
}
});
process.stderr
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.listen((String line) {
print('stderr: $line');
});

final int exitCode = await process.exitCode;

if (exitCode != 0) {
return TaskResult.failure(
'Failed to start flutter iOS app with WatchOS companion on simulated device.');
}

final String simulatorAppBundle = Directory(path.join(
projectDir.path,
'build',
'ios',
'iphonesimulator',
'Runner.app',
)).path;

checkDirectoryExists(simulatorAppBundle);
checkFileExists(path.join(
simulatorAppBundle,
'Frameworks',
'App.framework',
'App',
));
checkFileExists(path.join(
simulatorAppBundle,
'Frameworks',
'Flutter.framework',
'Flutter',
));

return TaskResult.success(null);
} catch (e) {
return TaskResult.failure(e.toString());
} finally {
rmTree(tempDir);
// Delete simulator devices
if (watchDeviceID != null && watchDeviceID != '') {
await eval(
'xcrun',
<String>['simctl', 'shutdown', watchDeviceID],
canFail: true,
workingDirectory: flutterDirectory.path,
);
await eval(
'xcrun',
<String>['simctl', 'delete', watchDeviceID],
canFail: true,
workingDirectory: flutterDirectory.path,
);
}
if (phoneDeviceID != null && phoneDeviceID != '') {
await eval(
'xcrun',
<String>['simctl', 'shutdown', phoneDeviceID],
canFail: true,
workingDirectory: flutterDirectory.path,
);
await eval(
'xcrun',
<String>['simctl', 'delete', phoneDeviceID],
canFail: true,
workingDirectory: flutterDirectory.path,
);
}
}
});
}
Expand All @@ -302,15 +99,3 @@ Future<void> _checkFlutterFrameworkArchs(String frameworkPath) async {
throw TaskResult.failure('$frameworkPath x86_64 architecture unexpectedly present');
}
}

Future<void> _checkWatchExtensionFrameworkArchs(String frameworkPath) async {
checkFileExists(frameworkPath);
final String archs = await fileType(frameworkPath);
if (!archs.contains('armv7k')) {
throw TaskResult.failure('$frameworkPath armv7k architecture missing');
}

if (!archs.contains('arm64_32')) {
throw TaskResult.failure('$frameworkPath arm64_32 architecture missing');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
49C15B60243E340E0025F804 /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C15B5F243E340E0025F804 /* ExtensionDelegate.swift */; };
49C15B62243E340F0025F804 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 49C15B61243E340F0025F804 /* Assets.xcassets */; };
49C15B65243E340F0025F804 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 49C15B64243E340F0025F804 /* Preview Assets.xcassets */; };
49C15B69243E340F0025F804 /* watch.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 49C15B4A243E340B0025F804 /* watch.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stop embedding the watch.

74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
Expand All @@ -34,13 +33,6 @@
remoteGlobalIDString = 49C15B55243E340E0025F804;
remoteInfo = "watch Extension";
};
49C15B67243E340F0025F804 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 49C15B49243E340B0025F804;
remoteInfo = watch;
};
/* End PBXContainerItemProxy section */

/* Begin PBXCopyFilesBuildPhase section */
Expand All @@ -55,17 +47,6 @@
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
49C15B73243E340F0025F804 /* Embed Watch Content */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
dstSubfolderSpec = 16;
files = (
49C15B69243E340F0025F804 /* watch.app in Embed Watch Content */,
);
name = "Embed Watch Content";
runOnlyForDeploymentPostprocessing = 0;
};
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
Expand Down Expand Up @@ -307,13 +288,11 @@
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
49C15B73243E340F0025F804 /* Embed Watch Content */,
DF3DAF4426EF33A40B49B448 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
49C15B68243E340F0025F804 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
Expand Down Expand Up @@ -531,11 +510,6 @@
target = 49C15B55243E340E0025F804 /* watch Extension */;
targetProxy = 49C15B58243E340E0025F804 /* PBXContainerItemProxy */;
};
49C15B68243E340F0025F804 /* PBXTargetDependency */ = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And remove the watch as an iOS app build dependency.

isa = PBXTargetDependency;
target = 49C15B49243E340B0025F804 /* watch */;
targetProxy = 49C15B67243E340F0025F804 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Xcode gonna Xcode, let it touch this file.

</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
Expand All @@ -38,8 +36,8 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
Expand All @@ -61,8 +59,6 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
Expand Down