Commit cc8c78ad authored by Todd Volkert's avatar Todd Volkert

iOS tools cleanup (#4161)

* iOS tools cleanup

1) Fix `flutter install` on both device and simulator to refer to the actual
   bundle and not just the .generated folder
2) Fix `flutter run` on device to actually run vs just installing

Still TODO:
1) Discovered that isAppInstalled on iOS simulator always reports true,
   meaning it'll never actually try to install the app.

Fixes #3947
Fixes #1823
parent 2d726fc0
...@@ -187,7 +187,8 @@ class AndroidDevice extends Device { ...@@ -187,7 +187,8 @@ class AndroidDevice extends Device {
} }
String _getSourceSha1(ApplicationPackage app) { String _getSourceSha1(ApplicationPackage app) {
File shaFile = new File('${app.localPath}.sha1'); AndroidApk apk = app;
File shaFile = new File('${apk.apkPath}.sha1');
return shaFile.existsSync() ? shaFile.readAsStringSync() : ''; return shaFile.existsSync() ? shaFile.readAsStringSync() : '';
} }
...@@ -207,15 +208,16 @@ class AndroidDevice extends Device { ...@@ -207,15 +208,16 @@ class AndroidDevice extends Device {
@override @override
bool installApp(ApplicationPackage app) { bool installApp(ApplicationPackage app) {
if (!FileSystemEntity.isFileSync(app.localPath)) { AndroidApk apk = app;
printError('"${app.localPath}" does not exist.'); if (!FileSystemEntity.isFileSync(apk.apkPath)) {
printError('"${apk.apkPath}" does not exist.');
return false; return false;
} }
if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion()) if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion())
return false; return false;
String installOut = runCheckedSync(adbCommandForDevice(<String>['install', '-r', app.localPath])); String installOut = runCheckedSync(adbCommandForDevice(<String>['install', '-r', apk.apkPath]));
RegExp failureExp = new RegExp(r'^Failure.*$', multiLine: true); RegExp failureExp = new RegExp(r'^Failure.*$', multiLine: true);
String failure = failureExp.stringMatch(installOut); String failure = failureExp.stringMatch(installOut);
if (failure != null) { if (failure != null) {
......
...@@ -11,23 +11,19 @@ import 'build_info.dart'; ...@@ -11,23 +11,19 @@ import 'build_info.dart';
import 'ios/plist_utils.dart'; import 'ios/plist_utils.dart';
abstract class ApplicationPackage { abstract class ApplicationPackage {
/// Path to the actual apk or bundle. /// Path to the package's root folder.
final String localPath; final String rootPath;
/// Package ID from the Android Manifest or equivalent. /// Package ID from the Android Manifest or equivalent.
final String id; final String id;
/// File name of the apk or bundle. ApplicationPackage({this.rootPath, this.id}) {
final String name; assert(rootPath != null);
ApplicationPackage({
String localPath,
this.id
}) : localPath = localPath, name = path.basename(localPath) {
assert(localPath != null);
assert(id != null); assert(id != null);
} }
String get name;
String get displayName => name; String get displayName => name;
@override @override
...@@ -35,14 +31,19 @@ abstract class ApplicationPackage { ...@@ -35,14 +31,19 @@ abstract class ApplicationPackage {
} }
class AndroidApk extends ApplicationPackage { class AndroidApk extends ApplicationPackage {
/// Path to the actual apk file.
final String apkPath;
/// The path to the activity that should be launched. /// The path to the activity that should be launched.
final String launchActivity; final String launchActivity;
AndroidApk({ AndroidApk({
String localPath, String buildDir,
String id, String id,
this.apkPath,
this.launchActivity this.launchActivity
}) : super(localPath: localPath, id: id) { }) : super(rootPath: buildDir, id: id) {
assert(apkPath != null);
assert(launchActivity != null); assert(launchActivity != null);
} }
...@@ -71,16 +72,25 @@ class AndroidApk extends ApplicationPackage { ...@@ -71,16 +72,25 @@ class AndroidApk extends ApplicationPackage {
if (id == null || launchActivity == null) if (id == null || launchActivity == null)
return null; return null;
String localPath = path.join('build', 'app.apk'); return new AndroidApk(
return new AndroidApk(localPath: localPath, id: id, launchActivity: launchActivity); buildDir: 'build',
id: id,
apkPath: path.join('build', 'app.apk'),
launchActivity: launchActivity
);
} }
@override
String get name => path.basename(apkPath);
} }
class IOSApp extends ApplicationPackage { class IOSApp extends ApplicationPackage {
static final String kBundleName = 'Runner.app';
IOSApp({ IOSApp({
String iosProjectDir, String projectDir,
String iosProjectBundleId String projectBundleId
}) : super(localPath: iosProjectDir, id: iosProjectBundleId); }) : super(rootPath: projectDir, id: projectBundleId);
factory IOSApp.fromCurrentDirectory() { factory IOSApp.fromCurrentDirectory() {
if (getCurrentHostPlatform() != HostPlatform.darwin_x64) if (getCurrentHostPlatform() != HostPlatform.darwin_x64)
...@@ -91,12 +101,25 @@ class IOSApp extends ApplicationPackage { ...@@ -91,12 +101,25 @@ class IOSApp extends ApplicationPackage {
if (value == null) if (value == null)
return null; return null;
String projectDir = path.join('ios', '.generated'); return new IOSApp(
return new IOSApp(iosProjectDir: projectDir, iosProjectBundleId: value); projectDir: path.join('ios', '.generated'),
projectBundleId: value
);
} }
@override
String get name => kBundleName;
@override @override
String get displayName => id; String get displayName => id;
String get simulatorBundlePath => _buildAppPath('iphonesimulator');
String get deviceBundlePath => _buildAppPath('iphoneos');
String _buildAppPath(String type) {
return path.join(rootPath, 'build', 'Release-$type', kBundleName);
}
} }
ApplicationPackage getApplicationPackageForPlatform(TargetPlatform platform) { ApplicationPackage getApplicationPackageForPlatform(TargetPlatform platform) {
......
...@@ -6,8 +6,6 @@ import 'dart:async'; ...@@ -6,8 +6,6 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:path/path.dart' as path;
import '../application_package.dart'; import '../application_package.dart';
import '../base/os.dart'; import '../base/os.dart';
import '../base/process.dart'; import '../base/process.dart';
...@@ -127,7 +125,8 @@ class IOSDevice extends Device { ...@@ -127,7 +125,8 @@ class IOSDevice extends Device {
@override @override
bool installApp(ApplicationPackage app) { bool installApp(ApplicationPackage app) {
try { try {
runCheckedSync(<String>[installerPath, '-i', app.localPath]); IOSApp iosApp = app;
runCheckedSync(<String>[installerPath, '-i', iosApp.deviceBundlePath]);
return true; return true;
} catch (e) { } catch (e) {
return false; return false;
...@@ -172,7 +171,8 @@ class IOSDevice extends Device { ...@@ -172,7 +171,8 @@ class IOSDevice extends Device {
} }
// Step 2: Check that the application exists at the specified path. // Step 2: Check that the application exists at the specified path.
Directory bundle = new Directory(path.join(app.localPath, 'build', 'Release-iphoneos', 'Runner.app')); IOSApp iosApp = app;
Directory bundle = new Directory(iosApp.deviceBundlePath);
bool bundleExists = bundle.existsSync(); bool bundleExists = bundle.existsSync();
if (!bundleExists) { if (!bundleExists) {
printError('Could not find the built application bundle at ${bundle.path}.'); printError('Could not find the built application bundle at ${bundle.path}.');
...@@ -187,6 +187,7 @@ class IOSDevice extends Device { ...@@ -187,6 +187,7 @@ class IOSDevice extends Device {
id, id,
'--bundle', '--bundle',
bundle.path, bundle.path,
'--justlaunch',
]); ]);
if (installationResult != 0) { if (installationResult != 0) {
......
...@@ -120,7 +120,7 @@ Future<bool> buildIOSXcodeProject(ApplicationPackage app, BuildMode mode, ...@@ -120,7 +120,7 @@ Future<bool> buildIOSXcodeProject(ApplicationPackage app, BuildMode mode,
// Before the build, all service definitions must be updated and the dylibs // Before the build, all service definitions must be updated and the dylibs
// copied over to a location that is suitable for Xcodebuild to find them. // copied over to a location that is suitable for Xcodebuild to find them.
await _addServicesToBundle(new Directory(app.localPath)); await _addServicesToBundle(new Directory(app.rootPath));
List<String> commands = <String>[ List<String> commands = <String>[
'/usr/bin/env', '/usr/bin/env',
...@@ -151,7 +151,7 @@ Future<bool> buildIOSXcodeProject(ApplicationPackage app, BuildMode mode, ...@@ -151,7 +151,7 @@ Future<bool> buildIOSXcodeProject(ApplicationPackage app, BuildMode mode,
printTrace(commands.join(' ')); printTrace(commands.join(' '));
ProcessResult result = Process.runSync( ProcessResult result = Process.runSync(
commands.first, commands.sublist(1), workingDirectory: app.localPath commands.first, commands.sublist(1), workingDirectory: app.rootPath
); );
if (result.exitCode != 0) { if (result.exitCode != 0) {
...@@ -199,7 +199,7 @@ bool _validateEngineRevision(ApplicationPackage app) { ...@@ -199,7 +199,7 @@ bool _validateEngineRevision(ApplicationPackage app) {
} }
String _getIOSEngineRevision(ApplicationPackage app) { String _getIOSEngineRevision(ApplicationPackage app) {
File revisionFile = new File(path.join(app.localPath, 'REVISION')); File revisionFile = new File(path.join(app.rootPath, 'REVISION'));
if (revisionFile.existsSync()) { if (revisionFile.existsSync()) {
// The format is 'REVISION-mode'. We only need the revision. // The format is 'REVISION-mode'. We only need the revision.
String revisionStamp = revisionFile.readAsStringSync().trim(); String revisionStamp = revisionFile.readAsStringSync().trim();
......
...@@ -363,7 +363,8 @@ class IOSSimulator extends Device { ...@@ -363,7 +363,8 @@ class IOSSimulator extends Device {
@override @override
bool installApp(ApplicationPackage app) { bool installApp(ApplicationPackage app) {
try { try {
SimControl.instance.install(id, app.localPath); IOSApp iosApp = app;
SimControl.instance.install(id, iosApp.simulatorBundlePath);
return true; return true;
} catch (e) { } catch (e) {
return false; return false;
...@@ -424,6 +425,7 @@ class IOSSimulator extends Device { ...@@ -424,6 +425,7 @@ class IOSSimulator extends Device {
@override @override
bool isAppInstalled(ApplicationPackage app) { bool isAppInstalled(ApplicationPackage app) {
try { try {
// TODO(tvolkert): This logic is wrong; simulatorHomeDirectory always exists
String simulatorHomeDirectory = _getSimulatorAppHomeDirectory(app); String simulatorHomeDirectory = _getSimulatorAppHomeDirectory(app);
return FileSystemEntity.isDirectorySync(simulatorHomeDirectory); return FileSystemEntity.isDirectorySync(simulatorHomeDirectory);
} catch (e) { } catch (e) {
...@@ -540,7 +542,8 @@ class IOSSimulator extends Device { ...@@ -540,7 +542,8 @@ class IOSSimulator extends Device {
} }
// Step 2: Assert that the Xcode project was successfully built. // Step 2: Assert that the Xcode project was successfully built.
Directory bundle = new Directory(path.join(app.localPath, 'build', 'Release-iphonesimulator', 'Runner.app')); IOSApp iosApp = app;
Directory bundle = new Directory(iosApp.simulatorBundlePath);
bool bundleExists = await bundle.exists(); bool bundleExists = await bundle.exists();
if (!bundleExists) { if (!bundleExists) {
printError('Could not find the built application bundle at ${bundle.path}.'); printError('Could not find the built application bundle at ${bundle.path}.');
......
...@@ -16,13 +16,14 @@ import 'package:mockito/mockito.dart'; ...@@ -16,13 +16,14 @@ import 'package:mockito/mockito.dart';
class MockApplicationPackageStore extends ApplicationPackageStore { class MockApplicationPackageStore extends ApplicationPackageStore {
MockApplicationPackageStore() : super( MockApplicationPackageStore() : super(
android: new AndroidApk( android: new AndroidApk(
localPath: '/mock/path/to/android/SkyShell.apk', buildDir: '/mock/path/to/android',
id: 'io.flutter.android.mock', id: 'io.flutter.android.mock',
apkPath: '/mock/path/to/android/SkyShell.apk',
launchActivity: 'io.flutter.android.mock.MockActivity' launchActivity: 'io.flutter.android.mock.MockActivity'
), ),
iOS: new IOSApp( iOS: new IOSApp(
iosProjectDir: '/mock/path/to/iOS/SkyShell.app', projectDir: '/mock/path/to/iOS/SkyShell.app',
iosProjectBundleId: 'io.flutter.ios.mock' projectBundleId: 'io.flutter.ios.mock'
) )
); );
} }
......
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