From df946dd875cd799cfa1acd5be11e438b3bff22e8 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Wed, 17 Feb 2016 10:58:34 -0800 Subject: [PATCH 1/4] iOS: Treat the initial Info.plist string as a mustache template. Use the project name to initialize the bundle name and identifier --- .../lib/src/application_package.dart | 29 ++++++++++++++----- .../lib/src/ios/plist_utils.dart | 29 +++++++++++++++++++ .../lib/src/ios/setup_xcodeproj.dart | 26 ++++------------- packages/flutter_tools/test/src/mocks.dart | 4 +-- 4 files changed, 57 insertions(+), 31 deletions(-) create mode 100644 packages/flutter_tools/lib/src/ios/plist_utils.dart diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart index b50878c1c60..1a1c30f33a0 100644 --- a/packages/flutter_tools/lib/src/application_package.dart +++ b/packages/flutter_tools/lib/src/application_package.dart @@ -10,6 +10,7 @@ import 'package:xml/xml.dart' as xml; import 'artifacts.dart'; import 'build_configuration.dart'; +import 'ios/plist_utils.dart'; abstract class ApplicationPackage { /// Path to the actual apk or bundle. @@ -81,13 +82,25 @@ class AndroidApk extends ApplicationPackage { } class IOSApp extends ApplicationPackage { - static const String _defaultId = 'io.flutter.runner.Runner'; - static const String _defaultPath = 'ios/.generated'; - IOSApp({ - String localPath: _defaultPath, - String id: _defaultId - }) : super(localPath: localPath, id: id); + String iosProjectDir, + String iosProjectBundleId + }) : super(localPath: iosProjectDir, id: iosProjectBundleId); + + factory IOSApp.fromBuildConfiguration(BuildConfiguration config) { + if (getCurrentHostPlatform() != HostPlatform.mac) { + return null; + } + + String plistPath = path.join("ios", "Info.plist"); + String id = plistValueForKey(plistPath, kCFBundleIdentifierKey); + if (id == "") { + return null; + } + + String projectDir = path.join("ios", ".generated"); + return new IOSApp(iosProjectDir: projectDir, iosProjectBundleId: id); + } } class ApplicationPackageStore { @@ -138,12 +151,12 @@ class ApplicationPackageStore { case TargetPlatform.iOS: assert(iOS == null); - iOS = new IOSApp(); + iOS = new IOSApp.fromBuildConfiguration(config); break; case TargetPlatform.iOSSimulator: assert(iOSSimulator == null); - iOSSimulator = new IOSApp(); + iOSSimulator = new IOSApp.fromBuildConfiguration(config); break; case TargetPlatform.mac: diff --git a/packages/flutter_tools/lib/src/ios/plist_utils.dart b/packages/flutter_tools/lib/src/ios/plist_utils.dart new file mode 100644 index 00000000000..cb9f6a2d985 --- /dev/null +++ b/packages/flutter_tools/lib/src/ios/plist_utils.dart @@ -0,0 +1,29 @@ +// Copyright 2016 The Chromium 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:path/path.dart' as path; + +import '../base/process.dart'; + +const String kCFBundleIdentifierKey = "CFBundleIdentifier"; + +String plistValueForKey(String plistFilePath, String plistKey) { + // TODO(chinmaygarde): For now, we only need to read from plist files on a + // mac host. If this changes, we will need our own Dart plist reader. + + // Don't use PlistBuddy since that is not guaranteed to be installed. + // 'defaults' requires the path to be absolute and without the 'plist' + // extension. + String normalizedPlistPath = path.withoutExtension(path.absolute(plistFilePath)); + + try { + return runCheckedSync([ + '/usr/bin/defaults', + 'read', + normalizedPlistPath, + plistKey]).trim(); + } catch (error) { + return ""; + } +} diff --git a/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart b/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart index ce97d9471c7..704c4e66a4b 100644 --- a/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart +++ b/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart @@ -91,18 +91,6 @@ Future _inflateXcodeArchive(String directory, List archiveBytes) asyn return true; } -void _writeUserEditableFilesIfNecessary(String directory) { - iosTemplateFiles.forEach((String filePath, String contents) { - File file = new File(filePath); - - if (!file.existsSync()) { - file.parent.createSync(recursive: true); - file.writeAsStringSync(contents); - printStatus('Created $filePath.'); - } - }); -} - void _setupXcodeProjXcconfig(String filePath) { StringBuffer localsBuffer = new StringBuffer(); @@ -160,19 +148,15 @@ Future setupXcodeProjectHarness() async { return 1; } - // Step 3: Setup default user editable files if this is the first run of - // the init command. - _writeUserEditableFilesIfNecessary(iosFilesPath); - - // Step 4: Populate the Local.xcconfig with project specific paths + // Step 3: Populate the Local.xcconfig with project specific paths _setupXcodeProjXcconfig(path.join(xcodeprojPath, 'Local.xcconfig')); - // Step 5: Write the REVISION file + // Step 4: Write the REVISION file File revisionFile = new File(path.join(xcodeprojPath, 'REVISION')); revisionFile.createSync(); revisionFile.writeAsStringSync(ArtifactStore.engineRevision); - // Step 6: Tell the user the location of the generated project. + // Step 5: Tell the user the location of the generated project. printStatus('Xcode project created at $xcodeprojPath/.'); printStatus('User editable settings are in $iosFilesPath/.'); @@ -189,11 +173,11 @@ final String _infoPlistInitialContents = ''' CFBundleExecutable Runner CFBundleIdentifier - io.flutter.runner.Runner + com.example.{{projectName}} CFBundleInfoDictionaryVersion 6.0 CFBundleName - Flutter + {{projectName}} CFBundlePackageType APPL CFBundleShortVersionString diff --git a/packages/flutter_tools/test/src/mocks.dart b/packages/flutter_tools/test/src/mocks.dart index 99161d6f3eb..145a6257323 100644 --- a/packages/flutter_tools/test/src/mocks.dart +++ b/packages/flutter_tools/test/src/mocks.dart @@ -14,8 +14,8 @@ import 'package:mockito/mockito.dart'; class MockApplicationPackageStore extends ApplicationPackageStore { MockApplicationPackageStore() : super( android: new AndroidApk(localPath: '/mock/path/to/android/SkyShell.apk'), - iOS: new IOSApp(localPath: '/mock/path/to/iOS/SkyShell.app'), - iOSSimulator: new IOSApp(localPath: '/mock/path/to/iOSSimulator/SkyShell.app')); + iOS: new IOSApp(iosProjectDir: '/mock/path/to/iOS/SkyShell.app'), + iOSSimulator: new IOSApp(iosProjectDir: '/mock/path/to/iOSSimulator/SkyShell.app')); } class MockCompiler extends Mock implements Compiler { From b37112af2afb78241920ede6c375a3cb1d587feb Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Wed, 17 Feb 2016 12:26:00 -0800 Subject: [PATCH 2/4] Rewrite Local.xcconfig per build In case the user changes the path of the Flutter project on disk, the Dart SDK or the Flutter repository itself, the old Xcode paths would be invalid. Now, we rewrite them when we build the project. --- packages/flutter_tools/lib/src/ios/device_ios.dart | 6 +++++- .../flutter_tools/lib/src/ios/setup_xcodeproj.dart | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/flutter_tools/lib/src/ios/device_ios.dart b/packages/flutter_tools/lib/src/ios/device_ios.dart index b6a667c98f4..83d46955e1d 100644 --- a/packages/flutter_tools/lib/src/ios/device_ios.dart +++ b/packages/flutter_tools/lib/src/ios/device_ios.dart @@ -565,12 +565,16 @@ String _getIOSEngineRevision(ApplicationPackage app) { } Future _buildIOSXcodeProject(ApplicationPackage app, { bool buildForDevice }) async { + String flutterProjectPath = Directory.current.path; + if (xcodeProjectRequiresUpdate()) { printTrace('Initializing the Xcode project.'); - if ((await setupXcodeProjectHarness()) != 0) { + if ((await setupXcodeProjectHarness(flutterProjectPath)) != 0) { printError('Could not initialize the Xcode project.'); return false; } + } else { + updateXcodeLocalProperties(flutterProjectPath); } if (!_validateEngineRevision(app)) diff --git a/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart b/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart index 704c4e66a4b..7c98bbc960f 100644 --- a/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart +++ b/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart @@ -91,7 +91,7 @@ Future _inflateXcodeArchive(String directory, List archiveBytes) asyn return true; } -void _setupXcodeProjXcconfig(String filePath) { +void updateXcodeLocalProperties(String projectPath) { StringBuffer localsBuffer = new StringBuffer(); localsBuffer.writeln('// This is a generated file; do not edit or check into version control.'); @@ -106,7 +106,7 @@ void _setupXcodeProjXcconfig(String filePath) { String dartSDKPath = path.normalize(path.join(Platform.resolvedExecutable, '..', '..')); localsBuffer.writeln('DART_SDK_PATH=$dartSDKPath'); - File localsFile = new File(filePath); + File localsFile = new File(path.join(projectPath, 'ios', '.generated', 'Local.xcconfig')); localsFile.createSync(recursive: true); localsFile.writeAsStringSync(localsBuffer.toString()); } @@ -130,9 +130,9 @@ bool xcodeProjectRequiresUpdate() { return false; } -Future setupXcodeProjectHarness() async { +Future setupXcodeProjectHarness(String flutterProjectPath) async { // Step 1: Fetch the archive from the cloud - String iosFilesPath = path.join(Directory.current.path, 'ios'); + String iosFilesPath = path.join(flutterProjectPath, 'ios'); String xcodeprojPath = path.join(iosFilesPath, '.generated'); List archiveBytes = await _fetchXcodeArchive(); @@ -149,7 +149,7 @@ Future setupXcodeProjectHarness() async { } // Step 3: Populate the Local.xcconfig with project specific paths - _setupXcodeProjXcconfig(path.join(xcodeprojPath, 'Local.xcconfig')); + updateXcodeLocalProperties(flutterProjectPath); // Step 4: Write the REVISION file File revisionFile = new File(path.join(xcodeprojPath, 'REVISION')); From 512f5764bd6078d69d9c87ddffa9a8da39e50633 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Wed, 17 Feb 2016 15:28:26 -0800 Subject: [PATCH 3/4] Add an issue template for Github --- ISSUE_TEMPLATE.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 ISSUE_TEMPLATE.md diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 00000000000..4748e1fb20d --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,14 @@ + +_Detailed issue description here. More information at [https://flutter.io/bug_reports/](https://flutter.io/bug_reports/)_ + +### Steps to Reproduce +* _Add steps here. Provide verbose variants of `flutter` commands if necessary._ + +### Flutter Version +_Add flutter version here_ + +### Logs +_Paste relevant logs here_ + +### Crash Reports +_Add relevant crash reports here_ From 9ed4e417d03473a61c00b1c1bb9b0aae0bf5a055 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Fri, 19 Feb 2016 11:48:39 -0800 Subject: [PATCH 4/4] Fix flutter_tools tests --- packages/flutter_tools/test/src/mocks.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/test/src/mocks.dart b/packages/flutter_tools/test/src/mocks.dart index 145a6257323..a5f3ee3f7da 100644 --- a/packages/flutter_tools/test/src/mocks.dart +++ b/packages/flutter_tools/test/src/mocks.dart @@ -14,8 +14,10 @@ import 'package:mockito/mockito.dart'; class MockApplicationPackageStore extends ApplicationPackageStore { MockApplicationPackageStore() : super( android: new AndroidApk(localPath: '/mock/path/to/android/SkyShell.apk'), - iOS: new IOSApp(iosProjectDir: '/mock/path/to/iOS/SkyShell.app'), - iOSSimulator: new IOSApp(iosProjectDir: '/mock/path/to/iOSSimulator/SkyShell.app')); + iOS: new IOSApp(iosProjectDir: '/mock/path/to/iOS/SkyShell.app', + iosProjectBundleId: 'io.flutter.ios.mock'), + iOSSimulator: new IOSApp(iosProjectDir: '/mock/path/to/iOSSimulator/SkyShell.app', + iosProjectBundleId: 'io.flutter.ios.mock')); } class MockCompiler extends Mock implements Compiler {