diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index f854a92f021..811761ee9f1 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -228,30 +228,55 @@ class RunCommand extends RunCommandBase { Future> get usageValues async { String deviceType, deviceOsVersion; bool isEmulator; + bool anyAndroidDevices = false; + bool anyIOSDevices = false; if (devices == null || devices.isEmpty) { deviceType = 'none'; deviceOsVersion = 'none'; isEmulator = false; } else if (devices.length == 1) { - deviceType = getNameForTargetPlatform(await devices[0].targetPlatform); + final TargetPlatform platform = await devices[0].targetPlatform; + anyAndroidDevices = platform == TargetPlatform.android; + anyIOSDevices = platform == TargetPlatform.ios; + deviceType = getNameForTargetPlatform(platform); deviceOsVersion = await devices[0].sdkNameAndVersion; isEmulator = await devices[0].isLocalEmulator; } else { deviceType = 'multiple'; deviceOsVersion = 'multiple'; isEmulator = false; + for (Device device in devices) { + final TargetPlatform platform = await device.targetPlatform; + anyAndroidDevices = anyAndroidDevices || (platform == TargetPlatform.android); + anyIOSDevices = anyIOSDevices || (platform == TargetPlatform.ios); + if (anyAndroidDevices && anyIOSDevices) { + break; + } + } } - final String modeName = getBuildInfo().modeName; - final AndroidProject androidProject = FlutterProject.current().android; - final IosProject iosProject = FlutterProject.current().ios; - final List hostLanguage = [ - if (androidProject != null && androidProject.existsSync()) - if (androidProject.isKotlin) 'kotlin' else 'java', - if (iosProject != null && iosProject.exists) - if (await iosProject.isSwift) 'swift' else 'objc', - ]; + String androidEmbeddingVersion; + final List hostLanguage = []; + if (anyAndroidDevices) { + final AndroidProject androidProject = FlutterProject.current().android; + if (androidProject != null && androidProject.existsSync()) { + hostLanguage.add(androidProject.isKotlin ? 'kotlin' : 'java'); + androidEmbeddingVersion = androidProject.getEmbeddingVersion().toString().split('.').last; + } + } + if (anyIOSDevices) { + final IosProject iosProject = FlutterProject.current().ios; + if (iosProject != null && iosProject.exists) { + final Iterable swiftFiles = iosProject.hostAppRoot + .listSync(recursive: true, followLinks: false) + .whereType() + .where((File file) => fs.path.extension(file.path) == '.swift'); + hostLanguage.add(swiftFiles.isNotEmpty ? 'swift' : 'objc'); + } + } + + final String modeName = getBuildInfo().modeName; return { CustomDimensions.commandRunIsEmulator: '$isEmulator', CustomDimensions.commandRunTargetName: deviceType, @@ -259,7 +284,8 @@ class RunCommand extends RunCommandBase { CustomDimensions.commandRunModeName: modeName, CustomDimensions.commandRunProjectModule: '${FlutterProject.current().isModule}', CustomDimensions.commandRunProjectHostLanguage: hostLanguage.join(','), - CustomDimensions.commandRunAndroidEmbeddingVersion: androidProject.getEmbeddingVersion().toString().split('.').last, + if (androidEmbeddingVersion != null) + CustomDimensions.commandRunAndroidEmbeddingVersion: androidEmbeddingVersion, }; } diff --git a/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart b/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart index 01856b7d2af..5c673d660b7 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart @@ -36,7 +36,6 @@ Future processPodsIfNeeded(XcodeBasedProject xcodeProject, String buildDir final bool didPodInstall = await cocoaPods.processPods( xcodeProject: xcodeProject, engineDir: flutterFrameworkDir(buildMode), - isSwift: await xcodeProject.isSwift, dependenciesChanged: !fingerprinter.doesFingerprintMatch(), ); if (didPodInstall) { diff --git a/packages/flutter_tools/lib/src/macos/cocoapods.dart b/packages/flutter_tools/lib/src/macos/cocoapods.dart index 8fb1dd617ed..ca29dee7969 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapods.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapods.dart @@ -138,7 +138,6 @@ class CocoaPods { @required XcodeBasedProject xcodeProject, // For backward compatibility with previously created Podfile only. @required String engineDir, - bool isSwift = false, bool dependenciesChanged = true, }) async { if (!xcodeProject.podfile.existsSync()) { diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index bc9dba0d72f..2671a03df4e 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -292,9 +292,6 @@ abstract class XcodeBasedProject { /// The CocoaPods 'Manifest.lock'. File get podManifestLock; - /// True if the host app project is using Swift. - Future get isSwift; - /// Directory containing symlinks to pub cache plugins source generated on `pod install`. Directory get symlinks; } @@ -410,10 +407,6 @@ class IosProject implements XcodeBasedProject { return null; } - @override - Future get isSwift async => - (await buildSettings)?.containsKey('SWIFT_VERSION') ?? false; - /// The build settings for the host app of this project, as a detached map. /// /// Returns null, if iOS tooling is unavailable. @@ -820,9 +813,6 @@ class MacOSProject implements XcodeBasedProject { @override Directory get symlinks => ephemeralDirectory.childDirectory('.symlinks'); - @override - Future get isSwift async => true; - /// The file where the Xcode build will write the name of the built app. /// /// Ideally this will be replaced in the future with inspection of the Runner diff --git a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart index 83d98db11a5..9fb909c5033 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart @@ -237,6 +237,7 @@ void main() { when(mockDevice.isLocalEmulator).thenAnswer((Invocation invocation) => Future.value(false)); when(mockDevice.getLogReader(app: anyNamed('app'))).thenReturn(MockDeviceLogReader()); when(mockDevice.supportsFastStart).thenReturn(true); + when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation invocation) => Future.value('iOS 13')); // App fails to start because we're only interested in usage when(mockDevice.startApp( any, @@ -262,6 +263,15 @@ void main() { (Invocation invocation) => Future>.value([mockDevice]) ); + final Directory tempDir = fs.systemTempDirectory.createTempSync('flutter_run_test.'); + tempDir.childDirectory('ios').childFile('AppDelegate.swift').createSync(recursive: true); + tempDir.childFile('.packages').createSync(); + tempDir.childDirectory('lib').childFile('main.dart').createSync(recursive: true); + tempDir.childFile('pubspec.yaml') + ..createSync() + ..writeAsStringSync('# Hello, World'); + fs.currentDirectory = tempDir; + try { await createTestCommandRunner(command).run([ 'run', @@ -281,7 +291,14 @@ void main() { )).captured; expect(captures[0], 'run'); final Map parameters = captures[1] as Map; - expect(parameters['cd4'], 'ios'); + + expect(parameters[cdKey(CustomDimensions.commandRunIsEmulator)], 'false'); + expect(parameters[cdKey(CustomDimensions.commandRunTargetName)], 'ios'); + expect(parameters[cdKey(CustomDimensions.commandRunProjectHostLanguage)], 'swift'); + expect(parameters[cdKey(CustomDimensions.commandRunTargetOsVersion)], 'iOS 13'); + expect(parameters[cdKey(CustomDimensions.commandRunModeName)], 'debug'); + expect(parameters[cdKey(CustomDimensions.commandRunProjectModule)], 'false'); + expect(parameters.containsKey(cdKey(CustomDimensions.commandRunAndroidEmbeddingVersion)), false); }, overrides: { ApplicationPackageFactory: () => mockApplicationPackageFactory, Artifacts: () => mockArtifacts, diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index 845af31d774..c5b680561ba 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -304,19 +304,12 @@ void main() { testInMemory('default host app language', () async { final FlutterProject project = await someProject(); - expect(await project.ios.isSwift, isFalse); expect(project.android.isKotlin, isFalse); }); - testUsingContext('swift and kotlin host app language', () async { + testUsingContext('kotlin host app language', () async { final FlutterProject project = await someProject(); - when(mockXcodeProjectInterpreter.getBuildSettings(any, any)).thenAnswer( - (_) { - return Future>.value({ - 'SWIFT_VERSION': '5.0', - }); - }); addAndroidGradleFile(project.directory, gradleFileContent: () { return ''' @@ -324,7 +317,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' '''; }); - expect(await project.ios.isSwift, isTrue); expect(project.android.isKotlin, isTrue); }, overrides: { FileSystem: () => fs,