Re-reland Xcode backend refactor (#23762) * Use Xcode build configurations to drive Flutter build mode * Proper check wrt local_engine, print error if profile mode misisng * Remove unused code, update tests, fix template problem, update warning * fix up warning * add explanatory dev comment * fix whitespace * missing words, change lambda arrow to function body * error indentation * Test early exits for xcode_backend.sh * only on macOS, use right test * Update error messages * case insensitive compare for build config * Update gallery podfile * update projects to add profile configuration * make compatible with flavors * add missing plist files * add FLUTTER_FRAMEWORK_DIR back, set swift version for profile, tell Podfile about profile
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh index 7348c0e..acdcf56 100755 --- a/packages/flutter_tools/bin/xcode_backend.sh +++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -46,12 +46,35 @@ target_path="${FLUTTER_TARGET}" fi + # Use FLUTTER_BUILD_MODE if it's set, otherwise use the Xcode build configuration name + # This means that if someone wants to use an Xcode build config other than Debug/Profile/Release, + # they _must_ set FLUTTER_BUILD_MODE so we know what type of artifact to build. + local build_mode="$(echo "${FLUTTER_BUILD_MODE:-${CONFIGURATION}}" | tr "[:upper:]" "[:lower:]")" + local artifact_variant="unknown" + case "$build_mode" in + release*) build_mode="release"; artifact_variant="ios-release";; + profile*) build_mode="profile"; artifact_variant="ios-profile";; + debug*) build_mode="debug"; artifact_variant="ios";; + *) + EchoError "========================================================================" + EchoError "ERROR: Unknown FLUTTER_BUILD_MODE: ${build_mode}." + EchoError "Valid values are 'Debug', 'Profile', or 'Release' (case insensitive)." + EchoError "This is controlled by the FLUTTER_BUILD_MODE environment varaible." + EchoError "If that is not set, the CONFIGURATION environment variable is used." + EchoError "" + EchoError "You can fix this by either adding an appropriately named build" + EchoError "configuration, or adding an appriate value for FLUTTER_BUILD_MODE to the" + EchoError ".xcconfig file for the current build configuration (${CONFIGURATION})." + EchoError "========================================================================" + exit -1;; + esac + # Archive builds (ACTION=install) should always run in release mode. - if [[ "$ACTION" == "install" && "$FLUTTER_BUILD_MODE" != "release" ]]; then + if [[ "$ACTION" == "install" && "$build_mode" != "release" ]]; then EchoError "========================================================================" EchoError "ERROR: Flutter archive builds must be run in Release mode." EchoError "" - EchoError "To correct, run:" + EchoError "To correct, ensure FLUTTER_BUILD_MODE is set to release or run:" EchoError "flutter build ios --release" EchoError "" EchoError "then re-run Archive from Xcode." @@ -59,24 +82,9 @@ exit -1 fi - local build_mode="release" - if [[ -n "$FLUTTER_BUILD_MODE" ]]; then - build_mode="${FLUTTER_BUILD_MODE}" - fi - - local artifact_variant="unknown" - case "$build_mode" in - release) artifact_variant="ios-release";; - profile) artifact_variant="ios-profile";; - debug) artifact_variant="ios";; - *) echo "Unknown FLUTTER_BUILD_MODE: $FLUTTER_BUILD_MODE";; - esac - local framework_path="${FLUTTER_ROOT}/bin/cache/artifacts/engine/${artifact_variant}" - if [[ -n "$FLUTTER_FRAMEWORK_DIR" ]]; then - framework_path="${FLUTTER_FRAMEWORK_DIR}" - fi - + + AssertExists "${framework_path}" AssertExists "${project_path}" local derived_dir="${SOURCE_ROOT}/Flutter" @@ -91,7 +99,20 @@ local local_engine_flag="" local flutter_framework="${framework_path}/Flutter.framework" local flutter_podspec="${framework_path}/Flutter.podspec" + if [[ -n "$LOCAL_ENGINE" ]]; then + if [[ $(echo "$LOCAL_ENGINE" | tr "[:upper:]" "[:lower:]") != *"$build_mode"* ]]; then + EchoError "========================================================================" + EchoError "ERROR: Requested build with Flutter local engine at '${LOCAL_ENGINE}'" + EchoError "This engine is not compatible with FLUTTER_BUILD_MODE: '${build_mode}'." + EchoError "You can fix this by updating the LOCAL_ENGINE environment variable, or" + EchoError "by running:" + EchoError " flutter build ios --local-engine=ios_${build_mode}" + EchoError "or" + EchoError " flutter build ios --local-engine=ios_${build_mode}_unopt" + EchoError "========================================================================" + exit -1 + fi local_engine_flag="--local-engine=${LOCAL_ENGINE}" flutter_framework="${LOCAL_ENGINE}/Flutter.framework" flutter_podspec="${LOCAL_ENGINE}/Flutter.podspec" @@ -129,6 +150,16 @@ StreamOutput " ├─Building Dart code..." # Transform ARCHS to comma-separated list of target architectures. local archs="${ARCHS// /,}" + if [[ $archs =~ .*i386.* || $archs =~ .*x86_64.* ]]; then + EchoError "========================================================================" + EchoError "ERROR: Flutter does not support running in profile or release mode on" + EchoError "the Simulator (this build was: '$build_mode')." + EchoError "You can ensure Flutter runs in Debug mode with your host app in release" + EchoError "mode by setting FLUTTER_BUILD_MODE=debug in the .xcconfig associated" + EchoError "with the ${CONFIGURATION} build configuration." + EchoError "========================================================================" + exit -1 + fi RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics \ ${verbose_flag} \ build aot \ @@ -309,8 +340,10 @@ # Prefer the hidden .ios folder, but fallback to a visible ios folder if .ios # doesn't exist. local flutter_ios_out_folder="${FLUTTER_APPLICATION_PATH}/.ios/Flutter" + local flutter_ios_engine_folder="${FLUTTER_APPLICATION_PATH}/.ios/Flutter/engine" if [[ ! -d ${flutter_ios_out_folder} ]]; then flutter_ios_out_folder="${FLUTTER_APPLICATION_PATH}/ios/Flutter" + flutter_ios_engine_folder="${FLUTTER_APPLICATION_PATH}/ios/Flutter" fi AssertExists "${flutter_ios_out_folder}" @@ -330,7 +363,7 @@ # Remove it first since Xcode might be trying to hold some of these files - this way we're # sure to get a clean copy. RunCommand rm -rf -- "${xcode_frameworks_dir}/Flutter.framework" - RunCommand cp -Rv -- "${flutter_ios_out_folder}/engine/Flutter.framework" "${xcode_frameworks_dir}/" + RunCommand cp -Rv -- "${flutter_ios_engine_folder}/Flutter.framework" "${xcode_frameworks_dir}/" # Sign the binaries we moved. local identity="${EXPANDED_CODE_SIGN_IDENTITY_NAME:-$CODE_SIGN_IDENTITY}"
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 346392a..77286f0 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -317,6 +317,23 @@ printError('Flutter expects a build configuration named ${XcodeProjectInfo.expectedBuildConfigurationFor(buildInfo, scheme)} or similar.'); printError('Open Xcode to fix the problem:'); printError(' open ios/Runner.xcworkspace'); + printError('1. Click on "Runner" in the project navigator.'); + printError('2. Ensure the Runner PROJECT is selected, not the Runner TARGET.'); + if (buildInfo.isDebug) { + printError('3. Click the Editor->Add Configuration->Duplicate "Debug" Configuration.'); + } else { + printError('3. Click the Editor->Add Configuration->Duplicate "Release" Configuration.'); + } + printError(''); + printError(' If this option is disabled, it is likely you have the target selected instead'); + printError(' of the project; see:'); + printError(' https://stackoverflow.com/questions/19842746/adding-a-build-configuration-in-xcode'); + printError(''); + printError(' If you have created a completely custom set of build configurations,'); + printError(' you can set the FLUTTER_BUILD_MODE=${buildInfo.modeName.toLowerCase()}'); + printError(' in the .xcconfig file for that configuration and run from Xcode.'); + printError(''); + printError('4. If you are not using completely custom build configurations, name the newly created configuration ${buildInfo.modeName}.'); return XcodeBuildResult(success: false); }
diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart index 2bb2a20..e8e07fc 100644 --- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart +++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
@@ -49,9 +49,6 @@ if (targetOverride != null) localsBuffer.writeln('FLUTTER_TARGET=$targetOverride'); - // The runtime mode for the current build. - localsBuffer.writeln('FLUTTER_BUILD_MODE=${buildInfo.modeName}'); - // The build outputs directory, relative to FLUTTER_APPLICATION_PATH. localsBuffer.writeln('FLUTTER_BUILD_DIR=${getBuildDirectory()}'); @@ -61,6 +58,7 @@ // For module projects we do not want to write the FLUTTER_FRAMEWORK_DIR // explicitly. Rather we rely on the xcode backend script and the Podfile // logic to derive it from FLUTTER_ROOT and FLUTTER_BUILD_MODE. + // However, this is necessary for regular projects using Cocoapods. localsBuffer.writeln('FLUTTER_FRAMEWORK_DIR=${flutterFrameworkDir(buildInfo.mode)}'); } @@ -247,6 +245,17 @@ return baseConfiguration + '-$scheme'; } + /// Checks whether the [buildConfigurations] contains the specified string, without + /// regard to case. + bool hasBuildConfiguratinForBuildMode(String buildMode) { + buildMode = buildMode.toLowerCase(); + for (String name in buildConfigurations) { + if (name.toLowerCase() == buildMode) { + return true; + } + } + return false; + } /// Returns unique scheme matching [buildInfo], or null, if there is no unique /// best match. String schemeFor(BuildInfo buildInfo) { @@ -262,7 +271,7 @@ /// null, if there is no unique best match. String buildConfigurationFor(BuildInfo buildInfo, String scheme) { final String expectedConfiguration = expectedBuildConfigurationFor(buildInfo, scheme); - if (buildConfigurations.contains(expectedConfiguration)) + if (hasBuildConfiguratinForBuildMode(expectedConfiguration)) return expectedConfiguration; final String baseConfiguration = _baseConfigurationFor(buildInfo); return _uniqueMatch(buildConfigurations, (String candidate) { @@ -274,7 +283,13 @@ }); } - static String _baseConfigurationFor(BuildInfo buildInfo) => buildInfo.isDebug ? 'Debug' : 'Release'; + static String _baseConfigurationFor(BuildInfo buildInfo) { + if (buildInfo.isDebug) + return 'Debug'; + if (buildInfo.isProfile) + return 'Profile'; + return 'Release'; + } static String _uniqueMatch(Iterable<String> strings, bool matches(String s)) { final List<String> options = strings.where(matches).toList();
diff --git a/packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl b/packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl index dafa4ce..92e02fc 100644 --- a/packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl +++ b/packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl
@@ -261,6 +261,78 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; @@ -417,6 +489,7 @@ buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -426,6 +499,7 @@ buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release;
diff --git a/packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..786d6aa --- /dev/null +++ b/packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0910" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "97C146ED1CF9000F007C117D" + BuildableName = "Runner.app" + BlueprintName = "Runner" + ReferencedContainer = "container:Runner.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "97C146ED1CF9000F007C117D" + BuildableName = "Runner.app" + BlueprintName = "Runner" + ReferencedContainer = "container:Runner.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "97C146ED1CF9000F007C117D" + BuildableName = "Runner.app" + BlueprintName = "Runner" + ReferencedContainer = "container:Runner.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Profile" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "97C146ED1CF9000F007C117D" + BuildableName = "Runner.app" + BlueprintName = "Runner" + ReferencedContainer = "container:Runner.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme>
diff --git a/packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/project.pbxproj.tmpl b/packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/project.pbxproj.tmpl index 096fae6..e3d6a9a 100644 --- a/packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/project.pbxproj.tmpl +++ b/packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/project.pbxproj.tmpl
@@ -257,6 +257,79 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; @@ -423,6 +496,7 @@ buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -432,11 +506,13 @@ buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + }; rootObject = 97C146E61CF9000F007C117D /* Project object */; }
diff --git a/packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..786d6aa --- /dev/null +++ b/packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0910" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "97C146ED1CF9000F007C117D" + BuildableName = "Runner.app" + BlueprintName = "Runner" + ReferencedContainer = "container:Runner.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "97C146ED1CF9000F007C117D" + BuildableName = "Runner.app" + BlueprintName = "Runner" + ReferencedContainer = "container:Runner.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "97C146ED1CF9000F007C117D" + BuildableName = "Runner.app" + BlueprintName = "Runner" + ReferencedContainer = "container:Runner.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Profile" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "97C146ED1CF9000F007C117D" + BuildableName = "Runner.app" + BlueprintName = "Runner" + ReferencedContainer = "container:Runner.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme>
diff --git a/packages/flutter_tools/templates/app/ios.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/flutter_tools/templates/app/ios.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 1263ac8..786d6aa 100644 --- a/packages/flutter_tools/templates/app/ios.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/flutter_tools/templates/app/ios.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -67,7 +67,7 @@ </AdditionalOptions> </LaunchAction> <ProfileAction - buildConfiguration = "Release" + buildConfiguration = "Profile" shouldUseLaunchSchemeArgsEnv = "YES" savedToolIdentifier = "" useCustomWorkingDirectory = "NO"
diff --git a/packages/flutter_tools/templates/cocoapods/Podfile-objc b/packages/flutter_tools/templates/cocoapods/Podfile-objc index 7c6cb6f..d077b08 100644 --- a/packages/flutter_tools/templates/cocoapods/Podfile-objc +++ b/packages/flutter_tools/templates/cocoapods/Podfile-objc
@@ -4,6 +4,12 @@ # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + def parse_KV_file(file, separator='=') file_abs_path = File.expand_path(file) if !File.exists? file_abs_path
diff --git a/packages/flutter_tools/templates/cocoapods/Podfile-swift b/packages/flutter_tools/templates/cocoapods/Podfile-swift index 2dfb501..64eddc6 100644 --- a/packages/flutter_tools/templates/cocoapods/Podfile-swift +++ b/packages/flutter_tools/templates/cocoapods/Podfile-swift
@@ -4,6 +4,12 @@ # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + def parse_KV_file(file, separator='=') file_abs_path = File.expand_path(file) if !File.exists? file_abs_path
diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl index 8d4b827..c8ea567 100644 --- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl +++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl
@@ -260,6 +260,78 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -416,6 +488,7 @@ buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -425,11 +498,13 @@ buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + }; rootObject = 97C146E61CF9000F007C117D /* Project object */; }
diff --git a/packages/flutter_tools/test/commands/create_test.dart b/packages/flutter_tools/test/commands/create_test.dart index c9016f6..b90c998 100644 --- a/packages/flutter_tools/test/commands/create_test.dart +++ b/packages/flutter_tools/test/commands/create_test.dart
@@ -481,7 +481,6 @@ final String xcodeConfig = xcodeConfigFile.readAsStringSync(); expect(xcodeConfig, contains('FLUTTER_ROOT=')); expect(xcodeConfig, contains('FLUTTER_APPLICATION_PATH=')); - expect(xcodeConfig, contains('FLUTTER_FRAMEWORK_DIR=')); // App identification final String xcodeProjectPath = fs.path.join('ios', 'Runner.xcodeproj', 'project.pbxproj'); expectExists(xcodeProjectPath);
diff --git a/packages/flutter_tools/test/ios/xcode_backend_test.dart b/packages/flutter_tools/test/ios/xcode_backend_test.dart new file mode 100644 index 0000000..26d0c63 --- /dev/null +++ b/packages/flutter_tools/test/ios/xcode_backend_test.dart
@@ -0,0 +1,68 @@ +// Copyright 2018 The Flutter 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/base/io.dart'; +import 'package:flutter_tools/src/base/platform.dart'; + +import '../src/common.dart'; + +const String xcodeBackendPath = 'bin/xcode_backend.sh'; +const String xcodeBackendErrorHeader = '========================================================================'; + +// Acceptable $CONFIGURATION/$FLUTTER_BUILD_MODE values should be debug, profile, or release +const Map<String, String> unknownConfiguration = <String, String>{ + 'CONFIGURATION': 'Custom', +}; + +// $FLUTTER_BUILD_MODE will override $CONFIGURATION +const Map<String, String> unknownFlutterBuildMode = <String, String>{ + 'FLUTTER_BUILD_MODE': 'Custom', + 'CONFIGURATION': 'Debug', +}; + +// Can't archive a non-release build. +const Map<String, String> installWithoutRelease = <String, String>{ + 'CONFIGURATION': 'Debug', + 'ACTION': 'install', +}; + +// Can't use a debug engine build with a release build. +const Map<String, String> localEngineDebugBuildModeRelease = <String, String>{ + 'SOURCE_ROOT': '../../examples/hello_world', + 'FLUTTER_ROOT': '../..', + 'LOCAL_ENGINE': '/engine/src/out/ios_debug_unopt', + 'CONFIGURATION': 'Release' +}; + +// Can't use a debug build with a profile engine. +const Map<String, String> localEngineProfileBuildeModeRelease = + <String, String>{ + 'SOURCE_ROOT': '../../examples/hello_world', + 'FLUTTER_ROOT': '../..', + 'LOCAL_ENGINE': '/engine/src/out/ios_profile', + 'CONFIGURATION': 'Debug', + 'FLUTTER_BUILD_MODE': 'Debug', +}; + +void main() { + Future<void> expectXcodeBackendFails(Map<String, String> environment) async { + final ProcessResult result = await Process.run( + xcodeBackendPath, + <String>['build'], + environment: environment, + ); + expect(result.stderr, startsWith(xcodeBackendErrorHeader)); + expect(result.exitCode, isNot(0)); + } + + test('Xcode backend fails for on unsupported configuration combinations', () async { + await expectXcodeBackendFails(unknownConfiguration); + await expectXcodeBackendFails(unknownFlutterBuildMode); + + await expectXcodeBackendFails(installWithoutRelease); + + await expectXcodeBackendFails(localEngineDebugBuildModeRelease); + await expectXcodeBackendFails(localEngineProfileBuildeModeRelease); + }, skip: !platform.isMacOS); +}
diff --git a/packages/flutter_tools/test/ios/xcodeproj_test.dart b/packages/flutter_tools/test/ios/xcodeproj_test.dart index d80fbc1..874f897 100644 --- a/packages/flutter_tools/test/ios/xcodeproj_test.dart +++ b/packages/flutter_tools/test/ios/xcodeproj_test.dart
@@ -197,7 +197,7 @@ }); test('expected build configuration for non-flavored build is derived from BuildMode', () { expect(XcodeProjectInfo.expectedBuildConfigurationFor(BuildInfo.debug, 'Runner'), 'Debug'); - expect(XcodeProjectInfo.expectedBuildConfigurationFor(BuildInfo.profile, 'Runner'), 'Release'); + expect(XcodeProjectInfo.expectedBuildConfigurationFor(BuildInfo.profile, 'Runner'), 'Profile'); expect(XcodeProjectInfo.expectedBuildConfigurationFor(BuildInfo.release, 'Runner'), 'Release'); }); test('expected scheme for flavored build is the title-cased flavor', () { @@ -207,7 +207,7 @@ }); test('expected build configuration for flavored build is Mode-Flavor', () { expect(XcodeProjectInfo.expectedBuildConfigurationFor(const BuildInfo(BuildMode.debug, 'hello'), 'Hello'), 'Debug-Hello'); - expect(XcodeProjectInfo.expectedBuildConfigurationFor(const BuildInfo(BuildMode.profile, 'HELLO'), 'Hello'), 'Release-Hello'); + expect(XcodeProjectInfo.expectedBuildConfigurationFor(const BuildInfo(BuildMode.profile, 'HELLO'), 'Hello'), 'Profile-Hello'); expect(XcodeProjectInfo.expectedBuildConfigurationFor(const BuildInfo(BuildMode.release, 'Hello'), 'Hello'), 'Release-Hello'); }); test('scheme for default project is Runner', () { @@ -218,9 +218,9 @@ expect(info.schemeFor(const BuildInfo(BuildMode.debug, 'unknown')), isNull); }); test('build configuration for default project is matched against BuildMode', () { - final XcodeProjectInfo info = XcodeProjectInfo(<String>['Runner'], <String>['Debug', 'Release'], <String>['Runner']); + final XcodeProjectInfo info = XcodeProjectInfo(<String>['Runner'], <String>['Debug', 'Profile', 'Release'], <String>['Runner']); expect(info.buildConfigurationFor(BuildInfo.debug, 'Runner'), 'Debug'); - expect(info.buildConfigurationFor(BuildInfo.profile, 'Runner'), 'Release'); + expect(info.buildConfigurationFor(BuildInfo.profile, 'Runner'), 'Profile'); expect(info.buildConfigurationFor(BuildInfo.release, 'Runner'), 'Release'); }); test('scheme for project with custom schemes is matched against flavor', () { @@ -238,12 +238,12 @@ test('build configuration for project with custom schemes is matched against BuildMode and flavor', () { final XcodeProjectInfo info = XcodeProjectInfo( <String>['Runner'], - <String>['debug (free)', 'Debug paid', 'release - Free', 'Release-Paid'], + <String>['debug (free)', 'Debug paid', 'profile - Free', 'Profile-Paid', 'release - Free', 'Release-Paid'], <String>['Free', 'Paid'], ); expect(info.buildConfigurationFor(const BuildInfo(BuildMode.debug, 'free'), 'Free'), 'debug (free)'); expect(info.buildConfigurationFor(const BuildInfo(BuildMode.debug, 'Paid'), 'Paid'), 'Debug paid'); - expect(info.buildConfigurationFor(const BuildInfo(BuildMode.profile, 'FREE'), 'Free'), 'release - Free'); + expect(info.buildConfigurationFor(const BuildInfo(BuildMode.profile, 'FREE'), 'Free'), 'profile - Free'); expect(info.buildConfigurationFor(const BuildInfo(BuildMode.release, 'paid'), 'Paid'), 'Release-Paid'); }); test('build configuration for project with inconsistent naming is null', () {