mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
Add a 'flutter ios --init' command that fetches the Xcode project from the cloud and configures it for a given flutter project
This commit is contained in:
parent
1d16ebff05
commit
08fdf99fea
|
@ -17,6 +17,7 @@ import 'src/commands/cache.dart';
|
|||
import 'src/commands/daemon.dart';
|
||||
import 'src/commands/init.dart';
|
||||
import 'src/commands/install.dart';
|
||||
import 'src/commands/ios.dart';
|
||||
import 'src/commands/list.dart';
|
||||
import 'src/commands/listen.dart';
|
||||
import 'src/commands/logs.dart';
|
||||
|
@ -62,6 +63,7 @@ Future main(List<String> args) async {
|
|||
..addCommand(new DaemonCommand())
|
||||
..addCommand(new InitCommand())
|
||||
..addCommand(new InstallCommand())
|
||||
..addCommand(new IOSCommand())
|
||||
..addCommand(new ListCommand())
|
||||
..addCommand(new ListenCommand())
|
||||
..addCommand(new LogsCommand())
|
||||
|
|
155
packages/flutter_tools/lib/src/commands/ios.dart
Normal file
155
packages/flutter_tools/lib/src/commands/ios.dart
Normal file
|
@ -0,0 +1,155 @@
|
|||
// Copyright 2015 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 "dart:async";
|
||||
import "dart:io";
|
||||
|
||||
import "package:path/path.dart" as path;
|
||||
|
||||
import "../runner/flutter_command_runner.dart";
|
||||
import "../runner/flutter_command.dart";
|
||||
|
||||
class IOSCommand extends FlutterCommand {
|
||||
final String name = "ios";
|
||||
|
||||
final String description = "Commands for creating and updating Flutter iOS projects";
|
||||
|
||||
final bool requiresProjectRoot = true;
|
||||
|
||||
IOSCommand() {
|
||||
argParser.addFlag('init', help: 'Initialize the Xcode project for building the iOS application');
|
||||
}
|
||||
|
||||
static Uri _xcodeProjectUri(String revision) {
|
||||
return Uri.parse("https://storage.googleapis.com/flutter_infra/flutter/${revision}/ios/FlutterXcode.zip");
|
||||
}
|
||||
|
||||
Future<List<int>> _fetchXcodeArchive() async {
|
||||
print("Fetching the Xcode project archive from the cloud...");
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
// TODO(chinmaygarde): Currently, engine releases are not tied to the release of the Xcode project
|
||||
// archive. So use a "Current" tag. This will need to be replaced once releases
|
||||
// are in lockstep with the engine
|
||||
HttpClientRequest request = await client.getUrl(_xcodeProjectUri("Current"));
|
||||
HttpClientResponse response = await request.close();
|
||||
|
||||
if (response.statusCode != 200)
|
||||
throw new Exception(response.reasonPhrase);
|
||||
|
||||
BytesBuilder bytesBuilder = new BytesBuilder(copy: false);
|
||||
await for (List<int> chunk in response)
|
||||
bytesBuilder.add(chunk);
|
||||
|
||||
return bytesBuilder.takeBytes();
|
||||
}
|
||||
|
||||
Future<bool> _inflateXcodeArchive(String directory, List<int> archiveBytes) async {
|
||||
print("Unzipping Xcode project to local directory...");
|
||||
|
||||
if (archiveBytes.isEmpty)
|
||||
return false;
|
||||
|
||||
// We cannot use ArchiveFile because this archive contains file that are exectuable
|
||||
// and there is currently no provision to modify file permissions during
|
||||
// or after creation. See https://github.com/dart-lang/sdk/issues/15078
|
||||
// So we depend on the platform to unzip the archive for us.
|
||||
|
||||
Directory tempDir = await Directory.systemTemp.create();
|
||||
File tempFile = await new File(path.join(tempDir.path, "FlutterXcode.zip")).create();
|
||||
IOSink writeSink = tempFile.openWrite();
|
||||
writeSink.add(archiveBytes);
|
||||
await writeSink.close();
|
||||
|
||||
ProcessResult result = await Process.run('/usr/bin/unzip', [tempFile.path, '-d', directory]);
|
||||
|
||||
// Cleanup the temp directory after unzipping
|
||||
await Process.run('/bin/rm', ['rf', tempDir.path]);
|
||||
|
||||
if (result.exitCode != 0)
|
||||
return false;
|
||||
|
||||
Directory flutterDir = new Directory(path.join(directory, 'Flutter'));
|
||||
bool flutterDirExists = await flutterDir.exists();
|
||||
if (!flutterDirExists)
|
||||
return false;
|
||||
|
||||
// Move contents of the Flutter directory one level up
|
||||
// There is no dart:io API to do this. See https://github.com/dart-lang/sdk/issues/8148
|
||||
|
||||
bool moveFailed = false;
|
||||
for (FileSystemEntity file in flutterDir.listSync()) {
|
||||
ProcessResult result = await Process.run('/bin/mv', [file.path, directory]);
|
||||
moveFailed = result.exitCode != 0;
|
||||
if (moveFailed)
|
||||
break;
|
||||
}
|
||||
|
||||
ProcessResult rmResult = await Process.run('/bin/rm', ["-rf", flutterDir.path]);
|
||||
|
||||
return !moveFailed && rmResult.exitCode == 0;
|
||||
}
|
||||
|
||||
Future<bool> _setupXcodeProjXcconfig(String filePath) async {
|
||||
StringBuffer localsBuffer = new StringBuffer();
|
||||
|
||||
localsBuffer.writeln("// Generated. Do not edit or check into version control!!");
|
||||
localsBuffer.writeln("// Recreate using `flutter ios`");
|
||||
|
||||
String flutterRoot = path.normalize(Platform.environment[kFlutterRootEnvironmentVariableName]);
|
||||
localsBuffer.writeln("FLUTTER_ROOT=${flutterRoot}");
|
||||
|
||||
// This holds because requiresProjectRoot is true for this command
|
||||
String applicationRoot = path.normalize(Directory.current.path);
|
||||
localsBuffer.writeln("FLUTTER_APPLICATION_PATH=${applicationRoot}");
|
||||
|
||||
String dartSDKPath = path.normalize(path.join(Platform.resolvedExecutable, "..", ".."));
|
||||
localsBuffer.writeln("DART_SDK_PATH=${dartSDKPath}");
|
||||
|
||||
File localsFile = new File(filePath);
|
||||
await localsFile.create(recursive: true);
|
||||
await localsFile.writeAsString(localsBuffer.toString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<int> _runInitCommand() async {
|
||||
// Step 1: Fetch the archive from the cloud
|
||||
String xcodeprojPath = path.join(Directory.current.path, "ios");
|
||||
List<int> archiveBytes = await _fetchXcodeArchive();
|
||||
|
||||
// Step 2: Inflate the archive into the user project directory
|
||||
bool result = await _inflateXcodeArchive(xcodeprojPath, archiveBytes);
|
||||
if (!result) {
|
||||
print("Could not fetch the Xcode project from the cloud...");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Step 3: Populate the Local.xcconfig with project specific paths
|
||||
result = await _setupXcodeProjXcconfig(path.join(xcodeprojPath, "Local.xcconfig"));
|
||||
if (!result) {
|
||||
print("Could not setup local properties file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Step 4: Launch Xcode and let the user edit plist, resources, provisioning, etc.
|
||||
print("Launching project in Xcode...");
|
||||
ProcessResult launch = await Process.run("/usr/bin/open", ["ios/FlutterApplication.xcodeproj"]);
|
||||
return launch.exitCode;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> runInProject() async {
|
||||
if (!Platform.isMacOS) {
|
||||
print("iOS specific commands may only be run on a Mac.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argResults['init'])
|
||||
return _runInitCommand();
|
||||
|
||||
print("No flags specified...");
|
||||
return -1;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue