From 7a7e2bb247c98456861de112cc10e57a559eef82 Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Thu, 12 Dec 2019 17:03:01 -0800 Subject: [PATCH] flutter run FULL_PRODUCT_NAME (#46838) --- dev/devicelab/bin/tasks/module_test_ios.dart | 10 +-- packages/flutter_tools/bin/xcode_backend.sh | 3 +- .../lib/src/application_package.dart | 11 ++- packages/flutter_tools/lib/src/ios/mac.dart | 2 +- .../flutter_tools/lib/src/ios/simulators.dart | 11 ++- packages/flutter_tools/lib/src/project.dart | 50 ++++++++---- .../Runner.xcodeproj/project.pbxproj.tmpl | 12 +-- .../{Runner.xcscheme => Runner.xcscheme.tmpl} | 8 +- .../Runner.xcodeproj/project.pbxproj.tmpl | 12 +-- .../{Runner.xcscheme => Runner.xcscheme.tmpl} | 8 +- .../{Runner.xcscheme => Runner.xcscheme.tmpl} | 8 +- .../app/ios.tmpl/Runner/Info.plist.tmpl | 2 +- .../Runner.tmpl/Info.plist.tmpl | 2 +- .../project.pbxproj.tmpl | 6 +- .../{Runner.xcscheme => Runner.xcscheme.tmpl} | 8 +- .../test/general.shard/ios/devices_test.dart | 80 +++++++++++++------ .../test/general.shard/ios/mac_test.dart | 2 +- .../general.shard/ios/simulators_test.dart | 6 +- .../test/general.shard/project_test.dart | 33 ++++++++ packages/flutter_tools/test/src/mocks.dart | 5 +- 20 files changed, 185 insertions(+), 94 deletions(-) rename packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/{Runner.xcscheme => Runner.xcscheme.tmpl} (93%) rename packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/{Runner.xcscheme => Runner.xcscheme.tmpl} (93%) rename packages/flutter_tools/templates/app/ios.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/{Runner.xcscheme => Runner.xcscheme.tmpl} (93%) rename packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/{Runner.xcscheme => Runner.xcscheme.tmpl} (93%) diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index 745614948a..a0a57c420a 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -44,7 +44,7 @@ Future main() async { 'build', 'ios', 'iphoneos', - 'Runner.app', + 'hello.app', )); if (!exists(ephemeralReleaseHostApp)) { @@ -84,7 +84,7 @@ Future main() async { 'build', 'ios', 'iphoneos', - 'Runner.app', + 'hello.app', )); if (!exists(ephemeralProfileHostApp)) { @@ -123,7 +123,7 @@ Future main() async { 'build', 'ios', 'iphonesimulator', - 'Runner.app', + 'hello.app', )); if (!exists(ephemeralDebugHostApp)) { @@ -178,7 +178,7 @@ Future main() async { 'build', 'ios', 'iphoneos', - 'Runner.app', + 'hello.app', ))); if (!ephemeralHostAppWithCocoaPodsBuilt) { @@ -223,7 +223,7 @@ Future main() async { 'build', 'ios', 'iphoneos', - 'Runner.app', + 'hello.app', ))); if (!editableHostAppBuilt) { diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh index 7f5bb868bb..b6a1de6ea8 100755 --- a/packages/flutter_tools/bin/xcode_backend.sh +++ b/packages/flutter_tools/bin/xcode_backend.sh @@ -341,7 +341,6 @@ ThinFramework() { local framework_dir="$1" shift - local plist_path="${framework_dir}/Info.plist" local executable="$(GetFrameworkExecutablePath "${framework_dir}")" LipoExecutable "${executable}" "$@" } @@ -374,7 +373,7 @@ EmbedFlutterFrameworks() { # Embed App.framework from Flutter into the app (after creating the Frameworks directory # if it doesn't already exist). - local xcode_frameworks_dir=${BUILT_PRODUCTS_DIR}"/"${PRODUCT_NAME}".app/Frameworks" + local xcode_frameworks_dir=${BUILT_PRODUCTS_DIR}"/"${FRAMEWORKS_FOLDER_PATH} RunCommand mkdir -p -- "${xcode_frameworks_dir}" RunCommand cp -Rv -- "${flutter_ios_out_folder}/App.framework" "${xcode_frameworks_dir}" diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart index cb761d0396..afe60c9b0c 100644 --- a/packages/flutter_tools/lib/src/application_package.dart +++ b/packages/flutter_tools/lib/src/application_package.dart @@ -358,18 +358,21 @@ abstract class IOSApp extends ApplicationPackage { } class BuildableIOSApp extends IOSApp { - BuildableIOSApp(this.project, String projectBundleId) + BuildableIOSApp(this.project, String projectBundleId, this._hostAppBundleName) : super(projectBundleId: projectBundleId); static Future fromProject(IosProject project) async { final String projectBundleId = await project.productBundleIdentifier; - return BuildableIOSApp(project, projectBundleId); + final String hostAppBundleName = await project.hostAppBundleName; + return BuildableIOSApp(project, projectBundleId, hostAppBundleName); } final IosProject project; + final String _hostAppBundleName; + @override - String get name => project.hostAppBundleName; + String get name => _hostAppBundleName; @override String get simulatorBundlePath => _buildAppPath('iphonesimulator'); @@ -378,7 +381,7 @@ class BuildableIOSApp extends IOSApp { String get deviceBundlePath => _buildAppPath('iphoneos'); String _buildAppPath(String type) { - return fs.path.join(getIosBuildDirectory(), type, name); + return fs.path.join(getIosBuildDirectory(), type, _hostAppBundleName); } } diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 3ac2ecba69..5499e3632b 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -736,7 +736,7 @@ bool upgradePbxProjWithFlutterAssets(IosProject project) { final Match match = oldAssets.firstMatch(line); if (match != null) { if (printedStatuses.add(match.group(1))) { - printStatus('Removing obsolete reference to ${match.group(1)} from ${project.hostAppBundleName}'); + printStatus('Removing obsolete reference to ${match.group(1)} from ${project.xcodeProject?.basename}'); } } else { buffer.writeln(line); diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index 7f24d01fda..fe6b6ad4ce 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart @@ -622,9 +622,8 @@ class _IOSSimulatorLogReader extends DeviceLogReader { } // Match the log prefix (in order to shorten it): - // * Xcode 8: Sep 13 15:28:51 cbracken-macpro localhost Runner[37195]: (Flutter) Observatory listening on http://127.0.0.1:57701/ - // * Xcode 9: 2017-09-13 15:26:57.228948-0700 localhost Runner[37195]: (Flutter) Observatory listening on http://127.0.0.1:57701/ - static final RegExp _mapRegex = RegExp(r'\S+ +\S+ +\S+ +(\S+ +)?(\S+)\[\d+\]\)?: (\(.*?\))? *(.*)$'); + // * Xcode 9: 2017-09-13 15:26:57.228948-0700 localhost My App[37195]: (Flutter) Observatory listening on http://127.0.0.1:57701/ + static final RegExp _mapRegex = RegExp(r'\S+ +\S+ +(?:\S+) (.+?(?=\[))\[\d+\]\)?: (\(.*?\))? *(.*)$'); // Jan 31 19:23:28 --- last message repeated 1 time --- static final RegExp _lastMessageSingleRegex = RegExp(r'\S+ +\S+ +\S+ --- last message repeated 1 time ---$'); @@ -635,9 +634,9 @@ class _IOSSimulatorLogReader extends DeviceLogReader { String _filterDeviceLine(String string) { final Match match = _mapRegex.matchAsPrefix(string); if (match != null) { - final String category = match.group(2); - final String tag = match.group(3); - final String content = match.group(4); + final String category = match.group(1); + final String tag = match.group(2); + final String content = match.group(3); // Filter out non-Flutter originated noise from the engine. if (_appName != null && category != _appName) { diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index bc9dba0d72..bce8622cd6 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -311,7 +311,7 @@ class IosProject implements XcodeBasedProject { static final RegExp _productBundleIdPattern = RegExp(r'''^\s*PRODUCT_BUNDLE_IDENTIFIER\s*=\s*(["']?)(.*?)\1;\s*$'''); static const String _productBundleIdVariable = r'$(PRODUCT_BUNDLE_IDENTIFIER)'; - static const String _hostAppBundleName = 'Runner'; + static const String _hostAppProjectName = 'Runner'; Directory get ephemeralDirectory => parent.directory.childDirectory('.ios'); Directory get _editableDirectory => parent.directory.childDirectory('ios'); @@ -332,9 +332,6 @@ class IosProject implements XcodeBasedProject { /// a Flutter module with an editable host app. Directory get _flutterLibRoot => isModule ? ephemeralDirectory : _editableDirectory; - /// The bundle name of the host app, `Runner.app`. - String get hostAppBundleName => '$_hostAppBundleName.app'; - /// True, if the parent Flutter project is a module project. bool get isModule => parent.isModule; @@ -357,19 +354,19 @@ class IosProject implements XcodeBasedProject { File get podManifestLock => hostAppRoot.childDirectory('Pods').childFile('Manifest.lock'); /// The 'Info.plist' file of the host app. - File get hostInfoPlist => hostAppRoot.childDirectory(_hostAppBundleName).childFile('Info.plist'); + File get hostInfoPlist => hostAppRoot.childDirectory(_hostAppProjectName).childFile('Info.plist'); @override Directory get symlinks => _flutterLibRoot.childDirectory('.symlinks'); @override - Directory get xcodeProject => hostAppRoot.childDirectory('$_hostAppBundleName.xcodeproj'); + Directory get xcodeProject => hostAppRoot.childDirectory('$_hostAppProjectName.xcodeproj'); @override File get xcodeProjectInfoFile => xcodeProject.childFile('project.pbxproj'); @override - Directory get xcodeWorkspace => hostAppRoot.childDirectory('$_hostAppBundleName.xcworkspace'); + Directory get xcodeWorkspace => hostAppRoot.childDirectory('$_hostAppProjectName.xcworkspace'); /// Xcode workspace shared data directory for the host app. Directory get xcodeWorkspaceSharedData => xcodeWorkspace.childDirectory('xcshareddata'); @@ -410,6 +407,26 @@ class IosProject implements XcodeBasedProject { return null; } + /// The bundle name of the host app, `My App.app`. + Future get hostAppBundleName async { + // The product name and bundle name are derived from the display name, which the user + // is instructed to change in Xcode as part of deploying to the App Store. + // https://flutter.dev/docs/deployment/ios#review-xcode-project-settings + // It may be expensive, but the only source of truth for the name is + // Xcode's interpretation of the build settings. + String productName; + if (xcode.xcodeProjectInterpreter.isInstalled) { + final Map xcodeBuildSettings = await buildSettings; + if (xcodeBuildSettings != null) { + productName = xcodeBuildSettings['FULL_PRODUCT_NAME']; + } + } + if (productName == null) { + printTrace('FULL_PRODUCT_NAME not present, defaulting to $_hostAppProjectName'); + } + return productName ?? '$_hostAppProjectName.app'; + } + @override Future get isSwift async => (await buildSettings)?.containsKey('SWIFT_VERSION') ?? false; @@ -421,11 +438,16 @@ class IosProject implements XcodeBasedProject { if (!xcode.xcodeProjectInterpreter.isInstalled) { return null; } - _buildSettings ??= await xcode.xcodeProjectInterpreter.getBuildSettings( + Map buildSettings = _buildSettings; + buildSettings ??= await xcode.xcodeProjectInterpreter.getBuildSettings( xcodeProject.path, - _hostAppBundleName, + _hostAppProjectName, ); - return _buildSettings; + if (buildSettings != null && buildSettings.isNotEmpty) { + // No timeouts, flakes, or errors. + _buildSettings = buildSettings; + } + return buildSettings; } Map _buildSettings; @@ -504,7 +526,7 @@ class IosProject implements XcodeBasedProject { Directory get pluginRegistrantHost { return isModule ? _flutterLibRoot.childDirectory('Flutter').childDirectory('FlutterPluginRegistrant') - : hostAppRoot.childDirectory(_hostAppBundleName); + : hostAppRoot.childDirectory(_hostAppProjectName); } void _overwriteFromTemplate(String path, Directory target) { @@ -765,7 +787,7 @@ class MacOSProject implements XcodeBasedProject { @override final FlutterProject parent; - static const String _hostAppBundleName = 'Runner'; + static const String _hostAppProjectName = 'Runner'; @override bool existsSync() => _macOSDirectory.existsSync(); @@ -809,13 +831,13 @@ class MacOSProject implements XcodeBasedProject { File get podManifestLock => _macOSDirectory.childDirectory('Pods').childFile('Manifest.lock'); @override - Directory get xcodeProject => _macOSDirectory.childDirectory('$_hostAppBundleName.xcodeproj'); + Directory get xcodeProject => _macOSDirectory.childDirectory('$_hostAppProjectName.xcodeproj'); @override File get xcodeProjectInfoFile => xcodeProject.childFile('project.pbxproj'); @override - Directory get xcodeWorkspace => _macOSDirectory.childDirectory('$_hostAppBundleName.xcworkspace'); + Directory get xcodeWorkspace => _macOSDirectory.childDirectory('$_hostAppProjectName.xcworkspace'); @override Directory get symlinks => ephemeralDirectory.childDirectory('.symlinks'); 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 2af713993f..a79e44909d 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 @@ -46,7 +46,7 @@ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146EE1CF9000F007C117D /* {{projectName}}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "{{projectName}}.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -93,7 +93,7 @@ 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, + 97C146EE1CF9000F007C117D /* {{projectName}}.app */, ); name = Products; sourceTree = ""; @@ -142,7 +142,7 @@ ); name = Runner; productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productReference = 97C146EE1CF9000F007C117D /* {{projectName}}.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -324,7 +324,7 @@ "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "{{projectName}}"; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; @@ -454,7 +454,7 @@ "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "{{projectName}}"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -477,7 +477,7 @@ "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "{{projectName}}"; VERSIONING_SYSTEM = "apple-generic"; }; name = 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.tmpl similarity index 93% rename from packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/flutter_tools/templates/app/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme.tmpl index a28140cfdb..cef7761b89 100644 --- 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.tmpl @@ -15,7 +15,7 @@ @@ -33,7 +33,7 @@ @@ -56,7 +56,7 @@ @@ -75,7 +75,7 @@ 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 39085ce2bf..3b35346a68 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 @@ -45,7 +45,7 @@ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146EE1CF9000F007C117D /* {{projectName}}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "{{projectName}}.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -90,7 +90,7 @@ 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, + 97C146EE1CF9000F007C117D /* {{projectName}}.app */, ); name = Products; sourceTree = ""; @@ -138,7 +138,7 @@ ); name = Runner; productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productReference = 97C146EE1CF9000F007C117D /* {{projectName}}.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -321,7 +321,7 @@ "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "{{projectName}}"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -455,7 +455,7 @@ "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "{{projectName}}"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -482,7 +482,7 @@ "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "{{projectName}}"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; 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.tmpl similarity index 93% rename from packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/flutter_tools/templates/app/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme.tmpl index a28140cfdb..cef7761b89 100644 --- 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.tmpl @@ -15,7 +15,7 @@ @@ -33,7 +33,7 @@ @@ -56,7 +56,7 @@ @@ -75,7 +75,7 @@ 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.tmpl similarity index 93% rename from packages/flutter_tools/templates/app/ios.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/flutter_tools/templates/app/ios.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme.tmpl index a28140cfdb..cef7761b89 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.tmpl @@ -15,7 +15,7 @@ @@ -33,7 +33,7 @@ @@ -56,7 +56,7 @@ @@ -75,7 +75,7 @@ diff --git a/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl b/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl index d9bd8c7b00..9e7e9ed5b3 100644 --- a/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl +++ b/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl @@ -11,7 +11,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - {{projectName}} + $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl index d9bd8c7b00..9e7e9ed5b3 100644 --- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl +++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl @@ -11,7 +11,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - {{projectName}} + $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 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 abbd314888..0531643aa3 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 @@ -319,7 +319,7 @@ "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "{{projectName}}"; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; @@ -447,7 +447,7 @@ "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "{{projectName}}"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -470,7 +470,7 @@ "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = {{iosIdentifier}}; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "{{projectName}}"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme.tmpl similarity index 93% rename from packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme rename to packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme.tmpl index 04a869b91e..ed7102cff4 100644 --- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme.tmpl @@ -15,7 +15,7 @@ @@ -33,7 +33,7 @@ @@ -56,7 +56,7 @@ @@ -75,7 +75,7 @@ diff --git a/packages/flutter_tools/test/general.shard/ios/devices_test.dart b/packages/flutter_tools/test/general.shard/ios/devices_test.dart index f5848913b0..270a02c6af 100644 --- a/packages/flutter_tools/test/general.shard/ios/devices_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/devices_test.dart @@ -20,6 +20,7 @@ import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/ios/mac.dart'; import 'package:flutter_tools/src/ios/ios_workflow.dart'; +import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/macos/xcode.dart'; import 'package:flutter_tools/src/mdns_discovery.dart'; import 'package:flutter_tools/src/project.dart'; @@ -575,23 +576,32 @@ void main() { Cache.flutterRoot = '../..'; final CreateCommand command = CreateCommand(); final CommandRunner runner = createTestCommandRunner(command); - await runner.run([ - 'create', - '--no-pub', - projectDir.path, - ]); + + FakeAsync().run((FakeAsync time) { + runner.run([ + 'create', + '--no-pub', + projectDir.path, + ]); + time.flushMicrotasks(); + time.elapse(const Duration(seconds: 65)); + }); if (additionalSetup != null) { additionalSetup(); } - final IOSApp app = await AbsoluteBuildableIOSApp.fromProject( - FlutterProject.fromDirectory(projectDir).ios); + final IOSApp app = AbsoluteBuildableIOSApp( + FlutterProject.fromDirectory(projectDir).ios, + 'io.flutter.flutter.app', + 'My Super Awesome App.app', + ); + final IOSDevice device = IOSDevice('123'); // Pre-create the expected build products. targetBuildDir.createSync(recursive: true); - projectDir.childDirectory('build/ios/iphoneos/Runner.app').createSync(recursive: true); + projectDir.childDirectory('build/ios/iphoneos/My Super Awesome App.app').createSync(recursive: true); final Completer completer = Completer(); FakeAsync().run((FakeAsync time) { @@ -620,6 +630,7 @@ void main() { IOSDeploy: () => mockIosDeploy, Platform: () => macPlatform, ProcessManager: () => mockProcessManager, + XcodeProjectInterpreter: () => FakeWithBuildSettingsXcodeProjectInterpreter(), }); } @@ -865,11 +876,11 @@ f577a7903cc54959be2e34bc4f7f80b7009efcf4 when(mockIMobileDevice.startLogger('123456')).thenAnswer((Invocation invocation) { final Process mockProcess = MockProcess( stdout: Stream>.fromIterable(>[''' -Runner(Flutter)[297] : A is for ari -Runner(libsystem_asl.dylib)[297] : libMobileGestalt MobileGestaltSupport.m:153: pid 123 (Runner) does not have sandbox access for frZQaeyWLUvLjeuEK43hmg and IS NOT appropriately entitled -Runner(libsystem_asl.dylib)[297] : libMobileGestalt MobileGestalt.c:550: no access to InverseDeviceID (see ) -Runner(Flutter)[297] : I is for ichigo -Runner(UIKit)[297] : E is for enpitsu" +My Super Awesome App(Flutter)[297] : A is for ari +My Super Awesome App(libsystem_asl.dylib)[297] : libMobileGestalt MobileGestaltSupport.m:153: pid 123 (Runner) does not have sandbox access for frZQaeyWLUvLjeuEK43hmg and IS NOT appropriately entitled +My Super Awesome App(libsystem_asl.dylib)[297] : libMobileGestalt MobileGestalt.c:550: no access to InverseDeviceID (see ) +My Super Awesome App(Flutter)[297] : I is for ichigo +My Super Awesome App(UIKit)[297] : E is for enpitsu" '''.codeUnits]) ); return Future.value(mockProcess); @@ -890,11 +901,11 @@ Runner(UIKit)[297] : E is for enpitsu" when(mockIMobileDevice.startLogger('123456')).thenAnswer((Invocation invocation) { final Process mockProcess = MockProcess( stdout: Stream>.fromIterable(>[''' -Runner(Flutter)[297] : This is a multi-line message, +My Super Awesome App(Flutter)[297] : This is a multi-line message, with another Flutter message following it. -Runner(Flutter)[297] : This is a multi-line message, +My Super Awesome App(Flutter)[297] : This is a multi-line message, with a non-Flutter log message following it. -Runner(libsystem_asl.dylib)[297] : libMobileGestalt +My Super Awesome App(libsystem_asl.dylib)[297] : libMobileGestalt '''.codeUnits]), ); return Future.value(mockProcess); @@ -963,13 +974,8 @@ flutter: } class AbsoluteBuildableIOSApp extends BuildableIOSApp { - AbsoluteBuildableIOSApp(IosProject project, String projectBundleId) : - super(project, projectBundleId); - - static Future fromProject(IosProject project) async { - final String projectBundleId = await project.productBundleIdentifier; - return AbsoluteBuildableIOSApp(project, projectBundleId); - } + AbsoluteBuildableIOSApp(IosProject project, String projectBundleId, String hostAppBundleName) : + super(project, projectBundleId, hostAppBundleName); @override String get deviceBundlePath => @@ -994,3 +1000,31 @@ class FakeIosDoctorProvider implements DoctorValidatorsProvider { return _workflows; } } + +class FakeWithBuildSettingsXcodeProjectInterpreter extends XcodeProjectInterpreter { + @override + bool get isInstalled => true; + + @override + String get versionText => 'Xcode 10.2'; + + @override + int get majorVersion => 10; + + @override + int get minorVersion => 2; + + @override + void cleanWorkspace(String workspacePath, String scheme) { + } + + @override + Future getInfo(String projectPath, {String projectFilename}) async { + return XcodeProjectInfo( + ['Runner'], + ['Debug', 'Release'], + ['Runner'], + ); + } +} + diff --git a/packages/flutter_tools/test/general.shard/ios/mac_test.dart b/packages/flutter_tools/test/general.shard/ios/mac_test.dart index 7a87dfa9ff..0c5f40fcbd 100644 --- a/packages/flutter_tools/test/general.shard/ios/mac_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/mac_test.dart @@ -435,7 +435,7 @@ Could not build the precompiled application for the device.''', final MockFile pbxprojFile = MockFile(); when(project.xcodeProjectInfoFile).thenReturn(pbxprojFile); - when(project.hostAppBundleName).thenReturn('UnitTestRunner.app'); + when(project.hostAppBundleName).thenAnswer((_) => Future.value('UnitTestRunner.app')); when(pbxprojFile.readAsLinesSync()) .thenAnswer((_) => flutterAssetPbxProjLines); when(pbxprojFile.existsSync()) diff --git a/packages/flutter_tools/test/general.shard/ios/simulators_test.dart b/packages/flutter_tools/test/general.shard/ios/simulators_test.dart index 7eb77ef3b0..9f8102db00 100644 --- a/packages/flutter_tools/test/general.shard/ios/simulators_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/simulators_test.dart @@ -344,9 +344,9 @@ void main() { when(mockProcess.stdout) .thenAnswer((Invocation invocation) { return Stream>.fromIterable(>[''' -2017-09-13 15:26:57.228948-0700 localhost Runner[37195]: (Flutter) Observatory listening on http://127.0.0.1:57701/ -2017-09-13 15:26:57.228948-0700 localhost Runner[37195]: (Flutter) )))))))))) -2017-09-13 15:26:57.228948-0700 localhost Runner[37195]: (Flutter) #0 Object.noSuchMethod (dart:core-patch/dart:core/object_patch.dart:46)''' +2017-09-13 15:26:57.228948-0700 localhost My Super Awesome App[37195]: (Flutter) Observatory listening on http://127.0.0.1:57701/ +2017-09-13 15:26:57.228948-0700 localhost My Super Awesome App[37195]: (Flutter) )))))))))) +2017-09-13 15:26:57.228948-0700 localhost My Super Awesome App[37195]: (Flutter) #0 Object.noSuchMethod (dart:core-patch/dart:core/object_patch.dart:46)''' .codeUnits]); }); when(mockProcess.stderr) diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index 845af31d77..b3420cef7f 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -416,6 +416,39 @@ apply plugin: 'kotlin-android' }); }); + group('application bundle name', () { + MemoryFileSystem fs; + MockXcodeProjectInterpreter mockXcodeProjectInterpreter; + setUp(() { + fs = MemoryFileSystem(); + mockXcodeProjectInterpreter = MockXcodeProjectInterpreter(); + }); + + testUsingContext('app product name defaults to Runner.app', () async { + final FlutterProject project = await someProject(); + expect(await project.ios.hostAppBundleName, 'Runner.app'); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + XcodeProjectInterpreter: () => mockXcodeProjectInterpreter + }); + + testUsingContext('app product name xcodebuild settings', () async { + final FlutterProject project = await someProject(); + when(mockXcodeProjectInterpreter.getBuildSettings(any, any)).thenAnswer((_) { + return Future>.value({ + 'FULL_PRODUCT_NAME': 'My App.app' + }); + }); + + expect(await project.ios.hostAppBundleName, 'My App.app'); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + XcodeProjectInterpreter: () => mockXcodeProjectInterpreter + }); + }); + group('organization names set', () { testInMemory('is empty, if project not created', () async { final FlutterProject project = await someProject(); diff --git a/packages/flutter_tools/test/src/mocks.dart b/packages/flutter_tools/test/src/mocks.dart index 539f8abd85..db191dc3db 100644 --- a/packages/flutter_tools/test/src/mocks.dart +++ b/packages/flutter_tools/test/src/mocks.dart @@ -40,7 +40,7 @@ class MockApplicationPackageStore extends ApplicationPackageStore { versionCode: 1, launchActivity: 'io.flutter.android.mock.MockActivity', ), - iOS: BuildableIOSApp(MockIosProject(), MockIosProject.bundleId), + iOS: BuildableIOSApp(MockIosProject(), MockIosProject.bundleId, MockIosProject.appBundleName), ); } @@ -519,12 +519,13 @@ class MockPollingDeviceDiscovery extends PollingDeviceDiscovery { class MockIosProject extends Mock implements IosProject { static const String bundleId = 'com.example.test'; + static const String appBundleName = 'My Super Awesome App.app'; @override Future get productBundleIdentifier async => bundleId; @override - String get hostAppBundleName => 'Runner.app'; + Future get hostAppBundleName async => appBundleName; } class MockAndroidDevice extends Mock implements AndroidDevice {