Stop using a prebuilt APK
Instead, require an AndroidManifest.xml and always build an APK. Fixes #2517
This commit is contained in:
parent
cb62071882
commit
e2744e9a30
19
dev/manual_tests/android/AndroidManifest.xml
Normal file
19
dev/manual_tests/android/AndroidManifest.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.flutter.tests.ManualTests" android:versionCode="1" android:versionName="0.0.1">
|
||||
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application android:label="Flutter Manual Tests" android:name="org.domokit.sky.shell.SkyApplication">
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:hardwareAccelerated="true" android:launchMode="singleTask" android:name="org.domokit.sky.shell.SkyActivity" android:theme="@android:style/Theme.Black.NoTitleBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
19
examples/hello_world/android/AndroidManifest.xml
Normal file
19
examples/hello_world/android/AndroidManifest.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.flutter.examples.HelloWorld" android:versionCode="1" android:versionName="0.0.1">
|
||||
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application android:label="Flutter Hello" android:name="org.domokit.sky.shell.SkyApplication">
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:hardwareAccelerated="true" android:launchMode="singleTask" android:name="org.domokit.sky.shell.SkyActivity" android:theme="@android:style/Theme.Black.NoTitleBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
19
examples/layers/android/AndroidManifest.xml
Normal file
19
examples/layers/android/AndroidManifest.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.flutter.examples.Layers" android:versionCode="1" android:versionName="0.0.1">
|
||||
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application android:label="Flutter Layers" android:name="org.domokit.sky.shell.SkyApplication">
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:hardwareAccelerated="true" android:launchMode="singleTask" android:name="org.domokit.sky.shell.SkyActivity" android:theme="@android:style/Theme.Black.NoTitleBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
@ -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<xml.XmlElement> 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:
|
||||
|
@ -74,13 +74,7 @@ class Artifact {
|
||||
class ArtifactStore {
|
||||
static const List<Artifact> knownArtifacts = const <Artifact>[
|
||||
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
|
||||
|
@ -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<int> 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(
|
||||
|
@ -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<int> startApp(
|
||||
Device device,
|
||||
ApplicationPackageStore applicationPackages,
|
||||
@ -157,7 +169,11 @@ Future<int> 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;
|
||||
}
|
||||
|
||||
|
@ -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'
|
||||
|
Loading…
x
Reference in New Issue
Block a user