diff --git a/dev/manual_tests/android/AndroidManifest.xml b/dev/manual_tests/android/AndroidManifest.xml new file mode 100644 index 0000000000..98a4eaf553 --- /dev/null +++ b/dev/manual_tests/android/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/examples/hello_world/android/AndroidManifest.xml b/examples/hello_world/android/AndroidManifest.xml new file mode 100644 index 0000000000..6d96b4e727 --- /dev/null +++ b/examples/hello_world/android/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/examples/layers/android/AndroidManifest.xml b/examples/layers/android/AndroidManifest.xml new file mode 100644 index 0000000000..e81d6863a6 --- /dev/null +++ b/examples/layers/android/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart index b5a5bac43d..1b233b645e 100644 --- a/packages/flutter_tools/lib/src/application_package.dart +++ b/packages/flutter_tools/lib/src/application_package.dart @@ -8,7 +8,6 @@ import 'dart:io'; import 'package:path/path.dart' as path; import 'package:xml/xml.dart' as xml; -import 'artifacts.dart'; import 'build_configuration.dart'; import 'ios/plist_utils.dart'; @@ -36,32 +35,23 @@ abstract class ApplicationPackage { } class AndroidApk extends ApplicationPackage { - static const String _defaultName = 'SkyShell.apk'; - static const String _defaultId = 'org.domokit.sky.shell'; - static const String _defaultLaunchActivity = '$_defaultId/$_defaultId.SkyActivity'; - static const String _defaultManifestPath = 'android/AndroidManifest.xml'; - static const String _defaultOutputPath = 'build/app.apk'; - /// The path to the activity that should be launched. - /// Defaults to 'org.domokit.sky.shell/org.domokit.sky.shell.SkyActivity' final String launchActivity; AndroidApk({ String localPath, - String id: _defaultId, - this.launchActivity: _defaultLaunchActivity + String id, + this.launchActivity }) : super(localPath: localPath, id: id) { assert(launchActivity != null); } /// Creates a new AndroidApk based on the information in the Android manifest. - static AndroidApk getCustomApk({ - String localPath: _defaultOutputPath, - String manifest: _defaultManifestPath - }) { - if (!FileSystemEntity.isFileSync(manifest)) + factory AndroidApk.fromBuildConfiguration(BuildConfiguration config) { + String manifestPath = path.join('android', 'AndroidManifest.xml'); + if (!FileSystemEntity.isFileSync(manifestPath)) return null; - String manifestString = new File(manifest).readAsStringSync(); + String manifestString = new File(manifestPath).readAsStringSync(); xml.XmlDocument document = xml.parse(manifestString); Iterable manifests = document.findElements('manifest'); @@ -81,6 +71,7 @@ class AndroidApk extends ApplicationPackage { if (id == null || launchActivity == null) return null; + String localPath = path.join('build', 'app.apk'); return new AndroidApk(localPath: localPath, id: id, launchActivity: launchActivity); } } @@ -95,12 +86,12 @@ class IOSApp extends ApplicationPackage { if (getCurrentHostPlatform() != HostPlatform.mac) return null; - String plistPath = path.join("ios", "Info.plist"); + String plistPath = path.join('ios', 'Info.plist'); String value = getValueFromFile(plistPath, kCFBundleIdentifierKey); if (value == null) return null; - String projectDir = path.join("ios", ".generated"); + String projectDir = path.join('ios', '.generated'); return new IOSApp(iosProjectDir: projectDir, iosProjectBundleId: value); } @@ -134,20 +125,7 @@ class ApplicationPackageStore { switch (config.targetPlatform) { case TargetPlatform.android_arm: assert(android == null); - android = AndroidApk.getCustomApk(); - // Fall back to the prebuilt or engine-provided apk if we can't build - // a custom one. - // TODO(mpcomplete): we should remove both these fallbacks. - if (android != null) { - break; - } else if (config.type != BuildType.prebuilt) { - String localPath = path.join(config.buildDir, 'apks', AndroidApk._defaultName); - android = new AndroidApk(localPath: localPath); - } else { - Artifact artifact = ArtifactStore.getArtifact( - type: ArtifactType.shell, targetPlatform: TargetPlatform.android_arm); - android = new AndroidApk(localPath: await ArtifactStore.getPath(artifact)); - } + android = new AndroidApk.fromBuildConfiguration(config); break; case TargetPlatform.ios_arm: diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index 19680d4fe0..db27a1961f 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -74,13 +74,7 @@ class Artifact { class ArtifactStore { static const List knownArtifacts = const [ const Artifact._( - name: 'Sky Shell', - fileName: 'SkyShell.apk', - type: ArtifactType.shell, - targetPlatform: TargetPlatform.android_arm - ), - const Artifact._( - name: 'Sky Shell', + name: 'Flutter Tester', fileName: 'sky_shell', type: ArtifactType.shell, targetPlatform: TargetPlatform.linux_x64 diff --git a/packages/flutter_tools/lib/src/commands/apk.dart b/packages/flutter_tools/lib/src/commands/apk.dart index 43114e84c7..d6dc01be74 100644 --- a/packages/flutter_tools/lib/src/commands/apk.dart +++ b/packages/flutter_tools/lib/src/commands/apk.dart @@ -242,7 +242,7 @@ Future<_ApkComponents> _findApkComponents( if (!components.resources.existsSync()) { // TODO(eseidel): This level should be higher when path is manually set. - printStatus('Can not locate Resources: ${components.resources}, ignoring.'); + printStatus('Cannot locate Resources: ${components.resources}, ignoring.'); components.resources = null; } @@ -250,7 +250,7 @@ Future<_ApkComponents> _findApkComponents( components.manifest, components.icuData, components.libSkyShell, components.debugKeystore ]..addAll(components.jars)) { if (!f.existsSync()) { - printError('Can not locate file: ${f.path}'); + printError('Cannot locate file: ${f.path}'); return null; } } @@ -453,8 +453,8 @@ Future build( String target: '' }) async { if (!FileSystemEntity.isFileSync(_kDefaultAndroidManifestPath)) { - printStatus('Using pre-built SkyShell.apk.'); - return 0; + printError('Cannot build APK. Missing $_kDefaultAndroidManifestPath.'); + return 1; } int result = await buildAndroid( diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 26c7dfc171..09f627e471 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -129,6 +129,18 @@ class RunCommand extends RunCommandBase { } } +String _getMissingPackageHintForPlatform(TargetPlatform platform) { + switch (platform) { + case TargetPlatform.android_arm: + return 'Is your project missing an android/AndroidManifest.xml?'; + case TargetPlatform.ios_arm: + case TargetPlatform.ios_x64: + return 'Is your project missing an ios/Info.plist?'; + default: + return null; + } +} + Future startApp( Device device, ApplicationPackageStore applicationPackages, @@ -157,7 +169,11 @@ Future startApp( ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform); if (package == null) { - printError('No application found for ${device.platform}.'); + String message = 'No application found for ${device.platform}.'; + String hint = _getMissingPackageHintForPlatform(device.platform); + if (hint != null) + message += '\n$hint'; + printError(message); return 1; } diff --git a/packages/flutter_tools/test/src/mocks.dart b/packages/flutter_tools/test/src/mocks.dart index 62d6c369eb..52db59ea99 100644 --- a/packages/flutter_tools/test/src/mocks.dart +++ b/packages/flutter_tools/test/src/mocks.dart @@ -16,7 +16,11 @@ import 'package:mockito/mockito.dart'; class MockApplicationPackageStore extends ApplicationPackageStore { MockApplicationPackageStore() : super( - android: new AndroidApk(localPath: '/mock/path/to/android/SkyShell.apk'), + android: new AndroidApk( + localPath: '/mock/path/to/android/SkyShell.apk', + id: 'io.flutter.android.mock', + launchActivity: 'io.flutter.android.mock.MockActivity' + ), iOS: new IOSApp( iosProjectDir: '/mock/path/to/iOS/SkyShell.app', iosProjectBundleId: 'io.flutter.ios.mock'