diff --git a/dev/devicelab/bin/tasks/ios_content_validation_test.dart b/dev/devicelab/bin/tasks/ios_content_validation_test.dart index 1f5efa2bfb69..eeaca8fb6c47 100644 --- a/dev/devicelab/bin/tasks/ios_content_validation_test.dart +++ b/dev/devicelab/bin/tasks/ios_content_validation_test.dart @@ -53,6 +53,11 @@ Future main() async { if (!output.contains('Warning: Launch image is set to the default placeholder. Replace with unique launch images.')) { throw TaskResult.failure('Must validate template launch image.'); } + + // The project is still using com.example as bundle identifier prefix. + if (!output.contains('Warning: Your application still contains the default "com.example" bundle identifier.')) { + throw TaskResult.failure('Must validate the default bundle identifier prefix'); + } }); final String archivePath = path.join( diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart index 7f7c53375485..f59d4991ef7a 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios.dart @@ -350,6 +350,10 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { if (xcodeProjectSettingsMap.values.any((String? element) => element == null)) { messageBuffer.writeln('\nYou must set up the missing settings.'); } + + if (xcodeProjectSettingsMap['Bundle Identifier']?.startsWith('com.example') ?? false) { + messageBuffer.writeln('\nWarning: Your application still contains the default "com.example" bundle identifier.'); + } } @override diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index b0fdfd7f8ec9..a628fba0dfab 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -740,13 +740,6 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode logger.printError("Also try selecting 'Product > Build' to fix the problem."); } - if (!issueDetected && _needUpdateSigningIdentifier(xcodeBuildExecution)) { - issueDetected = true; - logger.printError(''); - logger.printError('It appears that your application still contains the default signing identifier.'); - logger.printError("Try replacing 'com.example' with your signing id in Xcode:"); - logger.printError(' open ios/Runner.xcworkspace'); - } return issueDetected; } @@ -760,13 +753,6 @@ bool _missingDevelopmentTeam(XcodeBuildExecution? xcodeBuildExecution) { xcodeBuildExecution.buildSettings.containsKey); } -// Return `true` if the signing identifier needs to be updated. -bool _needUpdateSigningIdentifier(XcodeBuildExecution? xcodeBuildExecution) { - return xcodeBuildExecution != null - && xcodeBuildExecution.environmentType == EnvironmentType.physical - && (xcodeBuildExecution.buildSettings['PRODUCT_BUNDLE_IDENTIFIER']?.contains('com.example') ?? false); -} - // Detects and handles errors from stdout. // // As detecting issues in stdout is not usually accurate, this should be used as a fallback when other issue detecting methods failed. diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart index 2c869975960e..0fa7e3307397 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart @@ -565,73 +565,6 @@ void main() { XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), }); - testUsingContext('Default bundle identifier error should be hidden if there is another xcresult issue.', () async { - final BuildCommand command = BuildCommand( - androidSdk: FakeAndroidSdk(), - buildSystem: TestBuildSystem.all(BuildResult(success: true)), - fileSystem: MemoryFileSystem.test(), - logger: BufferLogger.test(), - osUtils: FakeOperatingSystemUtils(), - ); - - createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const ['build', 'ios', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); - expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); - expect(testLogger.errorText, isNot(contains('It appears that your application still contains the default signing identifier.'))); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list([ - xattrCommand, - setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), - setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - EnvironmentType: () => EnvironmentType.physical, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(productBundleIdentifier: 'com.example'), - }); - - testUsingContext('Show default bundle identifier error if there are no other errors.', () async { - final BuildCommand command = BuildCommand( - androidSdk: FakeAndroidSdk(), - buildSystem: TestBuildSystem.all(BuildResult(success: true)), - fileSystem: MemoryFileSystem.test(), - logger: BufferLogger.test(), - osUtils: FakeOperatingSystemUtils(), - ); - - createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const ['build', 'ios', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains('It appears that your application still contains the default signing identifier.')); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list([ - xattrCommand, - setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - setUpXCResultCommand(stdout: kSampleResultJsonNoIssues), - setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - EnvironmentType: () => EnvironmentType.physical, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(productBundleIdentifier: 'com.example'), - }); - - testUsingContext('Display xcresult issues with no provisioning profile.', () async { final BuildCommand command = BuildCommand( androidSdk: FakeAndroidSdk(), diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart index 1043411e2d3a..676ba54f355a 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart @@ -991,6 +991,84 @@ void main() { PlistParser: () => plistUtils, }); + testUsingContext( + 'Validate basic Xcode settings with default bundle identifier prefix', () async { + const String plistPath = 'build/ios/archive/Runner.xcarchive/Products/Applications/Runner.app/Info.plist'; + fakeProcessManager.addCommands([ + xattrCommand, + setUpFakeXcodeBuildHandler(onRun: () { + fileSystem.file(plistPath).createSync(recursive: true); + }), + exportArchiveCommand(exportOptionsPlist: _exportOptionsPlist), + ]); + + createMinimalMockProjectFiles(); + + plistUtils.fileContents[plistPath] = { + 'CFBundleIdentifier': 'com.example.my_app', + }; + + final BuildCommand command = BuildCommand( + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), + osUtils: FakeOperatingSystemUtils(), + ); + await createTestCommandRunner(command).run( + ['build', 'ipa', '--no-pub']); + + expect( + testLogger.statusText, + contains('Warning: Your application still contains the default "com.example" bundle identifier.') + ); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => fakeProcessManager, + Platform: () => macosPlatform, + XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), + PlistParser: () => plistUtils, + }); + + testUsingContext( + 'Validate basic Xcode settings with custom bundle identifier prefix', () async { + const String plistPath = 'build/ios/archive/Runner.xcarchive/Products/Applications/Runner.app/Info.plist'; + fakeProcessManager.addCommands([ + xattrCommand, + setUpFakeXcodeBuildHandler(onRun: () { + fileSystem.file(plistPath).createSync(recursive: true); + }), + exportArchiveCommand(exportOptionsPlist: _exportOptionsPlist), + ]); + + createMinimalMockProjectFiles(); + + plistUtils.fileContents[plistPath] = { + 'CFBundleIdentifier': 'com.my_company.my_app', + }; + + final BuildCommand command = BuildCommand( + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), + osUtils: FakeOperatingSystemUtils(), + ); + await createTestCommandRunner(command).run( + ['build', 'ipa', '--no-pub']); + + expect( + testLogger.statusText, + isNot(contains('Warning: Your application still contains the default "com.example" bundle identifier.')) + ); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => fakeProcessManager, + Platform: () => macosPlatform, + XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), + PlistParser: () => plistUtils, + }); + testUsingContext('Validate template app icons with conflicts', () async { const String projectIconContentsJsonPath = 'ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json';