Unverified Commit 1e8ef602 authored by Sigurd Meldgaard's avatar Sigurd Meldgaard Committed by GitHub

Add iOS module template (#18830) (#18903)

Add iOS module template

This will enable integration of flutter-views into existing iOS project.
parent 266a7202
...@@ -83,10 +83,20 @@ BuildApp() { ...@@ -83,10 +83,20 @@ BuildApp() {
RunCommand mkdir -p -- "$derived_dir" RunCommand mkdir -p -- "$derived_dir"
AssertExists "$derived_dir" AssertExists "$derived_dir"
RunCommand rm -rf -- "${derived_dir}/Flutter.framework"
RunCommand rm -rf -- "${derived_dir}/App.framework" RunCommand rm -rf -- "${derived_dir}/App.framework"
RunCommand cp -r -- "${framework_path}/Flutter.framework" "${derived_dir}"
RunCommand find "${derived_dir}/Flutter.framework" -type f -exec chmod a-w "{}" \; if [[ -e "${project_path}/.ios" ]]; then
RunCommand rm -rf -- "${derived_dir}/engine"
mkdir "${derived_dir}/engine"
RunCommand cp -r -- "${framework_path}/Flutter.podspec" "${derived_dir}/engine"
RunCommand cp -r -- "${framework_path}/Flutter.framework" "${derived_dir}/engine"
RunCommand find "${derived_dir}/engine/Flutter.framework" -type f -exec chmod a-w "{}" \;
else
RunCommand rm -rf -- "${derived_dir}/Flutter.framework"
RunCommand cp -r -- "${framework_path}/Flutter.framework" "${derived_dir}"
RunCommand find "${derived_dir}/Flutter.framework" -type f -exec chmod a-w "{}" \;
fi
RunCommand pushd "${project_path}" > /dev/null RunCommand pushd "${project_path}" > /dev/null
AssertExists "${target_path}" AssertExists "${target_path}"
...@@ -155,7 +165,13 @@ BuildApp() { ...@@ -155,7 +165,13 @@ BuildApp() {
-install_name '@rpath/App.framework/App' \ -install_name '@rpath/App.framework/App' \
-o "${derived_dir}/App.framework/App" -)" -o "${derived_dir}/App.framework/App" -)"
fi fi
RunCommand cp -- "${project_path}/ios/Flutter/AppFrameworkInfo.plist" "${derived_dir}/App.framework/Info.plist"
local plistPath="${project_path}/ios/Flutter/AppFrameworkInfo.plist"
if [[ -e "${project_path}/.ios" ]]; then
plistPath="${project_path}/.ios/Flutter/AppFrameworkInfo.plist"
fi
RunCommand cp -- "$plistPath" "${derived_dir}/App.framework/Info.plist"
local precompilation_flag="" local precompilation_flag=""
if [[ "$CURRENT_ARCH" != "x86_64" ]] && [[ "$build_mode" != "debug" ]]; then if [[ "$CURRENT_ARCH" != "x86_64" ]] && [[ "$build_mode" != "debug" ]]; then
......
...@@ -169,6 +169,19 @@ class Cache { ...@@ -169,6 +169,19 @@ class Cache {
return fs.file(fs.path.join(getRoot().path, '$artifactName.stamp')); return fs.file(fs.path.join(getRoot().path, '$artifactName.stamp'));
} }
/// Returns `true` if either [file] is older than the tools stamp or if
/// [file] doesn't exist.
bool fileOlderThanToolsStamp(File file) {
if (!file.existsSync()) {
return true;
}
final File flutterToolsStamp = getStampFileFor('flutter_tools');
return flutterToolsStamp.existsSync() &&
flutterToolsStamp
.lastModifiedSync()
.isAfter(file.lastModifiedSync());
}
bool isUpToDate() => _artifacts.every((CachedArtifact artifact) => artifact.isUpToDate()); bool isUpToDate() => _artifacts.every((CachedArtifact artifact) => artifact.isUpToDate());
Future<String> getThirdPartyFile(String urlStr, String serviceName) async { Future<String> getThirdPartyFile(String urlStr, String serviceName) async {
......
...@@ -233,20 +233,20 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit ...@@ -233,20 +233,20 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
} }
} }
Future<int> _generateModule(String dirPath, Map<String, dynamic> templateContext) async { Future<int> _generateModule(String path, Map<String, dynamic> templateContext) async {
int generatedCount = 0; int generatedCount = 0;
final String description = argResults.wasParsed('description') final String description = argResults.wasParsed('description')
? argResults['description'] ? argResults['description']
: 'A new flutter module project.'; : 'A new flutter module project.';
templateContext['description'] = description; templateContext['description'] = description;
generatedCount += _renderTemplate(fs.path.join('module', 'common'), dirPath, templateContext); generatedCount += _renderTemplate(fs.path.join('module', 'common'), path, templateContext);
if (argResults['pub']) { if (argResults['pub']) {
await pubGet( await pubGet(
context: PubContext.create, context: PubContext.create,
directory: dirPath, directory: path,
offline: argResults['offline'], offline: argResults['offline'],
); );
final FlutterProject project = new FlutterProject(fs.directory(dirPath)); final FlutterProject project = new FlutterProject.fromPath(path);
await project.ensureReadyForPlatformSpecificTooling(); await project.ensureReadyForPlatformSpecificTooling();
} }
return generatedCount; return generatedCount;
...@@ -303,23 +303,23 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit ...@@ -303,23 +303,23 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
return generatedCount; return generatedCount;
} }
Future<int> _generateApp(String appPath, Map<String, dynamic> templateContext) async { Future<int> _generateApp(String projectPath, Map<String, dynamic> templateContext) async {
int generatedCount = 0; int generatedCount = 0;
generatedCount += _renderTemplate('create', appPath, templateContext); generatedCount += _renderTemplate('create', projectPath, templateContext);
generatedCount += _injectGradleWrapper(appPath); generatedCount += _injectGradleWrapper(projectPath);
if (argResults['with-driver-test']) { if (argResults['with-driver-test']) {
final String testPath = fs.path.join(appPath, 'test_driver'); final String testPath = fs.path.join(projectPath, 'test_driver');
generatedCount += _renderTemplate('driver', testPath, templateContext); generatedCount += _renderTemplate('driver', testPath, templateContext);
} }
if (argResults['pub']) { if (argResults['pub']) {
await pubGet(context: PubContext.create, directory: appPath, offline: argResults['offline']); await pubGet(context: PubContext.create, directory: projectPath, offline: argResults['offline']);
await new FlutterProject(fs.directory(appPath)).ensureReadyForPlatformSpecificTooling(); await new FlutterProject.fromPath(projectPath).ensureReadyForPlatformSpecificTooling();
} }
if (android_sdk.androidSdk != null) if (android_sdk.androidSdk != null)
await gradle.updateLocalProperties(projectPath: appPath); await gradle.updateLocalProperties(projectPath: projectPath);
return generatedCount; return generatedCount;
} }
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
import 'dart:async'; import 'dart:async';
import '../base/file_system.dart';
import '../flutter_manifest.dart';
import '../globals.dart'; import '../globals.dart';
import '../plugins.dart'; import '../plugins.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -24,7 +26,9 @@ class InjectPluginsCommand extends FlutterCommand { ...@@ -24,7 +26,9 @@ class InjectPluginsCommand extends FlutterCommand {
@override @override
Future<Null> runCommand() async { Future<Null> runCommand() async {
injectPlugins(); final String projectPath = fs.currentDirectory.path;
final FlutterManifest manifest = await FlutterManifest.createFromPath(projectPath);
injectPlugins(projectPath: projectPath, manifest: manifest);
final bool result = hasPlugins(); final bool result = hasPlugins();
if (result) { if (result) {
printStatus('GeneratedPluginRegistrants successfully written.'); printStatus('GeneratedPluginRegistrants successfully written.');
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
import 'dart:async'; import 'dart:async';
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart';
import '../base/os.dart'; import '../base/os.dart';
import '../dart/pub.dart'; import '../dart/pub.dart';
import '../project.dart'; import '../project.dart';
...@@ -81,7 +80,7 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -81,7 +80,7 @@ class PackagesGetCommand extends FlutterCommand {
} }
await _runPubGet(target); await _runPubGet(target);
final FlutterProject rootProject = new FlutterProject(fs.directory(target)); final FlutterProject rootProject = new FlutterProject.fromPath(target);
await rootProject.ensureReadyForPlatformSpecificTooling(); await rootProject.ensureReadyForPlatformSpecificTooling();
// Get/upgrade packages in example app as well // Get/upgrade packages in example app as well
......
...@@ -15,6 +15,7 @@ import '../base/process.dart'; ...@@ -15,6 +15,7 @@ import '../base/process.dart';
import '../base/process_manager.dart'; import '../base/process_manager.dart';
import '../base/version.dart'; import '../base/version.dart';
import '../cache.dart'; import '../cache.dart';
import '../flutter_manifest.dart';
import '../globals.dart'; import '../globals.dart';
import 'xcodeproj.dart'; import 'xcodeproj.dart';
...@@ -150,11 +151,14 @@ class CocoaPods { ...@@ -150,11 +151,14 @@ class CocoaPods {
/// Ensures the `ios` sub-project of the Flutter project at [appDirectory] /// Ensures the `ios` sub-project of the Flutter project at [appDirectory]
/// contains a suitable `Podfile` and that its `Flutter/Xxx.xcconfig` files /// contains a suitable `Podfile` and that its `Flutter/Xxx.xcconfig` files
/// include pods configuration. /// include pods configuration.
void setupPodfile(String appDirectory) { void setupPodfile(String appDirectory, FlutterManifest manifest) {
if (!xcodeProjectInterpreter.isInstalled) { if (!xcodeProjectInterpreter.isInstalled) {
// Don't do anything for iOS when host platform doesn't support it. // Don't do anything for iOS when host platform doesn't support it.
return; return;
} }
if (!fs.directory(fs.path.join(appDirectory, 'ios')).existsSync()) {
return;
}
final String podfilePath = fs.path.join(appDirectory, 'ios', 'Podfile'); final String podfilePath = fs.path.join(appDirectory, 'ios', 'Podfile');
if (!fs.file(podfilePath).existsSync()) { if (!fs.file(podfilePath).existsSync()) {
final bool isSwift = xcodeProjectInterpreter.getBuildSettings( final bool isSwift = xcodeProjectInterpreter.getBuildSettings(
...@@ -171,6 +175,7 @@ class CocoaPods { ...@@ -171,6 +175,7 @@ class CocoaPods {
)); ));
podfileTemplate.copySync(podfilePath); podfileTemplate.copySync(podfilePath);
} }
_addPodsDependencyToFlutterXcconfig(appDirectory, 'Debug'); _addPodsDependencyToFlutterXcconfig(appDirectory, 'Debug');
_addPodsDependencyToFlutterXcconfig(appDirectory, 'Release'); _addPodsDependencyToFlutterXcconfig(appDirectory, 'Release');
} }
......
...@@ -20,6 +20,7 @@ import '../base/process.dart'; ...@@ -20,6 +20,7 @@ import '../base/process.dart';
import '../base/process_manager.dart'; import '../base/process_manager.dart';
import '../base/utils.dart'; import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../flutter_manifest.dart';
import '../globals.dart'; import '../globals.dart';
import '../plugins.dart'; import '../plugins.dart';
import '../services.dart'; import '../services.dart';
...@@ -242,11 +243,15 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -242,11 +243,15 @@ Future<XcodeBuildResult> buildXcodeProject({
final Directory appDirectory = fs.directory(app.appDirectory); final Directory appDirectory = fs.directory(app.appDirectory);
await _addServicesToBundle(appDirectory); await _addServicesToBundle(appDirectory);
await updateGeneratedXcodeProperties( final FlutterManifest manifest = await FlutterManifest.createFromPath(
fs.currentDirectory.childFile('pubspec.yaml').path,
);
updateGeneratedXcodeProperties(
projectPath: fs.currentDirectory.path, projectPath: fs.currentDirectory.path,
buildInfo: buildInfo, buildInfo: buildInfo,
targetOverride: targetOverride, targetOverride: targetOverride,
previewDart2: buildInfo.previewDart2, previewDart2: buildInfo.previewDart2,
manifest: manifest,
); );
if (hasPlugins()) { if (hasPlugins()) {
......
...@@ -2,12 +2,9 @@ ...@@ -2,12 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/common.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
...@@ -28,21 +25,30 @@ String flutterFrameworkDir(BuildMode mode) { ...@@ -28,21 +25,30 @@ String flutterFrameworkDir(BuildMode mode) {
return fs.path.normalize(fs.path.dirname(artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, mode))); return fs.path.normalize(fs.path.dirname(artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, mode)));
} }
String _generatedXcodePropertiesPath(String projectPath) { String _generatedXcodePropertiesPath({@required String projectPath, @required FlutterManifest manifest}) {
return fs.path.join(projectPath, 'ios', 'Flutter', 'Generated.xcconfig'); if (manifest.isModule) {
return fs.path.join(projectPath, '.ios', 'Flutter', 'Generated.xcconfig');
} else {
return fs.path.join(projectPath, 'ios', 'Flutter', 'Generated.xcconfig');
}
} }
/// Writes default Xcode properties files in the Flutter project at [projectPath], /// Writes default Xcode properties files in the Flutter project at [projectPath],
/// if project is an iOS project and such files do not already exist. /// if project is an iOS project and such files are out of date or do not
Future<void> generateXcodeProperties(String projectPath) async { /// already exist.
if (fs.isDirectorySync(fs.path.join(projectPath, 'ios'))) { void generateXcodeProperties({String projectPath, FlutterManifest manifest}) {
if (fs.file(_generatedXcodePropertiesPath(projectPath)).existsSync()) if (manifest.isModule || fs.isDirectorySync(fs.path.join(projectPath, 'ios'))) {
final File propertiesFile = fs.file(_generatedXcodePropertiesPath(projectPath: projectPath, manifest: manifest));
if (!Cache.instance.fileOlderThanToolsStamp(propertiesFile)) {
return; return;
await updateGeneratedXcodeProperties( }
updateGeneratedXcodeProperties(
projectPath: projectPath, projectPath: projectPath,
manifest: manifest,
buildInfo: BuildInfo.debug, buildInfo: BuildInfo.debug,
targetOverride: bundle.defaultMainPath, targetOverride: bundle.defaultMainPath,
previewDart2: false, previewDart2: true,
); );
} }
} }
...@@ -51,14 +57,13 @@ Future<void> generateXcodeProperties(String projectPath) async { ...@@ -51,14 +57,13 @@ Future<void> generateXcodeProperties(String projectPath) async {
/// ///
/// targetOverride: Optional parameter, if null or unspecified the default value /// targetOverride: Optional parameter, if null or unspecified the default value
/// from xcode_backend.sh is used 'lib/main.dart'. /// from xcode_backend.sh is used 'lib/main.dart'.
/// void updateGeneratedXcodeProperties({
/// Returns the number of files written.
Future<void> updateGeneratedXcodeProperties({
@required String projectPath, @required String projectPath,
@required FlutterManifest manifest,
@required BuildInfo buildInfo, @required BuildInfo buildInfo,
String targetOverride, String targetOverride,
@required bool previewDart2, @required bool previewDart2,
}) async { }) {
final StringBuffer localsBuffer = new StringBuffer(); final StringBuffer localsBuffer = new StringBuffer();
localsBuffer.writeln('// This is a generated file; do not edit or check into version control.'); localsBuffer.writeln('// This is a generated file; do not edit or check into version control.');
...@@ -81,14 +86,11 @@ Future<void> updateGeneratedXcodeProperties({ ...@@ -81,14 +86,11 @@ Future<void> updateGeneratedXcodeProperties({
localsBuffer.writeln('SYMROOT=\${SOURCE_ROOT}/../${getIosBuildDirectory()}'); localsBuffer.writeln('SYMROOT=\${SOURCE_ROOT}/../${getIosBuildDirectory()}');
localsBuffer.writeln('FLUTTER_FRAMEWORK_DIR=${flutterFrameworkDir(buildInfo.mode)}'); if (!manifest.isModule) {
// For module projects we do not want to write the FLUTTER_FRAMEWORK_DIR
final String flutterManifest = fs.path.join(projectPath, bundle.defaultManifestPath); // explicitly. Rather we rely on the xcode backend script and the Podfile
FlutterManifest manifest; // logic to derive it from FLUTTER_ROOT and FLUTTER_BUILD_MODE.
try { localsBuffer.writeln('FLUTTER_FRAMEWORK_DIR=${flutterFrameworkDir(buildInfo.mode)}');
manifest = await FlutterManifest.createFromPath(flutterManifest);
} catch (error) {
throwToolExit('Failed to load pubspec.yaml: $error');
} }
final String buildName = buildInfo?.buildName ?? manifest.buildName; final String buildName = buildInfo?.buildName ?? manifest.buildName;
...@@ -123,7 +125,7 @@ Future<void> updateGeneratedXcodeProperties({ ...@@ -123,7 +125,7 @@ Future<void> updateGeneratedXcodeProperties({
localsBuffer.writeln('TRACK_WIDGET_CREATION=true'); localsBuffer.writeln('TRACK_WIDGET_CREATION=true');
} }
final File localsFile = fs.file(_generatedXcodePropertiesPath(projectPath)); final File localsFile = fs.file(_generatedXcodePropertiesPath(projectPath: projectPath, manifest: manifest));
localsFile.createSync(recursive: true); localsFile.createSync(recursive: true);
localsFile.writeAsStringSync(localsBuffer.toString()); localsFile.writeAsStringSync(localsBuffer.toString());
} }
......
...@@ -8,9 +8,18 @@ import 'package:yaml/yaml.dart'; ...@@ -8,9 +8,18 @@ import 'package:yaml/yaml.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'dart/package_map.dart'; import 'dart/package_map.dart';
import 'flutter_manifest.dart';
import 'globals.dart'; import 'globals.dart';
import 'ios/cocoapods.dart'; import 'ios/cocoapods.dart';
void _renderTemplateToFile(String template, dynamic context, String filePath) {
final String renderedTemplate =
new mustache.Template(template).renderString(context);
final File file = fs.file(filePath);
file.createSync(recursive: true);
file.writeAsStringSync(renderedTemplate);
}
class Plugin { class Plugin {
final String name; final String name;
final String path; final String path;
...@@ -60,7 +69,7 @@ Plugin _pluginFromPubspec(String name, Uri packageRoot) { ...@@ -60,7 +69,7 @@ Plugin _pluginFromPubspec(String name, Uri packageRoot) {
return new Plugin.fromYaml(name, packageRootPath, flutterConfig['plugin']); return new Plugin.fromYaml(name, packageRootPath, flutterConfig['plugin']);
} }
List<Plugin> _findPlugins(String directory) { List<Plugin> findPlugins(String directory) {
final List<Plugin> plugins = <Plugin>[]; final List<Plugin> plugins = <Plugin>[];
Map<String, Uri> packages; Map<String, Uri> packages;
try { try {
...@@ -146,14 +155,9 @@ void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) { ...@@ -146,14 +155,9 @@ void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) {
'plugins': androidPlugins, 'plugins': androidPlugins,
}; };
final String pluginRegistry =
new mustache.Template(_androidPluginRegistryTemplate).renderString(context);
final String javaSourcePath = fs.path.join(directory, 'src', 'main', 'java'); final String javaSourcePath = fs.path.join(directory, 'src', 'main', 'java');
final Directory registryDirectory = final String registryPath = fs.path.join(javaSourcePath, 'io', 'flutter', 'plugins', 'GeneratedPluginRegistrant.java');
fs.directory(fs.path.join(javaSourcePath, 'io', 'flutter', 'plugins')); _renderTemplateToFile(_androidPluginRegistryTemplate, context, registryPath);
registryDirectory.createSync(recursive: true);
final File registryFile = registryDirectory.childFile('GeneratedPluginRegistrant.java');
registryFile.writeAsStringSync(pluginRegistry);
} }
const String _iosPluginRegistryHeaderTemplate = '''// const String _iosPluginRegistryHeaderTemplate = '''//
...@@ -192,7 +196,32 @@ const String _iosPluginRegistryImplementationTemplate = '''// ...@@ -192,7 +196,32 @@ const String _iosPluginRegistryImplementationTemplate = '''//
@end @end
'''; ''';
void _writeIOSPluginRegistrant(String directory, List<Plugin> plugins) { const String _iosPluginRegistrantPodspecTemplate = '''
#
# Generated file, do not edit.
#
Pod::Spec.new do |s|
s.name = 'FlutterPluginRegistrant'
s.version = '0.0.1'
s.summary = 'Registers plugins with your flutter app'
s.description = <<-DESC
Depends on all your plugins, and provides a function to register them.
DESC
s.homepage = 'https://flutter.io'
s.license = { :type => 'BSD' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.ios.deployment_target = '7.0'
s.source_files = "Classes", "Classes/**/*.{h,m}"
s.source = { :path => '.' }
s.public_header_files = './Classes/**/*.h'
{{#plugins}}
s.dependency '{{name}}'
{{/plugins}}
end
''';
void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List<Plugin> plugins) {
final List<Map<String, dynamic>> iosPlugins = plugins final List<Map<String, dynamic>> iosPlugins = plugins
.where((Plugin p) => p.pluginClass != null) .where((Plugin p) => p.pluginClass != null)
.map((Plugin p) => <String, dynamic>{ .map((Plugin p) => <String, dynamic>{
...@@ -205,16 +234,41 @@ void _writeIOSPluginRegistrant(String directory, List<Plugin> plugins) { ...@@ -205,16 +234,41 @@ void _writeIOSPluginRegistrant(String directory, List<Plugin> plugins) {
'plugins': iosPlugins, 'plugins': iosPlugins,
}; };
final String pluginRegistryHeader = if (manifest.isModule) {
new mustache.Template(_iosPluginRegistryHeaderTemplate).renderString(context); // In a module create the GeneratedPluginRegistrant as a pod to be included
final String pluginRegistryImplementation = // from a hosting app.
new mustache.Template(_iosPluginRegistryImplementationTemplate).renderString(context); final String registryDirectory = fs.path.join(directory, 'FlutterPluginRegistrant');
final Directory registryDirectory = fs.directory(fs.path.join(directory, 'ios', 'Runner')); final String registryClassesDirectory = fs.path.join(registryDirectory, 'Classes');
registryDirectory.createSync(recursive: true); _renderTemplateToFile(
final File registryHeaderFile = registryDirectory.childFile('GeneratedPluginRegistrant.h'); _iosPluginRegistrantPodspecTemplate,
registryHeaderFile.writeAsStringSync(pluginRegistryHeader); context,
final File registryImplementationFile = registryDirectory.childFile('GeneratedPluginRegistrant.m'); fs.path.join(registryDirectory, 'FlutterPluginRegistrant.podspec'),
registryImplementationFile.writeAsStringSync(pluginRegistryImplementation); );
_renderTemplateToFile(
_iosPluginRegistryHeaderTemplate,
context,
fs.path.join(registryClassesDirectory, 'GeneratedPluginRegistrant.h'),
);
_renderTemplateToFile(
_iosPluginRegistryImplementationTemplate,
context,
fs.path.join(registryClassesDirectory, 'GeneratedPluginRegistrant.m'),
);
} else {
// For a non-module create the GeneratedPluginRegistrant as source files
// directly in the ios project.
final String runnerDirectory = fs.path.join(directory, 'Runner');
_renderTemplateToFile(
_iosPluginRegistryHeaderTemplate,
context,
fs.path.join(runnerDirectory, 'GeneratedPluginRegistrant.h'),
);
_renderTemplateToFile(
_iosPluginRegistryImplementationTemplate,
context,
fs.path.join(runnerDirectory, 'GeneratedPluginRegistrant.m'),
);
}
} }
class InjectPluginsResult{ class InjectPluginsResult{
...@@ -229,22 +283,23 @@ class InjectPluginsResult{ ...@@ -229,22 +283,23 @@ class InjectPluginsResult{
} }
/// Injects plugins found in `pubspec.yaml` into the platform-specific projects. /// Injects plugins found in `pubspec.yaml` into the platform-specific projects.
void injectPlugins({String directory}) { void injectPlugins({@required String projectPath, @required FlutterManifest manifest}) {
directory ??= fs.currentDirectory.path; final List<Plugin> plugins = findPlugins(projectPath);
final List<Plugin> plugins = _findPlugins(directory); final bool changed = _writeFlutterPluginsList(projectPath, plugins);
final bool changed = _writeFlutterPluginsList(directory, plugins); if (manifest.isModule) {
if (fs.isDirectorySync(fs.path.join(directory, '.android', 'Flutter'))) { _writeAndroidPluginRegistrant(fs.path.join(projectPath, '.android', 'Flutter'), plugins);
_writeAndroidPluginRegistrant(fs.path.join(directory, '.android', 'Flutter'), plugins); } else if (fs.isDirectorySync(fs.path.join(projectPath, 'android', 'app'))) {
} else if (fs.isDirectorySync(fs.path.join(directory, 'android', 'app'))) { _writeAndroidPluginRegistrant(fs.path.join(projectPath, 'android', 'app'), plugins);
_writeAndroidPluginRegistrant(fs.path.join(directory, 'android', 'app'), plugins);
} }
if (fs.isDirectorySync(fs.path.join(directory, 'ios'))) { if (manifest.isModule) {
_writeIOSPluginRegistrant(directory, plugins); _writeIOSPluginRegistrant(fs.path.join(projectPath, '.ios'), manifest, plugins);
} else if (fs.isDirectorySync(fs.path.join(projectPath, 'ios'))) {
_writeIOSPluginRegistrant(fs.path.join(projectPath, 'ios'), manifest, plugins);
final CocoaPods cocoaPods = new CocoaPods(); final CocoaPods cocoaPods = new CocoaPods();
if (plugins.isNotEmpty) if (plugins.isNotEmpty)
cocoaPods.setupPodfile(directory); cocoaPods.setupPodfile(projectPath, manifest);
if (changed) if (changed)
cocoaPods.invalidatePodInstallOutput(directory); cocoaPods.invalidatePodInstallOutput(projectPath);
} }
} }
......
...@@ -8,6 +8,7 @@ import 'dart:convert'; ...@@ -8,6 +8,7 @@ import 'dart:convert';
import 'android/gradle.dart' as gradle; import 'android/gradle.dart' as gradle;
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'bundle.dart' as bundle;
import 'cache.dart'; import 'cache.dart';
import 'flutter_manifest.dart'; import 'flutter_manifest.dart';
import 'ios/xcodeproj.dart' as xcode; import 'ios/xcodeproj.dart' as xcode;
...@@ -16,11 +17,20 @@ import 'template.dart'; ...@@ -16,11 +17,20 @@ import 'template.dart';
/// Represents the contents of a Flutter project at the specified [directory]. /// Represents the contents of a Flutter project at the specified [directory].
class FlutterProject { class FlutterProject {
FlutterProject(this.directory); FlutterProject(this.directory);
FlutterProject.fromPath(String projectPath) : directory = fs.directory(projectPath);
/// The location of this project. /// The location of this project.
final Directory directory; final Directory directory;
Future<FlutterManifest> get manifest {
return _manifest ??= FlutterManifest.createFromPath(
directory.childFile(bundle.defaultManifestPath).path,
);
}
Future<FlutterManifest> _manifest;
/// Asynchronously returns the organization names found in this project as /// Asynchronously returns the organization names found in this project as
/// part of iOS product bundle identifier, Android application ID, or /// part of iOS product bundle identifier, Android application ID, or
/// Gradle group ID. /// Gradle group ID.
...@@ -54,11 +64,17 @@ class FlutterProject { ...@@ -54,11 +64,17 @@ class FlutterProject {
/// The generated AndroidModule sub project of this module project. /// The generated AndroidModule sub project of this module project.
AndroidModuleProject get androidModule => new AndroidModuleProject(directory.childDirectory('.android')); AndroidModuleProject get androidModule => new AndroidModuleProject(directory.childDirectory('.android'));
/// The generated IosModule sub project of this module project.
IosModuleProject get iosModule => new IosModuleProject(directory.childDirectory('.ios'));
/// Returns true if this project has an example application /// Returns true if this project has an example application
bool get hasExampleApp => directory.childDirectory('example').childFile('pubspec.yaml').existsSync(); bool get hasExampleApp => _exampleDirectory.childFile('pubspec.yaml').existsSync();
/// The example sub project of this (package or plugin) project. /// The example sub project of this (package or plugin) project.
FlutterProject get example => new FlutterProject(directory.childDirectory('example')); FlutterProject get example => new FlutterProject(_exampleDirectory);
/// The directory that will contain the example if an example exists.
Directory get _exampleDirectory => directory.childDirectory('example');
/// Generates project files necessary to make Gradle builds work on Android /// Generates project files necessary to make Gradle builds work on Android
/// and CocoaPods+Xcode work on iOS, for app and module projects only. /// and CocoaPods+Xcode work on iOS, for app and module projects only.
...@@ -68,12 +84,13 @@ class FlutterProject { ...@@ -68,12 +84,13 @@ class FlutterProject {
if (!directory.existsSync() || hasExampleApp) { if (!directory.existsSync() || hasExampleApp) {
return 0; return 0;
} }
final FlutterManifest manifest = await FlutterManifest.createFromPath(directory.childFile('pubspec.yaml').path); final FlutterManifest manifest = await this.manifest;
if (manifest.isModule) { if (manifest.isModule) {
await androidModule.ensureReadyForPlatformSpecificTooling(manifest); await androidModule.ensureReadyForPlatformSpecificTooling(manifest);
await iosModule.ensureReadyForPlatformSpecificTooling(manifest);
} }
injectPlugins(directory: directory.path); xcode.generateXcodeProperties(projectPath: directory.path, manifest: manifest);
await xcode.generateXcodeProperties(directory.path); injectPlugins(projectPath: directory.path, manifest: manifest);
} }
} }
...@@ -90,6 +107,25 @@ class IosProject { ...@@ -90,6 +107,25 @@ class IosProject {
} }
} }
/// Represents the contents of the .ios/ folder of a Flutter module
/// project.
class IosModuleProject {
IosModuleProject(this.directory);
final Directory directory;
Future<void> ensureReadyForPlatformSpecificTooling(FlutterManifest manifest) async {
if (_shouldRegenerate()) {
final Template template = new Template.fromName(fs.path.join('module', 'ios'));
template.render(directory, <String, dynamic>{}, printStatusWhenWriting: false);
}
}
bool _shouldRegenerate() {
return Cache.instance.fileOlderThanToolsStamp(directory.childFile('podhelper.rb'));
}
}
/// Represents the contents of the android/ folder of a Flutter project. /// Represents the contents of the android/ folder of a Flutter project.
class AndroidProject { class AndroidProject {
static final RegExp _applicationIdPattern = new RegExp('^\\s*applicationId\\s+[\'\"](.*)[\'\"]\\s*\$'); static final RegExp _applicationIdPattern = new RegExp('^\\s*applicationId\\s+[\'\"](.*)[\'\"]\\s*\$');
...@@ -129,14 +165,7 @@ class AndroidModuleProject { ...@@ -129,14 +165,7 @@ class AndroidModuleProject {
} }
bool _shouldRegenerate() { bool _shouldRegenerate() {
final File flutterToolsStamp = Cache.instance.getStampFileFor('flutter_tools'); return Cache.instance.fileOlderThanToolsStamp(directory.childFile('build.gradle'));
final File buildDotGradleFile = directory.childFile('build.gradle');
if (!buildDotGradleFile.existsSync())
return true;
return flutterToolsStamp.existsSync() &&
flutterToolsStamp
.lastModifiedSync()
.isAfter(buildDotGradleFile.lastModifiedSync());
} }
} }
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>
This directory contains support code for embedding the Flutter project in an iOS app.
It should not be edited or checked in.
# This file should be used from the target section of the host-app's Podfile like this:
# ```
# target 'host' do
# flutter_application_path = /"(.*)\/.ios\/Generated.xcconfig"/.match(File.read("./Flutter/FlutterConfig.xcconfig"))[1]
# eval(File.read(File.join(flutter_application_path, '.ios', 'podhelper.rb')))
# end
# ```
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_array = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_array.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_array
end
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
def flutter_root(f)
generated_xcode_build_settings = parse_KV_file(File.join(f, File.join('.ios', 'Generated.xcconfig')))
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. Make sure `flutter packages get` is executed in ${f}."
exit
end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_ROOT'
return p[:path]
end
}
end
framework_dir = File.join(File.expand_path(File.dirname(__FILE__)), 'Flutter')
engine_dir = File.join(framework_dir, 'engine')
if !File.exist?(engine_dir)
# Copy the debug engine to have something to link against if the xcode backend script has not run yet.
debug_framework_dir = File.join(flutter_root(flutter_application_path), 'bin', 'cache', 'artifacts', 'engine', 'ios')
FileUtils.mkdir(engine_dir)
FileUtils.cp_r(File.join(debug_framework_dir, 'Flutter.framework'), engine_dir)
FileUtils.cp(File.join(debug_framework_dir, 'Flutter.podspec'), engine_dir)
end
symlink = File.join('.symlinks', 'flutter')
File.symlink(framework_dir, symlink)
pod 'Flutter', :path => File.join(symlink, 'engine')
plugin_pods = parse_KV_file(File.join(flutter_application_path, '.flutter-plugins'))
plugin_pods.map { |r|
symlink = File.join('.symlinks', 'plugins', r[:name])
File.symlink(r[:path], symlink)
pod r[:name], :path => File.join(symlink, 'ios')
}
symlink = File.join('.symlinks', 'FlutterApp')
File.symlink(File.absolute_path(flutter_application_path), symlink)
pod 'FlutterPluginRegistrant', :path => File.join(symlink, '.ios', 'FlutterPluginRegistrant')
...@@ -9,6 +9,8 @@ import 'package:file/memory.dart'; ...@@ -9,6 +9,8 @@ import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/flutter_manifest.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/ios/cocoapods.dart'; import 'package:flutter_tools/src/ios/cocoapods.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
...@@ -132,21 +134,25 @@ void main() { ...@@ -132,21 +134,25 @@ void main() {
podFile = fs.file(fs.path.join('project', 'ios', 'Podfile')); podFile = fs.file(fs.path.join('project', 'ios', 'Podfile'));
}); });
testUsingContext('creates objective-c Podfile when not present', () { testUsingContext('creates objective-c Podfile when not present', () async {
cocoaPodsUnderTest.setupPodfile('project'); final FlutterManifest manifest =
await new FlutterProject.fromPath('project').manifest;
cocoaPodsUnderTest.setupPodfile('project', manifest);
expect(podFile.readAsStringSync(), 'Objective-C podfile template'); expect(podFile.readAsStringSync(), 'Objective-C podfile template');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fs, FileSystem: () => fs,
}); });
testUsingContext('creates swift Podfile if swift', () { testUsingContext('creates swift Podfile if swift', () async {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true); when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.getBuildSettings(any, any)).thenReturn(<String, String>{ when(mockXcodeProjectInterpreter.getBuildSettings(any, any)).thenReturn(<String, String>{
'SWIFT_VERSION': '4.0', 'SWIFT_VERSION': '4.0',
}); });
cocoaPodsUnderTest.setupPodfile('project'); final FlutterManifest manifest =
await new FlutterProject.fromPath('project').manifest;
cocoaPodsUnderTest.setupPodfile('project', manifest);
expect(podFile.readAsStringSync(), 'Swift podfile template'); expect(podFile.readAsStringSync(), 'Swift podfile template');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
...@@ -154,20 +160,24 @@ void main() { ...@@ -154,20 +160,24 @@ void main() {
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter, XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
}); });
testUsingContext('does not recreate Podfile when already present', () { testUsingContext('does not recreate Podfile when already present', () async {
podFile..createSync()..writeAsStringSync('Existing Podfile'); podFile..createSync()..writeAsStringSync('Existing Podfile');
cocoaPodsUnderTest.setupPodfile('project'); final FlutterManifest manifest =
await new FlutterProject.fromPath('project').manifest;
cocoaPodsUnderTest.setupPodfile('project', manifest);
expect(podFile.readAsStringSync(), 'Existing Podfile'); expect(podFile.readAsStringSync(), 'Existing Podfile');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fs, FileSystem: () => fs,
}); });
testUsingContext('does not create Podfile when we cannot interpret Xcode projects', () { testUsingContext('does not create Podfile when we cannot interpret Xcode projects', () async {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(false); when(mockXcodeProjectInterpreter.isInstalled).thenReturn(false);
cocoaPodsUnderTest.setupPodfile('project'); final FlutterManifest manifest =
await new FlutterProject.fromPath('project').manifest;
cocoaPodsUnderTest.setupPodfile('project', manifest);
expect(podFile.existsSync(), false); expect(podFile.existsSync(), false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
...@@ -175,12 +185,14 @@ void main() { ...@@ -175,12 +185,14 @@ void main() {
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter, XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
}); });
testUsingContext('includes Pod config in xcconfig files, if not present', () { testUsingContext('includes Pod config in xcconfig files, if not present', () async {
podFile..createSync()..writeAsStringSync('Existing Podfile'); podFile..createSync()..writeAsStringSync('Existing Podfile');
debugConfigFile..createSync(recursive: true)..writeAsStringSync('Existing debug config'); debugConfigFile..createSync(recursive: true)..writeAsStringSync('Existing debug config');
releaseConfigFile..createSync(recursive: true)..writeAsStringSync('Existing release config'); releaseConfigFile..createSync(recursive: true)..writeAsStringSync('Existing release config');
cocoaPodsUnderTest.setupPodfile('project'); final FlutterManifest manifest =
await new FlutterProject.fromPath('project').manifest;
cocoaPodsUnderTest.setupPodfile('project', manifest);
final String debugContents = debugConfigFile.readAsStringSync(); final String debugContents = debugConfigFile.readAsStringSync();
expect(debugContents, contains( expect(debugContents, contains(
......
...@@ -11,6 +11,8 @@ import 'package:flutter_tools/src/base/io.dart'; ...@@ -11,6 +11,8 @@ import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/bundle.dart' as bundle; import 'package:flutter_tools/src/bundle.dart' as bundle;
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/flutter_manifest.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
...@@ -284,12 +286,16 @@ Information about project "Runner": ...@@ -284,12 +286,16 @@ Information about project "Runner":
testUsingOsxContext('sets ARCHS=armv7 when armv7 local engine is set', () async { testUsingOsxContext('sets ARCHS=armv7 when armv7 local engine is set', () async {
when(mockArtifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, any)).thenReturn('engine'); when(mockArtifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, any)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm')); when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
const BuildInfo buildInfo = const BuildInfo(BuildMode.debug, null, const BuildInfo buildInfo = const BuildInfo(BuildMode.debug, null,
previewDart2: true, previewDart2: true,
targetPlatform: TargetPlatform.ios, targetPlatform: TargetPlatform.ios,
); );
await updateGeneratedXcodeProperties( final FlutterManifest manifest =
await new FlutterProject.fromPath('path/to/project').manifest;
updateGeneratedXcodeProperties(
projectPath: 'path/to/project', projectPath: 'path/to/project',
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
previewDart2: true, previewDart2: true,
); );
...@@ -309,8 +315,11 @@ Information about project "Runner": ...@@ -309,8 +315,11 @@ Information about project "Runner":
trackWidgetCreation: true, trackWidgetCreation: true,
targetPlatform: TargetPlatform.ios, targetPlatform: TargetPlatform.ios,
); );
await updateGeneratedXcodeProperties( final FlutterManifest manifest =
await new FlutterProject.fromPath('path/to/project').manifest;
updateGeneratedXcodeProperties(
projectPath: 'path/to/project', projectPath: 'path/to/project',
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
previewDart2: true, previewDart2: true,
); );
...@@ -329,8 +338,11 @@ Information about project "Runner": ...@@ -329,8 +338,11 @@ Information about project "Runner":
previewDart2: true, previewDart2: true,
targetPlatform: TargetPlatform.ios, targetPlatform: TargetPlatform.ios,
); );
await updateGeneratedXcodeProperties( final FlutterManifest manifest =
await new FlutterProject.fromPath('path/to/project').manifest;
updateGeneratedXcodeProperties(
projectPath: 'path/to/project', projectPath: 'path/to/project',
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
previewDart2: true, previewDart2: true,
); );
...@@ -349,8 +361,12 @@ Information about project "Runner": ...@@ -349,8 +361,12 @@ Information about project "Runner":
previewDart2: true, previewDart2: true,
targetPlatform: TargetPlatform.ios, targetPlatform: TargetPlatform.ios,
); );
await updateGeneratedXcodeProperties(
final FlutterManifest manifest =
await new FlutterProject.fromPath('path/to/project').manifest;
updateGeneratedXcodeProperties(
projectPath: 'path/to/project', projectPath: 'path/to/project',
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
previewDart2: true, previewDart2: true,
); );
...@@ -394,15 +410,18 @@ Information about project "Runner": ...@@ -394,15 +410,18 @@ Information about project "Runner":
} }
Future<void> checkBuildVersion({ Future<void> checkBuildVersion({
String manifest, String manifestString,
BuildInfo buildInfo, BuildInfo buildInfo,
String expectedBuildName, String expectedBuildName,
String expectedBuildNumber, String expectedBuildNumber,
}) async { }) async {
final String projectPath = await createMinimalProject(manifest); final String projectPath = await createMinimalProject(manifestString);
await updateGeneratedXcodeProperties( final FlutterManifest manifest =
await new FlutterProject.fromPath(projectPath).manifest;
updateGeneratedXcodeProperties(
projectPath: projectPath, projectPath: projectPath,
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
targetOverride: bundle.defaultMainPath, targetOverride: bundle.defaultMainPath,
previewDart2: false, previewDart2: false,
...@@ -427,7 +446,7 @@ flutter: ...@@ -427,7 +446,7 @@ flutter:
const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null); const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null);
await checkBuildVersion( await checkBuildVersion(
manifest: manifest, manifestString: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
expectedBuildName: '1.0.0', expectedBuildName: '1.0.0',
expectedBuildNumber: '1', expectedBuildNumber: '1',
...@@ -445,7 +464,7 @@ flutter: ...@@ -445,7 +464,7 @@ flutter:
'''; ''';
const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null); const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null);
await checkBuildVersion( await checkBuildVersion(
manifest: manifest, manifestString: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
expectedBuildName: '1.0.0', expectedBuildName: '1.0.0',
expectedBuildNumber: null, expectedBuildNumber: null,
...@@ -463,7 +482,7 @@ flutter: ...@@ -463,7 +482,7 @@ flutter:
'''; ''';
const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2'); const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2');
await checkBuildVersion( await checkBuildVersion(
manifest: manifest, manifestString: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
expectedBuildName: '1.0.2', expectedBuildName: '1.0.2',
expectedBuildNumber: '1', expectedBuildNumber: '1',
...@@ -481,7 +500,7 @@ flutter: ...@@ -481,7 +500,7 @@ flutter:
'''; ''';
const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildNumber: 3); const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildNumber: 3);
await checkBuildVersion( await checkBuildVersion(
manifest: manifest, manifestString: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
expectedBuildName: '1.0.0', expectedBuildName: '1.0.0',
expectedBuildNumber: '3', expectedBuildNumber: '3',
...@@ -499,7 +518,7 @@ flutter: ...@@ -499,7 +518,7 @@ flutter:
'''; ''';
const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3); const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3);
await checkBuildVersion( await checkBuildVersion(
manifest: manifest, manifestString: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
expectedBuildName: '1.0.2', expectedBuildName: '1.0.2',
expectedBuildNumber: '3', expectedBuildNumber: '3',
...@@ -517,7 +536,7 @@ flutter: ...@@ -517,7 +536,7 @@ flutter:
'''; ''';
const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3); const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3);
await checkBuildVersion( await checkBuildVersion(
manifest: manifest, manifestString: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
expectedBuildName: '1.0.2', expectedBuildName: '1.0.2',
expectedBuildNumber: '3', expectedBuildNumber: '3',
...@@ -534,7 +553,7 @@ flutter: ...@@ -534,7 +553,7 @@ flutter:
'''; ''';
const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3); const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3);
await checkBuildVersion( await checkBuildVersion(
manifest: manifest, manifestString: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
expectedBuildName: '1.0.2', expectedBuildName: '1.0.2',
expectedBuildNumber: '3', expectedBuildNumber: '3',
......
...@@ -15,7 +15,14 @@ void main() { ...@@ -15,7 +15,14 @@ void main() {
group('Project', () { group('Project', () {
testInMemory('knows location', () { testInMemory('knows location', () {
final Directory directory = fs.directory('myproject'); final Directory directory = fs.directory('myproject');
expect(new FlutterProject(directory).directory, directory); expect(
new FlutterProject(directory).directory.absolute.path,
directory.absolute.path,
);
expect(
new FlutterProject.fromPath(directory.path).directory.absolute.path,
directory.absolute.path,
);
}); });
group('ensure ready for platform-specific tooling', () { group('ensure ready for platform-specific tooling', () {
testInMemory('does nothing, if project is not created', () async { testInMemory('does nothing, if project is not created', () async {
...@@ -94,7 +101,7 @@ void main() { ...@@ -94,7 +101,7 @@ void main() {
}); });
} }
FlutterProject someProject() => new FlutterProject(fs.directory('some_project')); FlutterProject someProject() => new FlutterProject.fromPath('some_project');
FlutterProject aProjectWithIos() { FlutterProject aProjectWithIos() {
final Directory directory = fs.directory('ios_project'); final Directory directory = fs.directory('ios_project');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment