Add more instructions and handling for first time iOS run (#10521)

* Before tests

* Add the part to trust the cert on the device

* flip the error checks since some are more specific and are more actionable

* add tests

* review
This commit is contained in:
xster 2017-06-07 15:56:13 -07:00 committed by GitHub
parent 96b9d6473e
commit c2b0a30c57
5 changed files with 247 additions and 56 deletions

View file

@ -45,7 +45,7 @@ class BuildIOSCommand extends BuildSubCommand {
if (getCurrentHostPlatform() != HostPlatform.darwin_x64)
throwToolExit('Building for iOS is only supported on the Mac.');
final IOSApp app = applicationPackages.getPackageForPlatform(TargetPlatform.ios);
final BuildableIOSApp app = applicationPackages.getPackageForPlatform(TargetPlatform.ios);
if (app == null)
throwToolExit('Application not configured for iOS');
@ -73,7 +73,7 @@ class BuildIOSCommand extends BuildSubCommand {
);
if (!result.success) {
await diagnoseXcodeBuildFailure(result);
await diagnoseXcodeBuildFailure(result, app);
throwToolExit('Encountered error while building for $logTarget.');
}

View file

@ -14,34 +14,60 @@ import '../base/process.dart';
import '../base/terminal.dart';
import '../globals.dart';
/// User message when no development certificates are found in the keychain.
///
/// The user likely never did any iOS development.
const String noCertificatesInstruction = '''
No valid code signing certificates were found
Please ensure that you have a valid Development Team with valid iOS Development Certificates
associated with your Apple ID by:
1- Opening the Xcode application
2- Go to Xcode->Preferences->Accounts
3- Make sure that you're signed in with your Apple ID via the '+' button on the bottom left
4- Make sure that you have development certificates available by signing up to Apple
Developer Program and/or downloading available profiles as needed.
You can connect to your Apple Developer account by signing in with your Apple ID in Xcode
and create an iOS Development Certificate as well as a Provisioning Profile for your project by:
$fixWithDevelopmentTeamInstruction
5- Trust your newly created Development Certificate on your iOS device
via Settings > General > Device Management > [your new certificate] > Trust
For more information, please visit:
https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingCertificates/MaintainingCertificates.html
Or run on an iOS simulator without code signing
''';
/// User message when there are no provisioning profile for the current app bundle identifier.
///
/// The user did iOS development but never on this project and/or device.
const String noProvisioningProfileInstruction = '''
No Provisioning Profile was found for your project's Bundle Identifier or your device.
You can create a new Provisioning Profile for your project in Xcode for your
team by:
$fixWithDevelopmentTeamInstruction
For more information, please visit:
https://flutter.io/setup/#deploy-to-ios-devices
Or run on an iOS simulator without code signing
''';
/// Fallback error message for signing issues.
///
/// Couldn't auto sign the app but can likely solved by retracing the signing flow in Xcode.
const String noDevelopmentTeamInstruction = '''
Building a deployable iOS app requires a selected Development Team with a Provisioning Profile
Please ensure that a Development Team is selected by:
1- Opening the Flutter project's Xcode target with
$fixWithDevelopmentTeamInstruction
For more information, please visit:
https://flutter.io/setup/#deploy-to-ios-devices
Or run on an iOS simulator without code signing
''';
const String fixWithDevelopmentTeamInstruction = '''
1- Open the Flutter project's Xcode target with
open ios/Runner.xcworkspace
2- Select the 'Runner' project in the navigator then the 'Runner' target
in the project settings
3- In the 'General' tab, make sure a 'Development Team' is selected\n
For more information, please visit:
https://flutter.io/setup/#deploy-to-ios-devices\n
Or run on an iOS simulator
''';
3- In the 'General' tab, make sure a 'Development Team' is selected. You may need to add
your Apple ID first.
4- Build or run your project again''';
final RegExp _securityFindIdentityDeveloperIdentityExtractionPattern =
new RegExp(r'^\s*\d+\).+"(.+Developer.+)"$');

View file

@ -208,7 +208,7 @@ class IOSDevice extends Device {
final XcodeBuildResult buildResult = await buildXcodeProject(app: app, mode: mode, target: mainPath, buildForDevice: true);
if (!buildResult.success) {
printError('Could not build the precompiled application for the device.');
await diagnoseXcodeBuildFailure(buildResult);
await diagnoseXcodeBuildFailure(buildResult, app);
printError('');
return new LaunchResult.failed();
}
@ -242,7 +242,7 @@ class IOSDevice extends Device {
// the port picked and scrape that later.
}
if (debuggingOptions.enableSoftwareRendering)
if (debuggingOptions.enableSoftwareRendering)
launchArguments.add('--enable-software-rendering');
if (platformArgs['trace-startup'] ?? false)

View file

@ -147,7 +147,7 @@ Future<XcodeBuildResult> buildXcodeProject({
}
String developmentTeam;
if (codesign && mode != BuildMode.release && buildForDevice)
if (codesign && buildForDevice)
developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app);
// Before the build, all service definitions must be updated and the dylibs
@ -246,51 +246,40 @@ Future<XcodeBuildResult> buildXcodeProject({
}
}
Future<Null> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
final File plistFile = fs.file('ios/Runner/Info.plist');
if (plistFile.existsSync()) {
final String plistContent = plistFile.readAsStringSync();
if (plistContent.contains('com.yourcompany')) {
printError('');
printError('It appears that your application still contains the default signing identifier.');
printError("Try replacing 'com.yourcompany' with your signing id");
printError('in ${plistFile.absolute.path}');
return;
}
Future<Null> diagnoseXcodeBuildFailure(XcodeBuildResult result, BuildableIOSApp app) async {
if (result.xcodeBuildExecution != null &&
result.xcodeBuildExecution.buildForPhysicalDevice &&
result.stdout?.contains('BCEROR') == true &&
// May need updating if Xcode changes its outputs.
result.stdout?.contains('Xcode couldn\'t find a provisioning profile matching') == true) {
printError(noProvisioningProfileInstruction, emphasis: true);
return;
}
if (result.xcodeBuildExecution != null &&
result.xcodeBuildExecution.buildForPhysicalDevice &&
// Make sure the user has specified at least the DEVELOPMENT_TEAM (for automatic Xcode 8)
// signing or the PROVISIONING_PROFILE (for manual signing or Xcode 7).
!(app.buildSettings?.containsKey('DEVELOPMENT_TEAM')) == true || app.buildSettings?.containsKey('PROVISIONING_PROFILE') == true) {
printError(noDevelopmentTeamInstruction, emphasis: true);
return;
}
if (app.id?.contains('com.yourcompany') ?? false) {
printError('');
printError('It appears that your application still contains the default signing identifier.');
printError("Try replacing 'com.yourcompany' with your signing id in Xcode:");
printError(' open ios/Runner.xcworkspace');
return;
}
if (result.stdout?.contains('Code Sign error') == true) {
printError('');
printError('It appears that there was a problem signing your application prior to installation on the device.');
printError('');
if (plistFile.existsSync()) {
printError('Verify that the CFBundleIdentifier in the Info.plist file is your signing id');
printError(' ${plistFile.absolute.path}');
printError('');
}
printError("Try launching Xcode and selecting 'Product > Build' to fix the problem:");
printError(" open ios/Runner.xcworkspace");
printError('Verify that the Bundle Identifier in your project is your signing id in Xcode');
printError(' open ios/Runner.xcworkspace');
printError('');
printError("Also try selecting 'Product > Build' to fix the problem:");
return;
}
if (result.xcodeBuildExecution != null) {
assert(result.xcodeBuildExecution.buildForPhysicalDevice != null);
assert(result.xcodeBuildExecution.buildCommands != null);
assert(result.xcodeBuildExecution.appDirectory != null);
if (result.xcodeBuildExecution.buildForPhysicalDevice &&
result.xcodeBuildExecution.buildCommands.contains('build')) {
final RunResult checkBuildSettings = await runAsync(
result.xcodeBuildExecution.buildCommands..add('-showBuildSettings'),
workingDirectory: result.xcodeBuildExecution.appDirectory,
allowReentrantFlutter: true
);
// Make sure the user has specified at least the DEVELOPMENT_TEAM (for automatic Xcode 8)
// signing or the PROVISIONING_PROFILE (for manual signing or Xcode 7).
if (checkBuildSettings.exitCode == 0 &&
!checkBuildSettings.stdout?.contains(new RegExp(r'\bDEVELOPMENT_TEAM\b')) == true &&
!checkBuildSettings.stdout?.contains(new RegExp(r'\bPROVISIONING_PROFILE\b')) == true) {
printError(noDevelopmentTeamInstruction, emphasis: true);
}
}
}
}
class XcodeBuildResult {

View file

@ -0,0 +1,176 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/ios/mac.dart';
import 'package:test/test.dart';
import '../src/context.dart';
void main() {
group('Diagnose Xcode build failure', () {
BuildableIOSApp app;
setUp(() {
app = new BuildableIOSApp(
projectBundleId: 'test.app',
buildSettings: <String, String>{
'For our purposes': 'a non-empty build settings map is valid',
},
);
});
testUsingContext('No provisioning profile shows message', () async {
final XcodeBuildResult buildResult = new XcodeBuildResult(
success: false,
stdout: '''
Launching lib/main.dart on iPhone in debug mode...
Signing iOS app for device deployment using developer identity: "iPhone Developer: test@flutter.io (1122334455)"
Running Xcode build... 1.3s
Failed to build iOS app
Error output from Xcode build:
** BUILD FAILED **
The following build commands failed:
Check dependencies
(1 failure)
Xcode's output:
Build settings from command line:
ARCHS = arm64
BUILD_DIR = /Users/blah/blah
DEVELOPMENT_TEAM = AABBCCDDEE
ONLY_ACTIVE_ARCH = YES
SDKROOT = iphoneos10.3
=== CLEAN TARGET Runner OF PROJECT Runner WITH CONFIGURATION Release ===
Check dependencies
[BCEROR]No profiles for 'com.yourcompany.test' were found: Xcode couldn't find a provisioning profile matching 'com.yourcompany.test'.
[BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3'
[BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3'
[BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3'
Create product structure
/bin/mkdir -p /Users/blah/Runner.app
Clean.Remove clean /Users/blah/Runner.app.dSYM
builtin-rm -rf /Users/blah/Runner.app.dSYM
Clean.Remove clean /Users/blah/Runner.app
builtin-rm -rf /Users/blah/Runner.app
Clean.Remove clean /Users/blah/Runner-dfvicjniknvzghgwsthwtgcjhtsk/Build/Intermediates/Runner.build/Release-iphoneos/Runner.build
builtin-rm -rf /Users/blah/Runner-dfvicjniknvzghgwsthwtgcjhtsk/Build/Intermediates/Runner.build/Release-iphoneos/Runner.build
** CLEAN SUCCEEDED **
=== BUILD TARGET Runner OF PROJECT Runner WITH CONFIGURATION Release ===
Check dependencies
No profiles for 'com.yourcompany.test' were found: Xcode couldn't find a provisioning profile matching 'com.yourcompany.test'.
Code signing is required for product type 'Application' in SDK 'iOS 10.3'
Code signing is required for product type 'Application' in SDK 'iOS 10.3'
Code signing is required for product type 'Application' in SDK 'iOS 10.3'
Could not build the precompiled application for the device.
Error launching application on iPhone.''',
xcodeBuildExecution: new XcodeBuildExecution(
<String>['xcrun', 'xcodebuild', 'blah'],
'/blah/blah',
buildForPhysicalDevice: true
),
);
await diagnoseXcodeBuildFailure(buildResult, app);
expect(
testLogger.errorText,
contains('No Provisioning Profile was found for your project\'s Bundle Identifier or your device.'),
);
});
testUsingContext('No development team shows message', () async {
final XcodeBuildResult buildResult = new XcodeBuildResult(
success: false,
stdout: '''
Running "flutter packages get" in flutter_gallery... 0.6s
Launching lib/main.dart on x in release mode...
Running pod install... 1.2s
Running Xcode build... 1.4s
Failed to build iOS app
Error output from Xcode build:
** BUILD FAILED **
The following build commands failed:
Check dependencies
(1 failure)
Xcode's output:
blah
=== CLEAN TARGET url_launcher OF PROJECT Pods WITH CONFIGURATION Release ===
Check dependencies
blah
=== CLEAN TARGET Pods-Runner OF PROJECT Pods WITH CONFIGURATION Release ===
Check dependencies
blah
=== CLEAN TARGET Runner OF PROJECT Runner WITH CONFIGURATION Release ===
Check dependencies
[BCEROR]Signing for "Runner" requires a development team. Select a development team in the project editor.
[BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3'
[BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3'
[BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3'
blah
** CLEAN SUCCEEDED **
=== BUILD TARGET url_launcher OF PROJECT Pods WITH CONFIGURATION Release ===
Check dependencies
blah
=== BUILD TARGET Pods-Runner OF PROJECT Pods WITH CONFIGURATION Release ===
Check dependencies
blah
=== BUILD TARGET Runner OF PROJECT Runner WITH CONFIGURATION Release ===
Check dependencies
Signing for "Runner" requires a development team. Select a development team in the project editor.
Code signing is required for product type 'Application' in SDK 'iOS 10.3'
Code signing is required for product type 'Application' in SDK 'iOS 10.3'
Code signing is required for product type 'Application' in SDK 'iOS 10.3'
Could not build the precompiled application for the device.''',
xcodeBuildExecution: new XcodeBuildExecution(
<String>['xcrun', 'xcodebuild', 'blah'],
'/blah/blah',
buildForPhysicalDevice: true
),
);
await diagnoseXcodeBuildFailure(buildResult, app);
expect(
testLogger.errorText,
contains('Building a deployable iOS app requires a selected Development Team with a Provisioning Profile'),
);
});
});
}