Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
e028d0f0
Unverified
Commit
e028d0f0
authored
Jun 28, 2021
by
Jenn Magder
Committed by
GitHub
Jun 28, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Split project.dart into CMake and Xcode projects (#85359)
parent
610ee89b
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
778 additions
and
754 deletions
+778
-754
utils.dart
packages/flutter_tools/lib/src/base/utils.dart
+16
-0
cmake.dart
packages/flutter_tools/lib/src/cmake.dart
+1
-1
cmake_project.dart
packages/flutter_tools/lib/src/cmake_project.dart
+175
-0
application_package.dart
packages/flutter_tools/lib/src/ios/application_package.dart
+1
-1
deployment_target_migration.dart
...s/lib/src/ios/migrations/deployment_target_migration.dart
+1
-1
project_base_configuration_migration.dart
.../ios/migrations/project_base_configuration_migration.dart
+1
-1
project_build_location_migration.dart
.../src/ios/migrations/project_build_location_migration.dart
+1
-1
remove_framework_link_and_embedding_migration.dart
...ations/remove_framework_link_and_embedding_migration.dart
+1
-1
xcode_build_system_migration.dart
.../lib/src/ios/migrations/xcode_build_system_migration.dart
+1
-1
application_package.dart
...ages/flutter_tools/lib/src/linux/application_package.dart
+1
-1
build_linux.dart
packages/flutter_tools/lib/src/linux/build_linux.dart
+1
-1
application_package.dart
...ages/flutter_tools/lib/src/macos/application_package.dart
+1
-1
cocoapods.dart
packages/flutter_tools/lib/src/macos/cocoapods.dart
+1
-1
remove_macos_framework_link_and_embedding_migration.dart
.../remove_macos_framework_link_and_embedding_migration.dart
+1
-1
cmake_custom_command_migration.dart
...ls/lib/src/migrations/cmake_custom_command_migration.dart
+1
-1
project.dart
packages/flutter_tools/lib/src/project.dart
+15
-735
application_package.dart
...es/flutter_tools/lib/src/windows/application_package.dart
+1
-1
build_windows.dart
packages/flutter_tools/lib/src/windows/build_windows.dart
+1
-1
install_manifest.dart
packages/flutter_tools/lib/src/windows/install_manifest.dart
+1
-1
xcode_project.dart
packages/flutter_tools/lib/src/xcode_project.dart
+553
-0
ios_project_migration_test.dart
...ls/test/general.shard/ios/ios_project_migration_test.dart
+1
-1
macos_project_migration_test.dart
...est/general.shard/macos/macos_project_migration_test.dart
+1
-1
cmake_project_migration_test.dart
...eneral.shard/migrations/cmake_project_migration_test.dart
+1
-1
No files found.
packages/flutter_tools/lib/src/base/utils.dart
View file @
e028d0f0
...
...
@@ -443,3 +443,19 @@ String interpolateString(String toInterpolate, Map<String, String> replacementVa
List
<
String
>
interpolateStringList
(
List
<
String
>
toInterpolate
,
Map
<
String
,
String
>
replacementValues
)
{
return
toInterpolate
.
map
((
String
s
)
=>
interpolateString
(
s
,
replacementValues
)).
toList
();
}
/// Returns the first line-based match for [regExp] in [file].
///
/// Assumes UTF8 encoding.
Match
?
firstMatchInFile
(
File
file
,
RegExp
regExp
)
{
if
(!
file
.
existsSync
())
{
return
null
;
}
for
(
final
String
line
in
file
.
readAsLinesSync
())
{
final
Match
?
match
=
regExp
.
firstMatch
(
line
);
if
(
match
!=
null
)
{
return
match
;
}
}
return
null
;
}
packages/flutter_tools/lib/src/cmake.dart
View file @
e028d0f0
...
...
@@ -3,7 +3,7 @@
// found in the LICENSE file.
import
'base/file_system.dart'
;
import
'project.dart'
;
import
'
cmake_
project.dart'
;
/// Extracts the `BINARY_NAME` from a project's CMake file.
///
...
...
packages/flutter_tools/lib/src/cmake_project.dart
0 → 100644
View file @
e028d0f0
// Copyright 2014 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:meta/meta.dart'
;
import
'package:xml/xml.dart'
;
import
'base/common.dart'
;
import
'base/file_system.dart'
;
import
'base/utils.dart'
;
import
'cmake.dart'
;
import
'platform_plugins.dart'
;
import
'project.dart'
;
/// Represents a CMake-based sub-project.
///
/// This defines interfaces common to Windows and Linux projects.
abstract
class
CmakeBasedProject
{
/// The parent of this project.
FlutterProject
get
parent
;
/// Whether the subproject (either Windows or Linux) exists in the Flutter project.
bool
existsSync
();
/// The native project CMake specification.
File
get
cmakeFile
;
/// Contains definitions for the Flutter library and the tool.
File
get
managedCmakeFile
;
/// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
/// the build.
File
get
generatedCmakeConfigFile
;
/// Included CMake with rules and variables for plugin builds.
File
get
generatedPluginCmakeFile
;
/// The directory to write plugin symlinks.
Directory
get
pluginSymlinkDirectory
;
}
/// The Windows sub project.
class
WindowsProject
extends
FlutterProjectPlatform
implements
CmakeBasedProject
{
WindowsProject
.
fromFlutter
(
this
.
parent
);
@override
final
FlutterProject
parent
;
@override
String
get
pluginConfigKey
=>
WindowsPlugin
.
kConfigKey
;
String
get
_childDirectory
=>
'windows'
;
@override
bool
existsSync
()
=>
_editableDirectory
.
existsSync
()
&&
cmakeFile
.
existsSync
();
@override
File
get
cmakeFile
=>
_editableDirectory
.
childFile
(
'CMakeLists.txt'
);
@override
File
get
managedCmakeFile
=>
managedDirectory
.
childFile
(
'CMakeLists.txt'
);
@override
File
get
generatedCmakeConfigFile
=>
ephemeralDirectory
.
childFile
(
'generated_config.cmake'
);
@override
File
get
generatedPluginCmakeFile
=>
managedDirectory
.
childFile
(
'generated_plugins.cmake'
);
@override
Directory
get
pluginSymlinkDirectory
=>
ephemeralDirectory
.
childDirectory
(
'.plugin_symlinks'
);
Directory
get
_editableDirectory
=>
parent
.
directory
.
childDirectory
(
_childDirectory
);
/// The directory in the project that is managed by Flutter. As much as
/// possible, files that are edited by Flutter tooling after initial project
/// creation should live here.
Directory
get
managedDirectory
=>
_editableDirectory
.
childDirectory
(
'flutter'
);
/// The subdirectory of [managedDirectory] that contains files that are
/// generated on the fly. All generated files that are not intended to be
/// checked in should live here.
Directory
get
ephemeralDirectory
=>
managedDirectory
.
childDirectory
(
'ephemeral'
);
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{}
}
/// The Windows UWP version of the Windows project.
class
WindowsUwpProject
extends
WindowsProject
{
WindowsUwpProject
.
fromFlutter
(
FlutterProject
parent
)
:
super
.
fromFlutter
(
parent
);
@override
String
get
_childDirectory
=>
'winuwp'
;
File
get
runnerCmakeFile
=>
_editableDirectory
.
childDirectory
(
'runner_uwp'
).
childFile
(
'CMakeLists.txt'
);
/// Eventually this will be used to check if the user's unstable project needs to be regenerated.
int
?
get
projectVersion
=>
int
.
tryParse
(
_editableDirectory
.
childFile
(
'project_version'
).
readAsStringSync
());
/// Retrieve the GUID of the UWP package.
String
?
get
packageGuid
=>
_packageGuid
??=
getCmakePackageGuid
(
runnerCmakeFile
);
String
?
_packageGuid
;
File
get
appManifest
=>
_editableDirectory
.
childDirectory
(
'runner_uwp'
).
childFile
(
'appxmanifest.in'
);
String
?
get
packageVersion
=>
_packageVersion
??=
parseAppVersion
(
this
);
String
?
_packageVersion
;
}
@visibleForTesting
String
?
parseAppVersion
(
WindowsUwpProject
project
)
{
final
File
appManifestFile
=
project
.
appManifest
;
if
(!
appManifestFile
.
existsSync
())
{
return
null
;
}
XmlDocument
document
;
try
{
document
=
XmlDocument
.
parse
(
appManifestFile
.
readAsStringSync
());
}
on
XmlParserException
{
throwToolExit
(
'Error parsing
$appManifestFile
. Please ensure that the appx manifest is a valid XML document and try again.'
);
}
for
(
final
XmlElement
metaData
in
document
.
findAllElements
(
'Identity'
))
{
return
metaData
.
getAttribute
(
'Version'
);
}
return
null
;
}
/// The Linux sub project.
class
LinuxProject
extends
FlutterProjectPlatform
implements
CmakeBasedProject
{
LinuxProject
.
fromFlutter
(
this
.
parent
);
@override
final
FlutterProject
parent
;
@override
String
get
pluginConfigKey
=>
LinuxPlugin
.
kConfigKey
;
static
final
RegExp
_applicationIdPattern
=
RegExp
(
r''
'^
\
s*set
\
s*
\
(
\
s*APPLICATION_ID
\
s*"(.*)"
\
s*
\
)
\
s*
$
'''
);
Directory
get
_editableDirectory
=>
parent
.
directory
.
childDirectory
(
'linux'
);
/// The directory in the project that is managed by Flutter. As much as
/// possible, files that are edited by Flutter tooling after initial project
/// creation should live here.
Directory
get
managedDirectory
=>
_editableDirectory
.
childDirectory
(
'flutter'
);
/// The subdirectory of [managedDirectory] that contains files that are
/// generated on the fly. All generated files that are not intended to be
/// checked in should live here.
Directory
get
ephemeralDirectory
=>
managedDirectory
.
childDirectory
(
'ephemeral'
);
@override
bool
existsSync
()
=>
_editableDirectory
.
existsSync
();
@override
File
get
cmakeFile
=>
_editableDirectory
.
childFile
(
'CMakeLists.txt'
);
@override
File
get
managedCmakeFile
=>
managedDirectory
.
childFile
(
'CMakeLists.txt'
);
@override
File
get
generatedCmakeConfigFile
=>
ephemeralDirectory
.
childFile
(
'generated_config.cmake'
);
@override
File
get
generatedPluginCmakeFile
=>
managedDirectory
.
childFile
(
'generated_plugins.cmake'
);
@override
Directory
get
pluginSymlinkDirectory
=>
ephemeralDirectory
.
childDirectory
(
'.plugin_symlinks'
);
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{}
String
?
get
applicationId
{
return
firstMatchInFile
(
cmakeFile
,
_applicationIdPattern
)?.
group
(
1
);
}
}
packages/flutter_tools/lib/src/ios/application_package.dart
View file @
e028d0f0
...
...
@@ -6,7 +6,7 @@ import '../application_package.dart';
import
'../base/file_system.dart'
;
import
'../build_info.dart'
;
import
'../globals_null_migrated.dart'
as
globals
;
import
'../project.dart'
;
import
'../
xcode_
project.dart'
;
import
'plist_parser.dart'
;
/// Tests whether a [Directory] is an iOS bundle directory.
...
...
packages/flutter_tools/lib/src/ios/migrations/deployment_target_migration.dart
View file @
e028d0f0
...
...
@@ -5,7 +5,7 @@
import
'../../base/file_system.dart'
;
import
'../../base/logger.dart'
;
import
'../../base/project_migrator.dart'
;
import
'../../project.dart'
;
import
'../../
xcode_
project.dart'
;
/// Update the minimum iOS deployment version to the minimum allowed by Xcode without causing a warning.
class
DeploymentTargetMigration
extends
ProjectMigrator
{
...
...
packages/flutter_tools/lib/src/ios/migrations/project_base_configuration_migration.dart
View file @
e028d0f0
...
...
@@ -5,7 +5,7 @@
import
'../../base/file_system.dart'
;
import
'../../base/logger.dart'
;
import
'../../base/project_migrator.dart'
;
import
'../../project.dart'
;
import
'../../
xcode_
project.dart'
;
// The Runner target should inherit its build configuration from Generated.xcconfig.
// However the top-level Runner project should not inherit any build configuration so
...
...
packages/flutter_tools/lib/src/ios/migrations/project_build_location_migration.dart
View file @
e028d0f0
...
...
@@ -5,7 +5,7 @@
import
'../../base/file_system.dart'
;
import
'../../base/logger.dart'
;
import
'../../base/project_migrator.dart'
;
import
'../../project.dart'
;
import
'../../
xcode_
project.dart'
;
// Update the xcodeproj build location. Legacy build location does not work with Swift Packages.
class
ProjectBuildLocationMigration
extends
ProjectMigrator
{
...
...
packages/flutter_tools/lib/src/ios/migrations/remove_framework_link_and_embedding_migration.dart
View file @
e028d0f0
...
...
@@ -6,8 +6,8 @@ import '../../base/common.dart';
import
'../../base/file_system.dart'
;
import
'../../base/logger.dart'
;
import
'../../base/project_migrator.dart'
;
import
'../../project.dart'
;
import
'../../reporting/reporting.dart'
;
import
'../../xcode_project.dart'
;
// Xcode 11.4 requires linked and embedded frameworks to contain all targeted architectures before build phases are run.
// This caused issues switching between a real device and simulator due to architecture mismatch.
...
...
packages/flutter_tools/lib/src/ios/migrations/xcode_build_system_migration.dart
View file @
e028d0f0
...
...
@@ -5,7 +5,7 @@
import
'../../base/file_system.dart'
;
import
'../../base/logger.dart'
;
import
'../../base/project_migrator.dart'
;
import
'../../project.dart'
;
import
'../../
xcode_
project.dart'
;
// Xcode legacy build system no longer supported by Xcode.
// Set in https://github.com/flutter/flutter/pull/21901/.
...
...
packages/flutter_tools/lib/src/linux/application_package.dart
View file @
e028d0f0
...
...
@@ -6,8 +6,8 @@ import '../application_package.dart';
import
'../base/file_system.dart'
;
import
'../build_info.dart'
;
import
'../cmake.dart'
;
import
'../cmake_project.dart'
;
import
'../globals_null_migrated.dart'
as
globals
;
import
'../project.dart'
;
abstract
class
LinuxApp
extends
ApplicationPackage
{
LinuxApp
({
required
String
projectBundleId
})
:
super
(
id:
projectBundleId
);
...
...
packages/flutter_tools/lib/src/linux/build_linux.dart
View file @
e028d0f0
...
...
@@ -12,11 +12,11 @@ import '../base/utils.dart';
import
'../build_info.dart'
;
import
'../cache.dart'
;
import
'../cmake.dart'
;
import
'../cmake_project.dart'
;
import
'../convert.dart'
;
import
'../flutter_plugins.dart'
;
import
'../globals_null_migrated.dart'
as
globals
;
import
'../migrations/cmake_custom_command_migration.dart'
;
import
'../project.dart'
;
// Matches the following error and warning patterns:
// - <file path>:<line>:<column>: (fatal) error: <error...>
...
...
packages/flutter_tools/lib/src/macos/application_package.dart
View file @
e028d0f0
...
...
@@ -13,7 +13,7 @@ import '../base/utils.dart';
import
'../build_info.dart'
;
import
'../globals_null_migrated.dart'
as
globals
;
import
'../ios/plist_parser.dart'
;
import
'../project.dart'
;
import
'../
xcode_
project.dart'
;
/// Tests whether a [FileSystemEntity] is an macOS bundle directory.
bool
_isBundleDirectory
(
FileSystemEntity
entity
)
=>
...
...
packages/flutter_tools/lib/src/macos/cocoapods.dart
View file @
e028d0f0
...
...
@@ -17,8 +17,8 @@ import '../base/version.dart';
import
'../build_info.dart'
;
import
'../cache.dart'
;
import
'../ios/xcodeproj.dart'
;
import
'../project.dart'
;
import
'../reporting/reporting.dart'
;
import
'../xcode_project.dart'
;
const
String
noCocoaPodsConsequence
=
'''
CocoaPods is used to retrieve the iOS and macOS platform side'
s
plugin
code
that
responds
to
your
plugin
usage
on
the
Dart
side
.
...
...
packages/flutter_tools/lib/src/macos/migrations/remove_macos_framework_link_and_embedding_migration.dart
View file @
e028d0f0
...
...
@@ -6,8 +6,8 @@ import '../../base/common.dart';
import
'../../base/file_system.dart'
;
import
'../../base/logger.dart'
;
import
'../../base/project_migrator.dart'
;
import
'../../project.dart'
;
import
'../../reporting/reporting.dart'
;
import
'../../xcode_project.dart'
;
// Remove the linking and embedding logic from the Xcode project to give the tool more control over these.
class
RemoveMacOSFrameworkLinkAndEmbeddingMigration
extends
ProjectMigrator
{
...
...
packages/flutter_tools/lib/src/migrations/cmake_custom_command_migration.dart
View file @
e028d0f0
...
...
@@ -5,7 +5,7 @@
import
'../base/file_system.dart'
;
import
'../base/logger.dart'
;
import
'../base/project_migrator.dart'
;
import
'../project.dart'
;
import
'../
cmake_
project.dart'
;
// CMake's add_custom_command() should use VERBATIM to handle escaping of spaces
// and special characters correctly.
...
...
packages/flutter_tools/lib/src/project.dart
View file @
e028d0f0
...
...
@@ -8,22 +8,23 @@ import 'package:yaml/yaml.dart';
import
'../src/convert.dart'
;
import
'android/gradle_utils.dart'
as
gradle
;
import
'artifacts.dart'
;
import
'base/common.dart'
;
import
'base/error_handling_io.dart'
;
import
'base/file_system.dart'
;
import
'base/logger.dart'
;
import
'b
uild_info
.dart'
;
import
'b
ase/utils
.dart'
;
import
'bundle.dart'
as
bundle
;
import
'cmake.dart'
;
import
'cmake
_project
.dart'
;
import
'features.dart'
;
import
'flutter_manifest.dart'
;
import
'flutter_plugins.dart'
;
import
'globals_null_migrated.dart'
as
globals
;
import
'ios/plist_parser.dart'
;
import
'ios/xcode_build_settings.dart'
as
xcode
;
import
'ios/xcodeproj.dart'
;
import
'platform_plugins.dart'
;
import
'template.dart'
;
import
'xcode_project.dart'
;
export
'cmake_project.dart'
;
export
'xcode_project.dart'
;
class
FlutterProjectFactory
{
FlutterProjectFactory
({
...
...
@@ -175,19 +176,19 @@ class FlutterProject {
/// The MacOS sub project of this project.
MacOSProject
?
_macos
;
MacOSProject
get
macos
=>
_macos
??=
MacOSProject
.
_
(
this
);
MacOSProject
get
macos
=>
_macos
??=
MacOSProject
.
fromFlutter
(
this
);
/// The Linux sub project of this project.
LinuxProject
?
_linux
;
LinuxProject
get
linux
=>
_linux
??=
LinuxProject
.
_
(
this
);
LinuxProject
get
linux
=>
_linux
??=
LinuxProject
.
fromFlutter
(
this
);
/// The Windows sub project of this project.
WindowsProject
?
_windows
;
WindowsProject
get
windows
=>
_windows
??=
WindowsProject
.
_
(
this
);
WindowsProject
get
windows
=>
_windows
??=
WindowsProject
.
fromFlutter
(
this
);
/// The Windows UWP sub project of this project.
WindowsUwpProject
?
_windowUwp
;
WindowsUwpProject
get
windowsUwp
=>
_windowUwp
??=
WindowsUwpProject
.
_
(
this
);
WindowsUwpProject
get
windowsUwp
=>
_windowUwp
??=
WindowsUwpProject
.
fromFlutter
(
this
);
/// The Fuchsia sub project of this project.
FuchsiaProject
?
_fuchsia
;
...
...
@@ -371,484 +372,6 @@ abstract class FlutterProjectPlatform {
bool
existsSync
();
}
/// Represents an Xcode-based sub-project.
///
/// This defines interfaces common to iOS and macOS projects.
abstract
class
XcodeBasedProject
{
/// The parent of this project.
FlutterProject
get
parent
;
/// Whether the subproject (either iOS or macOS) exists in the Flutter project.
bool
existsSync
();
/// The Xcode project (.xcodeproj directory) of the host app.
Directory
get
xcodeProject
;
/// The 'project.pbxproj' file of [xcodeProject].
File
get
xcodeProjectInfoFile
;
/// The Xcode workspace (.xcworkspace directory) of the host app.
Directory
get
xcodeWorkspace
;
/// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
/// the Xcode build.
File
get
generatedXcodePropertiesFile
;
/// The Flutter-managed Xcode config file for [mode].
File
xcodeConfigFor
(
String
mode
);
/// The script that exports environment variables needed for Flutter tools.
/// Can be run first in a Xcode Script build phase to make FLUTTER_ROOT,
/// LOCAL_ENGINE, and other Flutter variables available to any flutter
/// tooling (`flutter build`, etc) to convert into flags.
File
get
generatedEnvironmentVariableExportScript
;
/// The CocoaPods 'Podfile'.
File
get
podfile
;
/// The CocoaPods 'Podfile.lock'.
File
get
podfileLock
;
/// The CocoaPods 'Manifest.lock'.
File
get
podManifestLock
;
}
/// Represents a CMake-based sub-project.
///
/// This defines interfaces common to Windows and Linux projects.
abstract
class
CmakeBasedProject
{
/// The parent of this project.
FlutterProject
get
parent
;
/// Whether the subproject (either Windows or Linux) exists in the Flutter project.
bool
existsSync
();
/// The native project CMake specification.
File
get
cmakeFile
;
/// Contains definitions for the Flutter library and the tool.
File
get
managedCmakeFile
;
/// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
/// the build.
File
get
generatedCmakeConfigFile
;
/// Included CMake with rules and variables for plugin builds.
File
get
generatedPluginCmakeFile
;
/// The directory to write plugin symlinks.
Directory
get
pluginSymlinkDirectory
;
}
/// Represents the iOS sub-project of a Flutter project.
///
/// Instances will reflect the contents of the `ios/` sub-folder of
/// Flutter applications and the `.ios/` sub-folder of Flutter module projects.
class
IosProject
extends
FlutterProjectPlatform
implements
XcodeBasedProject
{
IosProject
.
fromFlutter
(
this
.
parent
);
@override
final
FlutterProject
parent
;
@override
String
get
pluginConfigKey
=>
IOSPlugin
.
kConfigKey
;
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 _hostAppProjectName = '
Runner
';
Directory get ephemeralModuleDirectory => parent.directory.childDirectory('
.
ios
');
Directory get _editableDirectory => parent.directory.childDirectory('
ios
');
/// This parent folder of `Runner.xcodeproj`.
Directory get hostAppRoot {
if (!isModule || _editableDirectory.existsSync()) {
return _editableDirectory;
}
return ephemeralModuleDirectory;
}
/// The root directory of the iOS wrapping of Flutter and plugins. This is the
/// parent of the `Flutter/` folder into which Flutter artifacts are written
/// during build.
///
/// This is the same as [hostAppRoot] except when the project is
/// a Flutter module with an editable host app.
Directory get _flutterLibRoot => isModule ? ephemeralModuleDirectory : _editableDirectory;
/// True, if the parent Flutter project is a module project.
bool get isModule => parent.isModule;
/// Whether the flutter application has an iOS project.
bool get exists => hostAppRoot.existsSync();
/// Put generated files here.
Directory get ephemeralDirectory => _flutterLibRoot.childDirectory('
Flutter
').childDirectory('
ephemeral
');
@override
File xcodeConfigFor(String mode) => _flutterLibRoot.childDirectory('
Flutter
').childFile('
$mode
.
xcconfig
');
@override
File get generatedEnvironmentVariableExportScript => _flutterLibRoot.childDirectory('
Flutter
').childFile('
flutter_export_environment
.
sh
');
@override
File get podfile => hostAppRoot.childFile('
Podfile
');
@override
File get podfileLock => hostAppRoot.childFile('
Podfile
.
lock
');
@override
File get podManifestLock => hostAppRoot.childDirectory('
Pods
').childFile('
Manifest
.
lock
');
/// The default '
Info
.
plist
' file of the host app. The developer can change this location in Xcode.
File get defaultHostInfoPlist => hostAppRoot.childDirectory(_hostAppProjectName).childFile('
Info
.
plist
');
File get appFrameworkInfoPlist => _flutterLibRoot.childDirectory('
Flutter
').childFile('
AppFrameworkInfo
.
plist
');
Directory get symlinks => _flutterLibRoot.childDirectory('
.
symlinks
');
@override
Directory get xcodeProject => hostAppRoot.childDirectory('
$_hostAppProjectName
.
xcodeproj
');
@override
File get xcodeProjectInfoFile => xcodeProject.childFile('
project
.
pbxproj
');
File get xcodeProjectWorkspaceData =>
xcodeProject
.childDirectory('
project
.
xcworkspace
')
.childFile('
contents
.
xcworkspacedata
');
@override
Directory get xcodeWorkspace => hostAppRoot.childDirectory('
$_hostAppProjectName
.
xcworkspace
');
/// Xcode workspace shared data directory for the host app.
Directory get xcodeWorkspaceSharedData => xcodeWorkspace.childDirectory('
xcshareddata
');
/// Xcode workspace shared workspace settings file for the host app.
File get xcodeWorkspaceSharedSettings => xcodeWorkspaceSharedData.childFile('
WorkspaceSettings
.
xcsettings
');
@override
bool existsSync() {
return parent.isModule || _editableDirectory.existsSync();
}
/// The product bundle identifier of the host app, or null if not set or if
/// iOS tooling needed to read it is not installed.
Future<String?> productBundleIdentifier(BuildInfo? buildInfo) async {
if (!existsSync()) {
return null;
}
return _productBundleIdentifier ??= await _parseProductBundleIdentifier(buildInfo);
}
String? _productBundleIdentifier;
Future<String?> _parseProductBundleIdentifier(BuildInfo? buildInfo) async {
String? fromPlist;
final File defaultInfoPlist = defaultHostInfoPlist;
// Users can change the location of the Info.plist.
// Try parsing the default, first.
if (defaultInfoPlist.existsSync()) {
try {
fromPlist = globals.plistParser.getValueFromFile(
defaultHostInfoPlist.path,
PlistParser.kCFBundleIdentifierKey,
);
} on FileNotFoundException {
// iOS tooling not found; likely not running OSX; let [fromPlist] be null
}
if (fromPlist != null && !fromPlist.contains(r'
$
')) {
// Info.plist has no build variables in product bundle ID.
return fromPlist;
}
}
final Map<String, String>? allBuildSettings = await buildSettingsForBuildInfo(buildInfo);
if (allBuildSettings != null) {
if (fromPlist != null) {
// Perform variable substitution using build settings.
return substituteXcodeVariables(fromPlist, allBuildSettings);
}
return allBuildSettings['
PRODUCT_BUNDLE_IDENTIFIER
'];
}
// On non-macOS platforms, parse the first PRODUCT_BUNDLE_IDENTIFIER from
// the project file. This can return the wrong bundle identifier if additional
// bundles have been added to the project and are found first, like frameworks
// or companion watchOS projects. However, on non-macOS platforms this is
// only used for display purposes and to regenerate organization names, so
// best-effort is probably fine.
final String? fromPbxproj = _firstMatchInFile(xcodeProjectInfoFile, _productBundleIdPattern)?.group(2);
if (fromPbxproj != null && (fromPlist == null || fromPlist == _productBundleIdVariable)) {
return fromPbxproj;
}
return null;
}
/// The bundle name of the host app, `My App.app`.
Future<String?> hostAppBundleName(BuildInfo buildInfo) async {
if (!existsSync()) {
return null;
}
return _hostAppBundleName ??= await _parseHostAppBundleName(buildInfo);
}
String? _hostAppBundleName;
Future<String> _parseHostAppBundleName(BuildInfo buildInfo) 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
// The only source of truth for the name is Xcode'
s
interpretation
of
the
build
settings
.
String
?
productName
;
if
(
globals
.
xcodeProjectInterpreter
?.
isInstalled
==
true
)
{
final
Map
<
String
,
String
>?
xcodeBuildSettings
=
await
buildSettingsForBuildInfo
(
buildInfo
);
if
(
xcodeBuildSettings
!=
null
)
{
productName
=
xcodeBuildSettings
[
'FULL_PRODUCT_NAME'
];
}
}
if
(
productName
==
null
)
{
globals
.
printTrace
(
'FULL_PRODUCT_NAME not present, defaulting to
$_hostAppProjectName
'
);
}
return
productName
??
'
$_hostAppProjectName
.app'
;
}
/// The build settings for the host app of this project, as a detached map.
///
/// Returns null, if iOS tooling is unavailable.
Future
<
Map
<
String
,
String
>?>
buildSettingsForBuildInfo
(
BuildInfo
?
buildInfo
,
{
EnvironmentType
environmentType
=
EnvironmentType
.
physical
})
async
{
if
(!
existsSync
())
{
return
null
;
}
final
XcodeProjectInfo
?
info
=
await
projectInfo
();
if
(
info
==
null
)
{
return
null
;
}
final
String
?
scheme
=
info
.
schemeFor
(
buildInfo
);
if
(
scheme
==
null
)
{
info
.
reportFlavorNotFoundAndExit
();
}
final
String
?
configuration
=
(
await
projectInfo
())?.
buildConfigurationFor
(
buildInfo
,
scheme
,
);
final
XcodeProjectBuildContext
buildContext
=
XcodeProjectBuildContext
(
environmentType:
environmentType
,
scheme:
scheme
,
configuration:
configuration
);
final
Map
<
String
,
String
>?
currentBuildSettings
=
_buildSettingsByBuildContext
[
buildContext
];
if
(
currentBuildSettings
==
null
)
{
final
Map
<
String
,
String
>?
calculatedBuildSettings
=
await
_xcodeProjectBuildSettings
(
buildContext
);
if
(
calculatedBuildSettings
!=
null
)
{
_buildSettingsByBuildContext
[
buildContext
]
=
calculatedBuildSettings
;
}
}
return
_buildSettingsByBuildContext
[
buildContext
];
}
final
Map
<
XcodeProjectBuildContext
,
Map
<
String
,
String
>>
_buildSettingsByBuildContext
=
<
XcodeProjectBuildContext
,
Map
<
String
,
String
>>{};
Future
<
XcodeProjectInfo
?>
projectInfo
()
async
{
final
XcodeProjectInterpreter
?
xcodeProjectInterpreter
=
globals
.
xcodeProjectInterpreter
;
if
(!
xcodeProject
.
existsSync
()
||
xcodeProjectInterpreter
==
null
||
!
xcodeProjectInterpreter
.
isInstalled
)
{
return
null
;
}
return
_projectInfo
??=
await
xcodeProjectInterpreter
.
getInfo
(
hostAppRoot
.
path
);
}
XcodeProjectInfo
?
_projectInfo
;
Future
<
Map
<
String
,
String
>?>
_xcodeProjectBuildSettings
(
XcodeProjectBuildContext
buildContext
)
async
{
final
XcodeProjectInterpreter
?
xcodeProjectInterpreter
=
globals
.
xcodeProjectInterpreter
;
if
(
xcodeProjectInterpreter
==
null
||
!
xcodeProjectInterpreter
.
isInstalled
)
{
return
null
;
}
final
Map
<
String
,
String
>
buildSettings
=
await
xcodeProjectInterpreter
.
getBuildSettings
(
xcodeProject
.
path
,
buildContext:
buildContext
,
);
if
(
buildSettings
!=
null
&&
buildSettings
.
isNotEmpty
)
{
// No timeouts, flakes, or errors.
return
buildSettings
;
}
return
null
;
}
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{
await
_regenerateFromTemplateIfNeeded
();
if
(!
_flutterLibRoot
.
existsSync
())
{
return
;
}
await
_updateGeneratedXcodeConfigIfNeeded
();
}
/// Check if one the [targets] of the project is a watchOS companion app target.
Future
<
bool
>
containsWatchCompanion
(
List
<
String
>
targets
,
BuildInfo
buildInfo
)
async
{
final
String
?
bundleIdentifier
=
await
productBundleIdentifier
(
buildInfo
);
// A bundle identifier is required for a companion app.
if
(
bundleIdentifier
==
null
)
{
return
false
;
}
for
(
final
String
target
in
targets
)
{
// Create Info.plist file of the target.
final
File
infoFile
=
hostAppRoot
.
childDirectory
(
target
).
childFile
(
'Info.plist'
);
// The Info.plist file of a target contains the key WKCompanionAppBundleIdentifier,
// if it is a watchOS companion app.
if
(
infoFile
.
existsSync
())
{
final
String
?
fromPlist
=
globals
.
plistParser
.
getValueFromFile
(
infoFile
.
path
,
'WKCompanionAppBundleIdentifier'
);
if
(
bundleIdentifier
==
fromPlist
)
{
return
true
;
}
// The key WKCompanionAppBundleIdentifier might contain an xcode variable
// that needs to be substituted before comparing it with bundle id
if
(
fromPlist
!=
null
&&
fromPlist
.
contains
(
r'$'
))
{
final
Map
<
String
,
String
>?
allBuildSettings
=
await
buildSettingsForBuildInfo
(
buildInfo
);
if
(
allBuildSettings
!=
null
)
{
final
String
substituedVariable
=
substituteXcodeVariables
(
fromPlist
,
allBuildSettings
);
if
(
substituedVariable
==
bundleIdentifier
)
{
return
true
;
}
}
}
}
}
return
false
;
}
Future
<
void
>
_updateGeneratedXcodeConfigIfNeeded
()
async
{
if
(
globals
.
cache
.
isOlderThanToolsStamp
(
generatedXcodePropertiesFile
))
{
await
xcode
.
updateGeneratedXcodeProperties
(
project:
parent
,
buildInfo:
BuildInfo
.
debug
,
targetOverride:
bundle
.
defaultMainPath
,
);
}
}
Future
<
void
>
_regenerateFromTemplateIfNeeded
()
async
{
if
(!
isModule
)
{
return
;
}
final
bool
pubspecChanged
=
globals
.
fsUtils
.
isOlderThanReference
(
entity:
ephemeralModuleDirectory
,
referenceFile:
parent
.
pubspecFile
,
);
final
bool
toolingChanged
=
globals
.
cache
.
isOlderThanToolsStamp
(
ephemeralModuleDirectory
);
if
(!
pubspecChanged
&&
!
toolingChanged
)
{
return
;
}
_deleteIfExistsSync
(
ephemeralModuleDirectory
);
await
_overwriteFromTemplate
(
globals
.
fs
.
path
.
join
(
'module'
,
'ios'
,
'library'
),
ephemeralModuleDirectory
,
);
// Add ephemeral host app, if a editable host app does not already exist.
if
(!
_editableDirectory
.
existsSync
())
{
await
_overwriteFromTemplate
(
globals
.
fs
.
path
.
join
(
'module'
,
'ios'
,
'host_app_ephemeral'
),
ephemeralModuleDirectory
,
);
if
(
hasPlugins
(
parent
))
{
await
_overwriteFromTemplate
(
globals
.
fs
.
path
.
join
(
'module'
,
'ios'
,
'host_app_ephemeral_cocoapods'
),
ephemeralModuleDirectory
,
);
}
// Use release mode so host project can link on bitcode variant.
_copyEngineArtifactToProject
(
BuildMode
.
release
,
EnvironmentType
.
physical
);
}
}
void
_copyEngineArtifactToProject
(
BuildMode
mode
,
EnvironmentType
environmentType
)
{
// Copy framework from engine cache. The actual build mode
// doesn't actually matter as it will be overwritten by xcode_backend.sh.
// However, cocoapods will run before that script and requires something
// to be in this location.
final
Directory
framework
=
globals
.
fs
.
directory
(
globals
.
artifacts
?.
getArtifactPath
(
Artifact
.
flutterXcframework
,
platform:
TargetPlatform
.
ios
,
mode:
mode
,
environmentType:
environmentType
,
)
);
if
(
framework
.
existsSync
())
{
copyDirectory
(
framework
,
engineCopyDirectory
.
childDirectory
(
'Flutter.xcframework'
),
);
}
}
@override
File
get
generatedXcodePropertiesFile
=>
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childFile
(
'Generated.xcconfig'
);
/// No longer compiled to this location.
///
/// Used only for "flutter clean" to remove old references.
Directory
get
deprecatedCompiledDartFramework
=>
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childDirectory
(
'App.framework'
);
/// No longer copied to this location.
///
/// Used only for "flutter clean" to remove old references.
Directory
get
deprecatedProjectFlutterFramework
=>
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childDirectory
(
'Flutter.framework'
);
/// Used only for "flutter clean" to remove old references.
File
get
flutterPodspec
=>
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childFile
(
'Flutter.podspec'
);
Directory
get
pluginRegistrantHost
{
return
isModule
?
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childDirectory
(
'FlutterPluginRegistrant'
)
:
hostAppRoot
.
childDirectory
(
_hostAppProjectName
);
}
File
get
pluginRegistrantHeader
{
final
Directory
registryDirectory
=
isModule
?
pluginRegistrantHost
.
childDirectory
(
'Classes'
)
:
pluginRegistrantHost
;
return
registryDirectory
.
childFile
(
'GeneratedPluginRegistrant.h'
);
}
File
get
pluginRegistrantImplementation
{
final
Directory
registryDirectory
=
isModule
?
pluginRegistrantHost
.
childDirectory
(
'Classes'
)
:
pluginRegistrantHost
;
return
registryDirectory
.
childFile
(
'GeneratedPluginRegistrant.m'
);
}
Directory
get
engineCopyDirectory
{
return
isModule
?
ephemeralModuleDirectory
.
childDirectory
(
'Flutter'
).
childDirectory
(
'engine'
)
:
hostAppRoot
.
childDirectory
(
'Flutter'
);
}
Future
<
void
>
_overwriteFromTemplate
(
String
path
,
Directory
target
)
async
{
final
Template
template
=
await
Template
.
fromName
(
path
,
fileSystem:
globals
.
fs
,
templateManifest:
null
,
logger:
globals
.
logger
,
templateRenderer:
globals
.
templateRenderer
,
);
final
String
iosBundleIdentifier
=
parent
.
manifest
.
iosBundleIdentifier
??
'com.example.
${parent.manifest.appName}
'
;
template
.
render
(
target
,
<
String
,
Object
>{
'ios'
:
true
,
'projectName'
:
parent
.
manifest
.
appName
,
'iosIdentifier'
:
iosBundleIdentifier
,
},
printStatusWhenWriting:
false
,
overwriteExisting:
true
,
);
}
}
/// Represents the Android sub-project of a Flutter project.
///
/// Instances will reflect the contents of the `android/` sub-folder of
...
...
@@ -918,7 +441,7 @@ class AndroidProject extends FlutterProjectPlatform {
/// True, if the app project is using Kotlin.
bool
get
isKotlin
{
final
File
gradleFile
=
hostAppGradleRoot
.
childDirectory
(
'app'
).
childFile
(
'build.gradle'
);
return
_
firstMatchInFile
(
gradleFile
,
_kotlinPluginPattern
)
!=
null
;
return
firstMatchInFile
(
gradleFile
,
_kotlinPluginPattern
)
!=
null
;
}
File
get
appManifestFile
{
...
...
@@ -945,12 +468,12 @@ class AndroidProject extends FlutterProjectPlatform {
String
?
get
applicationId
{
final
File
gradleFile
=
hostAppGradleRoot
.
childDirectory
(
'app'
).
childFile
(
'build.gradle'
);
return
_
firstMatchInFile
(
gradleFile
,
_applicationIdPattern
)?.
group
(
1
);
return
firstMatchInFile
(
gradleFile
,
_applicationIdPattern
)?.
group
(
1
);
}
String
?
get
group
{
final
File
gradleFile
=
hostAppGradleRoot
.
childFile
(
'build.gradle'
);
return
_
firstMatchInFile
(
gradleFile
,
_groupPattern
)?.
group
(
1
);
return
firstMatchInFile
(
gradleFile
,
_groupPattern
)?.
group
(
1
);
}
/// The build directory where the Android artifacts are placed.
...
...
@@ -1002,7 +525,7 @@ to migrate your project.
Directory
get
pluginRegistrantHost
=>
_flutterLibGradleRoot
.
childDirectory
(
isModule
?
'Flutter'
:
'app'
);
Future
<
void
>
_regenerateLibrary
()
async
{
_deleteIfExistsSync
(
ephemeralDirectory
);
ErrorHandlingFileSystem
.
deleteIfExists
(
ephemeralDirectory
,
recursive:
true
);
await
_overwriteFromTemplate
(
globals
.
fs
.
path
.
join
(
'module'
,
'android'
,
...
...
@@ -1107,249 +630,6 @@ class WebProject extends FlutterProjectPlatform {
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{}
}
/// Deletes [directory] with all content.
void
_deleteIfExistsSync
(
Directory
directory
)
{
if
(
directory
.
existsSync
())
{
directory
.
deleteSync
(
recursive:
true
);
}
}
/// Returns the first line-based match for [regExp] in [file].
///
/// Assumes UTF8 encoding.
Match
?
_firstMatchInFile
(
File
file
,
RegExp
regExp
)
{
if
(!
file
.
existsSync
())
{
return
null
;
}
for
(
final
String
line
in
file
.
readAsLinesSync
())
{
final
Match
?
match
=
regExp
.
firstMatch
(
line
);
if
(
match
!=
null
)
{
return
match
;
}
}
return
null
;
}
/// The macOS sub project.
class
MacOSProject
extends
FlutterProjectPlatform
implements
XcodeBasedProject
{
MacOSProject
.
_
(
this
.
parent
);
@override
final
FlutterProject
parent
;
@override
String
get
pluginConfigKey
=>
MacOSPlugin
.
kConfigKey
;
static
const
String
_hostAppProjectName
=
'Runner'
;
@override
bool
existsSync
()
=>
_macOSDirectory
.
existsSync
();
Directory
get
_macOSDirectory
=>
parent
.
directory
.
childDirectory
(
'macos'
);
/// The directory in the project that is managed by Flutter. As much as
/// possible, files that are edited by Flutter tooling after initial project
/// creation should live here.
Directory
get
managedDirectory
=>
_macOSDirectory
.
childDirectory
(
'Flutter'
);
/// The subdirectory of [managedDirectory] that contains files that are
/// generated on the fly. All generated files that are not intended to be
/// checked in should live here.
Directory
get
ephemeralDirectory
=>
managedDirectory
.
childDirectory
(
'ephemeral'
);
/// The xcfilelist used to track the inputs for the Flutter script phase in
/// the Xcode build.
File
get
inputFileList
=>
ephemeralDirectory
.
childFile
(
'FlutterInputs.xcfilelist'
);
/// The xcfilelist used to track the outputs for the Flutter script phase in
/// the Xcode build.
File
get
outputFileList
=>
ephemeralDirectory
.
childFile
(
'FlutterOutputs.xcfilelist'
);
@override
File
get
generatedXcodePropertiesFile
=>
ephemeralDirectory
.
childFile
(
'Flutter-Generated.xcconfig'
);
@override
File
xcodeConfigFor
(
String
mode
)
=>
managedDirectory
.
childFile
(
'Flutter-
$mode
.xcconfig'
);
@override
File
get
generatedEnvironmentVariableExportScript
=>
ephemeralDirectory
.
childFile
(
'flutter_export_environment.sh'
);
@override
File
get
podfile
=>
_macOSDirectory
.
childFile
(
'Podfile'
);
@override
File
get
podfileLock
=>
_macOSDirectory
.
childFile
(
'Podfile.lock'
);
@override
File
get
podManifestLock
=>
_macOSDirectory
.
childDirectory
(
'Pods'
).
childFile
(
'Manifest.lock'
);
@override
Directory
get
xcodeProject
=>
_macOSDirectory
.
childDirectory
(
'
$_hostAppProjectName
.xcodeproj'
);
@override
File
get
xcodeProjectInfoFile
=>
xcodeProject
.
childFile
(
'project.pbxproj'
);
@override
Directory
get
xcodeWorkspace
=>
_macOSDirectory
.
childDirectory
(
'
$_hostAppProjectName
.xcworkspace'
);
/// 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
/// scheme's target.
File
get
nameFile
=>
ephemeralDirectory
.
childFile
(
'.app_filename'
);
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{
// TODO(stuartmorgan): Add create-from-template logic here.
await
_updateGeneratedXcodeConfigIfNeeded
();
}
Future
<
void
>
_updateGeneratedXcodeConfigIfNeeded
()
async
{
if
(
globals
.
cache
.
isOlderThanToolsStamp
(
generatedXcodePropertiesFile
))
{
await
xcode
.
updateGeneratedXcodeProperties
(
project:
parent
,
buildInfo:
BuildInfo
.
debug
,
useMacOSConfig:
true
,
);
}
}
}
/// The Windows sub project.
class
WindowsProject
extends
FlutterProjectPlatform
implements
CmakeBasedProject
{
WindowsProject
.
_
(
this
.
parent
);
@override
final
FlutterProject
parent
;
@override
String
get
pluginConfigKey
=>
WindowsPlugin
.
kConfigKey
;
String
get
_childDirectory
=>
'windows'
;
@override
bool
existsSync
()
=>
_editableDirectory
.
existsSync
()
&&
cmakeFile
.
existsSync
();
@override
File
get
cmakeFile
=>
_editableDirectory
.
childFile
(
'CMakeLists.txt'
);
@override
File
get
managedCmakeFile
=>
managedDirectory
.
childFile
(
'CMakeLists.txt'
);
@override
File
get
generatedCmakeConfigFile
=>
ephemeralDirectory
.
childFile
(
'generated_config.cmake'
);
@override
File
get
generatedPluginCmakeFile
=>
managedDirectory
.
childFile
(
'generated_plugins.cmake'
);
@override
Directory
get
pluginSymlinkDirectory
=>
ephemeralDirectory
.
childDirectory
(
'.plugin_symlinks'
);
Directory
get
_editableDirectory
=>
parent
.
directory
.
childDirectory
(
_childDirectory
);
/// The directory in the project that is managed by Flutter. As much as
/// possible, files that are edited by Flutter tooling after initial project
/// creation should live here.
Directory
get
managedDirectory
=>
_editableDirectory
.
childDirectory
(
'flutter'
);
/// The subdirectory of [managedDirectory] that contains files that are
/// generated on the fly. All generated files that are not intended to be
/// checked in should live here.
Directory
get
ephemeralDirectory
=>
managedDirectory
.
childDirectory
(
'ephemeral'
);
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{}
}
/// The Windows UWP version of the Windows project.
class
WindowsUwpProject
extends
WindowsProject
{
WindowsUwpProject
.
_
(
FlutterProject
parent
)
:
super
.
_
(
parent
);
@override
String
get
_childDirectory
=>
'winuwp'
;
File
get
runnerCmakeFile
=>
_editableDirectory
.
childDirectory
(
'runner_uwp'
).
childFile
(
'CMakeLists.txt'
);
/// Eventually this will be used to check if the user's unstable project needs to be regenerated.
int
?
get
projectVersion
=>
int
.
tryParse
(
_editableDirectory
.
childFile
(
'project_version'
).
readAsStringSync
());
/// Retrieve the GUID of the UWP package.
String
?
get
packageGuid
=>
_packageGuid
??=
getCmakePackageGuid
(
runnerCmakeFile
);
String
?
_packageGuid
;
File
get
appManifest
=>
_editableDirectory
.
childDirectory
(
'runner_uwp'
).
childFile
(
'appxmanifest.in'
);
String
?
get
packageVersion
=>
_packageVersion
??=
parseAppVersion
(
this
);
String
?
_packageVersion
;
}
@visibleForTesting
String
?
parseAppVersion
(
WindowsUwpProject
project
)
{
final
File
appManifestFile
=
project
.
appManifest
;
if
(!
appManifestFile
.
existsSync
())
{
return
null
;
}
XmlDocument
document
;
try
{
document
=
XmlDocument
.
parse
(
appManifestFile
.
readAsStringSync
());
}
on
XmlParserException
{
throwToolExit
(
'Error parsing
$appManifestFile
. Please ensure that the appx manifest is a valid XML document and try again.'
);
}
for
(
final
XmlElement
metaData
in
document
.
findAllElements
(
'Identity'
))
{
return
metaData
.
getAttribute
(
'Version'
);
}
return
null
;
}
/// The Linux sub project.
class
LinuxProject
extends
FlutterProjectPlatform
implements
CmakeBasedProject
{
LinuxProject
.
_
(
this
.
parent
);
@override
final
FlutterProject
parent
;
@override
String
get
pluginConfigKey
=>
LinuxPlugin
.
kConfigKey
;
static
final
RegExp
_applicationIdPattern
=
RegExp
(
r''
'^
\
s*set
\
s*
\
(
\
s*APPLICATION_ID
\
s*"(.*)"
\
s*
\
)
\
s*
$
'''
);
Directory
get
_editableDirectory
=>
parent
.
directory
.
childDirectory
(
'linux'
);
/// The directory in the project that is managed by Flutter. As much as
/// possible, files that are edited by Flutter tooling after initial project
/// creation should live here.
Directory
get
managedDirectory
=>
_editableDirectory
.
childDirectory
(
'flutter'
);
/// The subdirectory of [managedDirectory] that contains files that are
/// generated on the fly. All generated files that are not intended to be
/// checked in should live here.
Directory
get
ephemeralDirectory
=>
managedDirectory
.
childDirectory
(
'ephemeral'
);
@override
bool
existsSync
()
=>
_editableDirectory
.
existsSync
();
@override
File
get
cmakeFile
=>
_editableDirectory
.
childFile
(
'CMakeLists.txt'
);
@override
File
get
managedCmakeFile
=>
managedDirectory
.
childFile
(
'CMakeLists.txt'
);
@override
File
get
generatedCmakeConfigFile
=>
ephemeralDirectory
.
childFile
(
'generated_config.cmake'
);
@override
File
get
generatedPluginCmakeFile
=>
managedDirectory
.
childFile
(
'generated_plugins.cmake'
);
@override
Directory
get
pluginSymlinkDirectory
=>
ephemeralDirectory
.
childDirectory
(
'.plugin_symlinks'
);
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{}
String
?
get
applicationId
{
return
_firstMatchInFile
(
cmakeFile
,
_applicationIdPattern
)?.
group
(
1
);
}
}
/// The Fuchsia sub project.
class
FuchsiaProject
{
FuchsiaProject
.
_
(
this
.
project
);
...
...
packages/flutter_tools/lib/src/windows/application_package.dart
View file @
e028d0f0
...
...
@@ -11,8 +11,8 @@ import '../base/file_system.dart';
import
'../base/utils.dart'
;
import
'../build_info.dart'
;
import
'../cmake.dart'
;
import
'../cmake_project.dart'
;
import
'../globals_null_migrated.dart'
as
globals
;
import
'../project.dart'
;
abstract
class
WindowsApp
extends
ApplicationPackage
{
WindowsApp
({
@required
String
projectBundleId
})
:
super
(
id:
projectBundleId
);
...
...
packages/flutter_tools/lib/src/windows/build_windows.dart
View file @
e028d0f0
...
...
@@ -14,11 +14,11 @@ import '../base/utils.dart';
import
'../build_info.dart'
;
import
'../cache.dart'
;
import
'../cmake.dart'
;
import
'../cmake_project.dart'
;
import
'../convert.dart'
;
import
'../flutter_plugins.dart'
;
import
'../globals_null_migrated.dart'
as
globals
;
import
'../migrations/cmake_custom_command_migration.dart'
;
import
'../project.dart'
;
import
'install_manifest.dart'
;
import
'visual_studio.dart'
;
...
...
packages/flutter_tools/lib/src/windows/install_manifest.dart
View file @
e028d0f0
...
...
@@ -12,7 +12,7 @@ import '../base/file_system.dart';
import
'../base/logger.dart'
;
import
'../base/platform.dart'
;
import
'../build_info.dart'
;
import
'../project.dart'
;
import
'../
cmake_
project.dart'
;
/// Generate an install manifest that is required for CMAKE on UWP projects.
Future
<
void
>
createManifest
({
...
...
packages/flutter_tools/lib/src/xcode_project.dart
0 → 100644
View file @
e028d0f0
// Copyright 2014 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
'artifacts.dart'
;
import
'base/error_handling_io.dart'
;
import
'base/file_system.dart'
;
import
'base/utils.dart'
;
import
'build_info.dart'
;
import
'bundle.dart'
as
bundle
;
import
'flutter_plugins.dart'
;
import
'globals_null_migrated.dart'
as
globals
;
import
'ios/plist_parser.dart'
;
import
'ios/xcode_build_settings.dart'
as
xcode
;
import
'ios/xcodeproj.dart'
;
import
'platform_plugins.dart'
;
import
'project.dart'
;
import
'template.dart'
;
/// Represents an Xcode-based sub-project.
///
/// This defines interfaces common to iOS and macOS projects.
abstract
class
XcodeBasedProject
{
/// The parent of this project.
FlutterProject
get
parent
;
/// Whether the subproject (either iOS or macOS) exists in the Flutter project.
bool
existsSync
();
/// The Xcode project (.xcodeproj directory) of the host app.
Directory
get
xcodeProject
;
/// The 'project.pbxproj' file of [xcodeProject].
File
get
xcodeProjectInfoFile
;
/// The Xcode workspace (.xcworkspace directory) of the host app.
Directory
get
xcodeWorkspace
;
/// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
/// the Xcode build.
File
get
generatedXcodePropertiesFile
;
/// The Flutter-managed Xcode config file for [mode].
File
xcodeConfigFor
(
String
mode
);
/// The script that exports environment variables needed for Flutter tools.
/// Can be run first in a Xcode Script build phase to make FLUTTER_ROOT,
/// LOCAL_ENGINE, and other Flutter variables available to any flutter
/// tooling (`flutter build`, etc) to convert into flags.
File
get
generatedEnvironmentVariableExportScript
;
/// The CocoaPods 'Podfile'.
File
get
podfile
;
/// The CocoaPods 'Podfile.lock'.
File
get
podfileLock
;
/// The CocoaPods 'Manifest.lock'.
File
get
podManifestLock
;
}
/// Represents the iOS sub-project of a Flutter project.
///
/// Instances will reflect the contents of the `ios/` sub-folder of
/// Flutter applications and the `.ios/` sub-folder of Flutter module projects.
class
IosProject
extends
FlutterProjectPlatform
implements
XcodeBasedProject
{
IosProject
.
fromFlutter
(
this
.
parent
);
@override
final
FlutterProject
parent
;
@override
String
get
pluginConfigKey
=>
IOSPlugin
.
kConfigKey
;
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 _hostAppProjectName = '
Runner
';
Directory get ephemeralModuleDirectory => parent.directory.childDirectory('
.
ios
');
Directory get _editableDirectory => parent.directory.childDirectory('
ios
');
/// This parent folder of `Runner.xcodeproj`.
Directory get hostAppRoot {
if (!isModule || _editableDirectory.existsSync()) {
return _editableDirectory;
}
return ephemeralModuleDirectory;
}
/// The root directory of the iOS wrapping of Flutter and plugins. This is the
/// parent of the `Flutter/` folder into which Flutter artifacts are written
/// during build.
///
/// This is the same as [hostAppRoot] except when the project is
/// a Flutter module with an editable host app.
Directory get _flutterLibRoot => isModule ? ephemeralModuleDirectory : _editableDirectory;
/// True, if the parent Flutter project is a module project.
bool get isModule => parent.isModule;
/// Whether the flutter application has an iOS project.
bool get exists => hostAppRoot.existsSync();
/// Put generated files here.
Directory get ephemeralDirectory => _flutterLibRoot.childDirectory('
Flutter
').childDirectory('
ephemeral
');
@override
File xcodeConfigFor(String mode) => _flutterLibRoot.childDirectory('
Flutter
').childFile('
$mode
.
xcconfig
');
@override
File get generatedEnvironmentVariableExportScript => _flutterLibRoot.childDirectory('
Flutter
').childFile('
flutter_export_environment
.
sh
');
@override
File get podfile => hostAppRoot.childFile('
Podfile
');
@override
File get podfileLock => hostAppRoot.childFile('
Podfile
.
lock
');
@override
File get podManifestLock => hostAppRoot.childDirectory('
Pods
').childFile('
Manifest
.
lock
');
/// The default '
Info
.
plist
' file of the host app. The developer can change this location in Xcode.
File get defaultHostInfoPlist => hostAppRoot.childDirectory(_hostAppProjectName).childFile('
Info
.
plist
');
File get appFrameworkInfoPlist => _flutterLibRoot.childDirectory('
Flutter
').childFile('
AppFrameworkInfo
.
plist
');
Directory get symlinks => _flutterLibRoot.childDirectory('
.
symlinks
');
@override
Directory get xcodeProject => hostAppRoot.childDirectory('
$_hostAppProjectName
.
xcodeproj
');
@override
File get xcodeProjectInfoFile => xcodeProject.childFile('
project
.
pbxproj
');
File get xcodeProjectWorkspaceData =>
xcodeProject
.childDirectory('
project
.
xcworkspace
')
.childFile('
contents
.
xcworkspacedata
');
@override
Directory get xcodeWorkspace => hostAppRoot.childDirectory('
$_hostAppProjectName
.
xcworkspace
');
/// Xcode workspace shared data directory for the host app.
Directory get xcodeWorkspaceSharedData => xcodeWorkspace.childDirectory('
xcshareddata
');
/// Xcode workspace shared workspace settings file for the host app.
File get xcodeWorkspaceSharedSettings => xcodeWorkspaceSharedData.childFile('
WorkspaceSettings
.
xcsettings
');
@override
bool existsSync() {
return parent.isModule || _editableDirectory.existsSync();
}
/// The product bundle identifier of the host app, or null if not set or if
/// iOS tooling needed to read it is not installed.
Future<String?> productBundleIdentifier(BuildInfo? buildInfo) async {
if (!existsSync()) {
return null;
}
return _productBundleIdentifier ??= await _parseProductBundleIdentifier(buildInfo);
}
String? _productBundleIdentifier;
Future<String?> _parseProductBundleIdentifier(BuildInfo? buildInfo) async {
String? fromPlist;
final File defaultInfoPlist = defaultHostInfoPlist;
// Users can change the location of the Info.plist.
// Try parsing the default, first.
if (defaultInfoPlist.existsSync()) {
try {
fromPlist = globals.plistParser.getValueFromFile(
defaultHostInfoPlist.path,
PlistParser.kCFBundleIdentifierKey,
);
} on FileNotFoundException {
// iOS tooling not found; likely not running OSX; let [fromPlist] be null
}
if (fromPlist != null && !fromPlist.contains(r'
$
')) {
// Info.plist has no build variables in product bundle ID.
return fromPlist;
}
}
final Map<String, String>? allBuildSettings = await buildSettingsForBuildInfo(buildInfo);
if (allBuildSettings != null) {
if (fromPlist != null) {
// Perform variable substitution using build settings.
return substituteXcodeVariables(fromPlist, allBuildSettings);
}
return allBuildSettings['
PRODUCT_BUNDLE_IDENTIFIER
'];
}
// On non-macOS platforms, parse the first PRODUCT_BUNDLE_IDENTIFIER from
// the project file. This can return the wrong bundle identifier if additional
// bundles have been added to the project and are found first, like frameworks
// or companion watchOS projects. However, on non-macOS platforms this is
// only used for display purposes and to regenerate organization names, so
// best-effort is probably fine.
final String? fromPbxproj = firstMatchInFile(xcodeProjectInfoFile, _productBundleIdPattern)?.group(2);
if (fromPbxproj != null && (fromPlist == null || fromPlist == _productBundleIdVariable)) {
return fromPbxproj;
}
return null;
}
/// The bundle name of the host app, `My App.app`.
Future<String?> hostAppBundleName(BuildInfo buildInfo) async {
if (!existsSync()) {
return null;
}
return _hostAppBundleName ??= await _parseHostAppBundleName(buildInfo);
}
String? _hostAppBundleName;
Future<String> _parseHostAppBundleName(BuildInfo buildInfo) 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
// The only source of truth for the name is Xcode'
s
interpretation
of
the
build
settings
.
String
?
productName
;
if
(
globals
.
xcodeProjectInterpreter
?.
isInstalled
==
true
)
{
final
Map
<
String
,
String
>?
xcodeBuildSettings
=
await
buildSettingsForBuildInfo
(
buildInfo
);
if
(
xcodeBuildSettings
!=
null
)
{
productName
=
xcodeBuildSettings
[
'FULL_PRODUCT_NAME'
];
}
}
if
(
productName
==
null
)
{
globals
.
printTrace
(
'FULL_PRODUCT_NAME not present, defaulting to
$_hostAppProjectName
'
);
}
return
productName
??
'
$_hostAppProjectName
.app'
;
}
/// The build settings for the host app of this project, as a detached map.
///
/// Returns null, if iOS tooling is unavailable.
Future
<
Map
<
String
,
String
>?>
buildSettingsForBuildInfo
(
BuildInfo
?
buildInfo
,
{
EnvironmentType
environmentType
=
EnvironmentType
.
physical
})
async
{
if
(!
existsSync
())
{
return
null
;
}
final
XcodeProjectInfo
?
info
=
await
projectInfo
();
if
(
info
==
null
)
{
return
null
;
}
final
String
?
scheme
=
info
.
schemeFor
(
buildInfo
);
if
(
scheme
==
null
)
{
info
.
reportFlavorNotFoundAndExit
();
}
final
String
?
configuration
=
(
await
projectInfo
())?.
buildConfigurationFor
(
buildInfo
,
scheme
,
);
final
XcodeProjectBuildContext
buildContext
=
XcodeProjectBuildContext
(
environmentType:
environmentType
,
scheme:
scheme
,
configuration:
configuration
);
final
Map
<
String
,
String
>?
currentBuildSettings
=
_buildSettingsByBuildContext
[
buildContext
];
if
(
currentBuildSettings
==
null
)
{
final
Map
<
String
,
String
>?
calculatedBuildSettings
=
await
_xcodeProjectBuildSettings
(
buildContext
);
if
(
calculatedBuildSettings
!=
null
)
{
_buildSettingsByBuildContext
[
buildContext
]
=
calculatedBuildSettings
;
}
}
return
_buildSettingsByBuildContext
[
buildContext
];
}
final
Map
<
XcodeProjectBuildContext
,
Map
<
String
,
String
>>
_buildSettingsByBuildContext
=
<
XcodeProjectBuildContext
,
Map
<
String
,
String
>>{};
Future
<
XcodeProjectInfo
?>
projectInfo
()
async
{
final
XcodeProjectInterpreter
?
xcodeProjectInterpreter
=
globals
.
xcodeProjectInterpreter
;
if
(!
xcodeProject
.
existsSync
()
||
xcodeProjectInterpreter
==
null
||
!
xcodeProjectInterpreter
.
isInstalled
)
{
return
null
;
}
return
_projectInfo
??=
await
xcodeProjectInterpreter
.
getInfo
(
hostAppRoot
.
path
);
}
XcodeProjectInfo
?
_projectInfo
;
Future
<
Map
<
String
,
String
>?>
_xcodeProjectBuildSettings
(
XcodeProjectBuildContext
buildContext
)
async
{
final
XcodeProjectInterpreter
?
xcodeProjectInterpreter
=
globals
.
xcodeProjectInterpreter
;
if
(
xcodeProjectInterpreter
==
null
||
!
xcodeProjectInterpreter
.
isInstalled
)
{
return
null
;
}
final
Map
<
String
,
String
>
buildSettings
=
await
xcodeProjectInterpreter
.
getBuildSettings
(
xcodeProject
.
path
,
buildContext:
buildContext
,
);
if
(
buildSettings
!=
null
&&
buildSettings
.
isNotEmpty
)
{
// No timeouts, flakes, or errors.
return
buildSettings
;
}
return
null
;
}
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{
await
_regenerateFromTemplateIfNeeded
();
if
(!
_flutterLibRoot
.
existsSync
())
{
return
;
}
await
_updateGeneratedXcodeConfigIfNeeded
();
}
/// Check if one the [targets] of the project is a watchOS companion app target.
Future
<
bool
>
containsWatchCompanion
(
List
<
String
>
targets
,
BuildInfo
buildInfo
)
async
{
final
String
?
bundleIdentifier
=
await
productBundleIdentifier
(
buildInfo
);
// A bundle identifier is required for a companion app.
if
(
bundleIdentifier
==
null
)
{
return
false
;
}
for
(
final
String
target
in
targets
)
{
// Create Info.plist file of the target.
final
File
infoFile
=
hostAppRoot
.
childDirectory
(
target
).
childFile
(
'Info.plist'
);
// The Info.plist file of a target contains the key WKCompanionAppBundleIdentifier,
// if it is a watchOS companion app.
if
(
infoFile
.
existsSync
())
{
final
String
?
fromPlist
=
globals
.
plistParser
.
getValueFromFile
(
infoFile
.
path
,
'WKCompanionAppBundleIdentifier'
);
if
(
bundleIdentifier
==
fromPlist
)
{
return
true
;
}
// The key WKCompanionAppBundleIdentifier might contain an xcode variable
// that needs to be substituted before comparing it with bundle id
if
(
fromPlist
!=
null
&&
fromPlist
.
contains
(
r'$'
))
{
final
Map
<
String
,
String
>?
allBuildSettings
=
await
buildSettingsForBuildInfo
(
buildInfo
);
if
(
allBuildSettings
!=
null
)
{
final
String
substituedVariable
=
substituteXcodeVariables
(
fromPlist
,
allBuildSettings
);
if
(
substituedVariable
==
bundleIdentifier
)
{
return
true
;
}
}
}
}
}
return
false
;
}
Future
<
void
>
_updateGeneratedXcodeConfigIfNeeded
()
async
{
if
(
globals
.
cache
.
isOlderThanToolsStamp
(
generatedXcodePropertiesFile
))
{
await
xcode
.
updateGeneratedXcodeProperties
(
project:
parent
,
buildInfo:
BuildInfo
.
debug
,
targetOverride:
bundle
.
defaultMainPath
,
);
}
}
Future
<
void
>
_regenerateFromTemplateIfNeeded
()
async
{
if
(!
isModule
)
{
return
;
}
final
bool
pubspecChanged
=
globals
.
fsUtils
.
isOlderThanReference
(
entity:
ephemeralModuleDirectory
,
referenceFile:
parent
.
pubspecFile
,
);
final
bool
toolingChanged
=
globals
.
cache
.
isOlderThanToolsStamp
(
ephemeralModuleDirectory
);
if
(!
pubspecChanged
&&
!
toolingChanged
)
{
return
;
}
ErrorHandlingFileSystem
.
deleteIfExists
(
ephemeralModuleDirectory
,
recursive:
true
);
await
_overwriteFromTemplate
(
globals
.
fs
.
path
.
join
(
'module'
,
'ios'
,
'library'
),
ephemeralModuleDirectory
,
);
// Add ephemeral host app, if a editable host app does not already exist.
if
(!
_editableDirectory
.
existsSync
())
{
await
_overwriteFromTemplate
(
globals
.
fs
.
path
.
join
(
'module'
,
'ios'
,
'host_app_ephemeral'
),
ephemeralModuleDirectory
,
);
if
(
hasPlugins
(
parent
))
{
await
_overwriteFromTemplate
(
globals
.
fs
.
path
.
join
(
'module'
,
'ios'
,
'host_app_ephemeral_cocoapods'
),
ephemeralModuleDirectory
,
);
}
// Use release mode so host project can link on bitcode variant.
_copyEngineArtifactToProject
(
BuildMode
.
release
,
EnvironmentType
.
physical
);
}
}
void
_copyEngineArtifactToProject
(
BuildMode
mode
,
EnvironmentType
environmentType
)
{
// Copy framework from engine cache. The actual build mode
// doesn't actually matter as it will be overwritten by xcode_backend.sh.
// However, cocoapods will run before that script and requires something
// to be in this location.
final
Directory
framework
=
globals
.
fs
.
directory
(
globals
.
artifacts
?.
getArtifactPath
(
Artifact
.
flutterXcframework
,
platform:
TargetPlatform
.
ios
,
mode:
mode
,
environmentType:
environmentType
,
)
);
if
(
framework
.
existsSync
())
{
copyDirectory
(
framework
,
engineCopyDirectory
.
childDirectory
(
'Flutter.xcframework'
),
);
}
}
@override
File
get
generatedXcodePropertiesFile
=>
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childFile
(
'Generated.xcconfig'
);
/// No longer compiled to this location.
///
/// Used only for "flutter clean" to remove old references.
Directory
get
deprecatedCompiledDartFramework
=>
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childDirectory
(
'App.framework'
);
/// No longer copied to this location.
///
/// Used only for "flutter clean" to remove old references.
Directory
get
deprecatedProjectFlutterFramework
=>
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childDirectory
(
'Flutter.framework'
);
/// Used only for "flutter clean" to remove old references.
File
get
flutterPodspec
=>
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childFile
(
'Flutter.podspec'
);
Directory
get
pluginRegistrantHost
{
return
isModule
?
_flutterLibRoot
.
childDirectory
(
'Flutter'
)
.
childDirectory
(
'FlutterPluginRegistrant'
)
:
hostAppRoot
.
childDirectory
(
_hostAppProjectName
);
}
File
get
pluginRegistrantHeader
{
final
Directory
registryDirectory
=
isModule
?
pluginRegistrantHost
.
childDirectory
(
'Classes'
)
:
pluginRegistrantHost
;
return
registryDirectory
.
childFile
(
'GeneratedPluginRegistrant.h'
);
}
File
get
pluginRegistrantImplementation
{
final
Directory
registryDirectory
=
isModule
?
pluginRegistrantHost
.
childDirectory
(
'Classes'
)
:
pluginRegistrantHost
;
return
registryDirectory
.
childFile
(
'GeneratedPluginRegistrant.m'
);
}
Directory
get
engineCopyDirectory
{
return
isModule
?
ephemeralModuleDirectory
.
childDirectory
(
'Flutter'
).
childDirectory
(
'engine'
)
:
hostAppRoot
.
childDirectory
(
'Flutter'
);
}
Future
<
void
>
_overwriteFromTemplate
(
String
path
,
Directory
target
)
async
{
final
Template
template
=
await
Template
.
fromName
(
path
,
fileSystem:
globals
.
fs
,
templateManifest:
null
,
logger:
globals
.
logger
,
templateRenderer:
globals
.
templateRenderer
,
);
final
String
iosBundleIdentifier
=
parent
.
manifest
.
iosBundleIdentifier
??
'com.example.
${parent.manifest.appName}
'
;
template
.
render
(
target
,
<
String
,
Object
>{
'ios'
:
true
,
'projectName'
:
parent
.
manifest
.
appName
,
'iosIdentifier'
:
iosBundleIdentifier
,
},
printStatusWhenWriting:
false
,
overwriteExisting:
true
,
);
}
}
/// The macOS sub project.
class
MacOSProject
extends
FlutterProjectPlatform
implements
XcodeBasedProject
{
MacOSProject
.
fromFlutter
(
this
.
parent
);
@override
final
FlutterProject
parent
;
@override
String
get
pluginConfigKey
=>
MacOSPlugin
.
kConfigKey
;
static
const
String
_hostAppProjectName
=
'Runner'
;
@override
bool
existsSync
()
=>
_macOSDirectory
.
existsSync
();
Directory
get
_macOSDirectory
=>
parent
.
directory
.
childDirectory
(
'macos'
);
/// The directory in the project that is managed by Flutter. As much as
/// possible, files that are edited by Flutter tooling after initial project
/// creation should live here.
Directory
get
managedDirectory
=>
_macOSDirectory
.
childDirectory
(
'Flutter'
);
/// The subdirectory of [managedDirectory] that contains files that are
/// generated on the fly. All generated files that are not intended to be
/// checked in should live here.
Directory
get
ephemeralDirectory
=>
managedDirectory
.
childDirectory
(
'ephemeral'
);
/// The xcfilelist used to track the inputs for the Flutter script phase in
/// the Xcode build.
File
get
inputFileList
=>
ephemeralDirectory
.
childFile
(
'FlutterInputs.xcfilelist'
);
/// The xcfilelist used to track the outputs for the Flutter script phase in
/// the Xcode build.
File
get
outputFileList
=>
ephemeralDirectory
.
childFile
(
'FlutterOutputs.xcfilelist'
);
@override
File
get
generatedXcodePropertiesFile
=>
ephemeralDirectory
.
childFile
(
'Flutter-Generated.xcconfig'
);
@override
File
xcodeConfigFor
(
String
mode
)
=>
managedDirectory
.
childFile
(
'Flutter-
$mode
.xcconfig'
);
@override
File
get
generatedEnvironmentVariableExportScript
=>
ephemeralDirectory
.
childFile
(
'flutter_export_environment.sh'
);
@override
File
get
podfile
=>
_macOSDirectory
.
childFile
(
'Podfile'
);
@override
File
get
podfileLock
=>
_macOSDirectory
.
childFile
(
'Podfile.lock'
);
@override
File
get
podManifestLock
=>
_macOSDirectory
.
childDirectory
(
'Pods'
).
childFile
(
'Manifest.lock'
);
@override
Directory
get
xcodeProject
=>
_macOSDirectory
.
childDirectory
(
'
$_hostAppProjectName
.xcodeproj'
);
@override
File
get
xcodeProjectInfoFile
=>
xcodeProject
.
childFile
(
'project.pbxproj'
);
@override
Directory
get
xcodeWorkspace
=>
_macOSDirectory
.
childDirectory
(
'
$_hostAppProjectName
.xcworkspace'
);
/// 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
/// scheme's target.
File
get
nameFile
=>
ephemeralDirectory
.
childFile
(
'.app_filename'
);
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{
// TODO(stuartmorgan): Add create-from-template logic here.
await
_updateGeneratedXcodeConfigIfNeeded
();
}
Future
<
void
>
_updateGeneratedXcodeConfigIfNeeded
()
async
{
if
(
globals
.
cache
.
isOlderThanToolsStamp
(
generatedXcodePropertiesFile
))
{
await
xcode
.
updateGeneratedXcodeProperties
(
project:
parent
,
buildInfo:
BuildInfo
.
debug
,
useMacOSConfig:
true
,
);
}
}
}
packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart
View file @
e028d0f0
...
...
@@ -11,8 +11,8 @@ import 'package:flutter_tools/src/ios/migrations/project_base_configuration_migr
import
'package:flutter_tools/src/ios/migrations/project_build_location_migration.dart'
;
import
'package:flutter_tools/src/ios/migrations/remove_framework_link_and_embedding_migration.dart'
;
import
'package:flutter_tools/src/ios/migrations/xcode_build_system_migration.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/reporting/reporting.dart'
;
import
'package:flutter_tools/src/xcode_project.dart'
;
import
'package:test/fake.dart'
;
import
'../../src/common.dart'
;
...
...
packages/flutter_tools/test/general.shard/macos/macos_project_migration_test.dart
View file @
e028d0f0
...
...
@@ -7,8 +7,8 @@ import 'package:file/memory.dart';
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/base/project_migrator.dart'
;
import
'package:flutter_tools/src/macos/migrations/remove_macos_framework_link_and_embedding_migration.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/reporting/reporting.dart'
;
import
'package:flutter_tools/src/xcode_project.dart'
;
import
'package:test/fake.dart'
;
import
'../../src/common.dart'
;
...
...
packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart
View file @
e028d0f0
...
...
@@ -7,8 +7,8 @@ import 'package:file/memory.dart';
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/base/project_migrator.dart'
;
import
'package:flutter_tools/src/base/terminal.dart'
;
import
'package:flutter_tools/src/cmake_project.dart'
;
import
'package:flutter_tools/src/migrations/cmake_custom_command_migration.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:test/fake.dart'
;
import
'../../src/common.dart'
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment