Commit 670bf871 authored by Chinmay Garde's avatar Chinmay Garde

Merge pull request #1969 from chinmaygarde/master

iOS: Misc tooling updates
parents 5009f44a 9ed4e417
_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_
...@@ -10,6 +10,7 @@ import 'package:xml/xml.dart' as xml; ...@@ -10,6 +10,7 @@ import 'package:xml/xml.dart' as xml;
import 'artifacts.dart'; import 'artifacts.dart';
import 'build_configuration.dart'; import 'build_configuration.dart';
import 'ios/plist_utils.dart';
abstract class ApplicationPackage { abstract class ApplicationPackage {
/// Path to the actual apk or bundle. /// Path to the actual apk or bundle.
...@@ -81,13 +82,25 @@ class AndroidApk extends ApplicationPackage { ...@@ -81,13 +82,25 @@ class AndroidApk extends ApplicationPackage {
} }
class IOSApp extends ApplicationPackage { class IOSApp extends ApplicationPackage {
static const String _defaultId = 'io.flutter.runner.Runner';
static const String _defaultPath = 'ios/.generated';
IOSApp({ IOSApp({
String localPath: _defaultPath, String iosProjectDir,
String id: _defaultId String iosProjectBundleId
}) : super(localPath: localPath, id: id); }) : 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 { class ApplicationPackageStore {
...@@ -138,12 +151,12 @@ class ApplicationPackageStore { ...@@ -138,12 +151,12 @@ class ApplicationPackageStore {
case TargetPlatform.iOS: case TargetPlatform.iOS:
assert(iOS == null); assert(iOS == null);
iOS = new IOSApp(); iOS = new IOSApp.fromBuildConfiguration(config);
break; break;
case TargetPlatform.iOSSimulator: case TargetPlatform.iOSSimulator:
assert(iOSSimulator == null); assert(iOSSimulator == null);
iOSSimulator = new IOSApp(); iOSSimulator = new IOSApp.fromBuildConfiguration(config);
break; break;
case TargetPlatform.mac: case TargetPlatform.mac:
......
...@@ -565,12 +565,16 @@ String _getIOSEngineRevision(ApplicationPackage app) { ...@@ -565,12 +565,16 @@ String _getIOSEngineRevision(ApplicationPackage app) {
} }
Future<bool> _buildIOSXcodeProject(ApplicationPackage app, { bool buildForDevice }) async { Future<bool> _buildIOSXcodeProject(ApplicationPackage app, { bool buildForDevice }) async {
String flutterProjectPath = Directory.current.path;
if (xcodeProjectRequiresUpdate()) { if (xcodeProjectRequiresUpdate()) {
printTrace('Initializing the Xcode project.'); printTrace('Initializing the Xcode project.');
if ((await setupXcodeProjectHarness()) != 0) { if ((await setupXcodeProjectHarness(flutterProjectPath)) != 0) {
printError('Could not initialize the Xcode project.'); printError('Could not initialize the Xcode project.');
return false; return false;
} }
} else {
updateXcodeLocalProperties(flutterProjectPath);
} }
if (!_validateEngineRevision(app)) if (!_validateEngineRevision(app))
......
// 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 "";
}
}
...@@ -91,19 +91,7 @@ Future<bool> _inflateXcodeArchive(String directory, List<int> archiveBytes) asyn ...@@ -91,19 +91,7 @@ Future<bool> _inflateXcodeArchive(String directory, List<int> archiveBytes) asyn
return true; return true;
} }
void _writeUserEditableFilesIfNecessary(String directory) { void updateXcodeLocalProperties(String projectPath) {
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(); 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.');
...@@ -118,7 +106,7 @@ void _setupXcodeProjXcconfig(String filePath) { ...@@ -118,7 +106,7 @@ void _setupXcodeProjXcconfig(String filePath) {
String dartSDKPath = path.normalize(path.join(Platform.resolvedExecutable, '..', '..')); String dartSDKPath = path.normalize(path.join(Platform.resolvedExecutable, '..', '..'));
localsBuffer.writeln('DART_SDK_PATH=$dartSDKPath'); 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.createSync(recursive: true);
localsFile.writeAsStringSync(localsBuffer.toString()); localsFile.writeAsStringSync(localsBuffer.toString());
} }
...@@ -142,9 +130,9 @@ bool xcodeProjectRequiresUpdate() { ...@@ -142,9 +130,9 @@ bool xcodeProjectRequiresUpdate() {
return false; return false;
} }
Future<int> setupXcodeProjectHarness() async { Future<int> setupXcodeProjectHarness(String flutterProjectPath) async {
// Step 1: Fetch the archive from the cloud // 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'); String xcodeprojPath = path.join(iosFilesPath, '.generated');
List<int> archiveBytes = await _fetchXcodeArchive(); List<int> archiveBytes = await _fetchXcodeArchive();
...@@ -160,19 +148,15 @@ Future<int> setupXcodeProjectHarness() async { ...@@ -160,19 +148,15 @@ Future<int> setupXcodeProjectHarness() async {
return 1; return 1;
} }
// Step 3: Setup default user editable files if this is the first run of // Step 3: Populate the Local.xcconfig with project specific paths
// the init command. updateXcodeLocalProperties(flutterProjectPath);
_writeUserEditableFilesIfNecessary(iosFilesPath);
// Step 4: 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')); File revisionFile = new File(path.join(xcodeprojPath, 'REVISION'));
revisionFile.createSync(); revisionFile.createSync();
revisionFile.writeAsStringSync(ArtifactStore.engineRevision); 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('Xcode project created at $xcodeprojPath/.');
printStatus('User editable settings are in $iosFilesPath/.'); printStatus('User editable settings are in $iosFilesPath/.');
...@@ -189,11 +173,11 @@ final String _infoPlistInitialContents = ''' ...@@ -189,11 +173,11 @@ final String _infoPlistInitialContents = '''
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>Runner</string> <string>Runner</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>io.flutter.runner.Runner</string> <string>com.example.{{projectName}}</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>Flutter</string> <string>{{projectName}}</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
......
...@@ -14,8 +14,10 @@ import 'package:mockito/mockito.dart'; ...@@ -14,8 +14,10 @@ import 'package:mockito/mockito.dart';
class MockApplicationPackageStore extends ApplicationPackageStore { class MockApplicationPackageStore extends ApplicationPackageStore {
MockApplicationPackageStore() : super( MockApplicationPackageStore() : super(
android: new AndroidApk(localPath: '/mock/path/to/android/SkyShell.apk'), android: new AndroidApk(localPath: '/mock/path/to/android/SkyShell.apk'),
iOS: new IOSApp(localPath: '/mock/path/to/iOS/SkyShell.app'), iOS: new IOSApp(iosProjectDir: '/mock/path/to/iOS/SkyShell.app',
iOSSimulator: new IOSApp(localPath: '/mock/path/to/iOSSimulator/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 { class MockCompiler extends Mock implements Compiler {
......
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