Unverified Commit d89a6b54 authored by Mikkel Nygaard Ravn's avatar Mikkel Nygaard Ravn Committed by GitHub

Add module template for Android (#18697)

parent f5f05511
......@@ -141,16 +141,13 @@ void handleKnownGradleExceptions(String exceptionString) {
}
}
String _locateProjectGradlew({ bool ensureExecutable = true }) {
final String path = fs.path.join(
'android',
String _locateGradlewExecutable(Directory directory) {
final File gradle = directory.childFile(
platform.isWindows ? 'gradlew.bat' : 'gradlew',
);
if (fs.isFileSync(path)) {
final File gradle = fs.file(path);
if (ensureExecutable)
os.makeExecutable(gradle);
if (gradle.existsSync()) {
os.makeExecutable(gradle);
return gradle.absolute.path;
} else {
return null;
......@@ -165,11 +162,12 @@ Future<String> _ensureGradle() async {
// Note: Gradle may be bootstrapped and possibly downloaded as a side-effect
// of validating the Gradle executable. This may take several seconds.
Future<String> _initializeGradle() async {
final Directory android = fs.directory('android');
final Status status = logger.startProgress('Initializing gradle...', expectSlowOperation: true);
String gradle = _locateProjectGradlew();
String gradle = _locateGradlewExecutable(android);
if (gradle == null) {
_injectGradleWrapper();
gradle = _locateProjectGradlew();
injectGradleWrapper(android);
gradle = _locateGradlewExecutable(android);
}
if (gradle == null)
throwToolExit('Unable to locate gradlew script');
......@@ -181,11 +179,13 @@ Future<String> _initializeGradle() async {
return gradle;
}
void _injectGradleWrapper() {
copyDirectorySync(cache.getArtifactDirectory('gradle_wrapper'), fs.directory('android'));
final String propertiesPath = fs.path.join('android', 'gradle', 'wrapper', 'gradle-wrapper.properties');
if (!fs.file(propertiesPath).existsSync()) {
fs.file(propertiesPath).writeAsStringSync('''
/// Injects the Gradle wrapper into the specified directory.
void injectGradleWrapper(Directory directory) {
copyDirectorySync(cache.getArtifactDirectory('gradle_wrapper'), directory);
_locateGradlewExecutable(directory);
final File propertiesFile = directory.childFile(fs.path.join('gradle', 'wrapper', 'gradle-wrapper.properties'));
if (!propertiesFile.existsSync()) {
propertiesFile.writeAsStringSync('''
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
......@@ -196,14 +196,31 @@ distributionUrl=https\\://services.gradle.org/distributions/gradle-$gradleVersio
}
}
/// Create android/local.properties if needed, and update Flutter settings.
/// Overwrite android/local.properties in the specified Flutter project, if needed.
///
/// Throws, if `pubspec.yaml` or Android SDK cannot be located.
Future<void> updateLocalProperties({String projectPath, BuildInfo buildInfo}) async {
final File localProperties = (projectPath == null)
? fs.file(fs.path.join('android', 'local.properties'))
: fs.file(fs.path.join(projectPath, 'android', 'local.properties'));
final Directory android = (projectPath == null)
? fs.directory('android')
: fs.directory(fs.path.join(projectPath, 'android'));
final String flutterManifest = (projectPath == null)
? fs.path.join(bundle.defaultManifestPath)
: fs.path.join(projectPath, bundle.defaultManifestPath);
if (androidSdk == null) {
throwToolExit('Unable to locate Android SDK. Please run `flutter doctor` for more details.');
}
FlutterManifest manifest;
try {
manifest = await FlutterManifest.createFromPath(flutterManifest);
} catch (error) {
throwToolExit('Failed to load pubspec.yaml: $error');
}
updateLocalPropertiesSync(android, manifest, buildInfo);
}
/// Overwrite local.properties in the specified directory, if needed.
void updateLocalPropertiesSync(Directory android, FlutterManifest manifest, [BuildInfo buildInfo]) {
final File localProperties = android.childFile('local.properties');
bool changed = false;
SettingsFile settings;
......@@ -211,40 +228,27 @@ Future<void> updateLocalProperties({String projectPath, BuildInfo buildInfo}) as
settings = new SettingsFile.parseFromFile(localProperties);
} else {
settings = new SettingsFile();
if (androidSdk == null) {
throwToolExit('Unable to locate Android SDK. Please run `flutter doctor` for more details.');
}
settings.values['sdk.dir'] = escapePath(androidSdk.directory);
changed = true;
}
final String escapedRoot = escapePath(Cache.flutterRoot);
if (changed || settings.values['flutter.sdk'] != escapedRoot) {
settings.values['flutter.sdk'] = escapedRoot;
changed = true;
}
if (buildInfo != null && settings.values['flutter.buildMode'] != buildInfo.modeName) {
settings.values['flutter.buildMode'] = buildInfo.modeName;
changed = true;
}
FlutterManifest manifest;
try {
manifest = await FlutterManifest.createFromPath(flutterManifest);
} catch (error) {
throwToolExit('Failed to load pubspec.yaml: $error');
void changeIfNecessary(String key, String value) {
if (settings.values[key] != value) {
settings.values[key] = value;
changed = true;
}
}
if (androidSdk != null)
changeIfNecessary('sdk.dir', escapePath(androidSdk.directory));
changeIfNecessary('flutter.sdk', escapePath(Cache.flutterRoot));
if (buildInfo != null)
changeIfNecessary('flutter.buildMode', buildInfo.modeName);
final String buildName = buildInfo?.buildName ?? manifest.buildName;
if (buildName != null) {
settings.values['flutter.versionName'] = buildName;
changed = true;
}
if (buildName != null)
changeIfNecessary('flutter.versionName', buildName);
final int buildNumber = buildInfo?.buildNumber ?? manifest.buildNumber;
if (buildNumber != null) {
settings.values['flutter.versionCode'] = '$buildNumber';
changed = true;
}
if (buildNumber != null)
changeIfNecessary('flutter.versionCode', '$buildNumber');
if (changed)
settings.writeContents(localProperties);
......
......@@ -44,7 +44,7 @@ class CreateCommand extends FlutterCommand {
argParser.addOption(
'template',
abbr: 't',
allowed: <String>['app', 'package', 'plugin'],
allowed: <String>['app', 'module', 'package', 'plugin'],
help: 'Specify the type of project to create.',
valueHelp: 'type',
allowedHelp: <String, String>{
......@@ -124,6 +124,7 @@ class CreateCommand extends FlutterCommand {
throwToolExit('Unable to find package:flutter_driver in $flutterDriverPackagePath', exitCode: 2);
final String template = argResults['template'];
final bool generateModule = template == 'module';
final bool generatePlugin = template == 'plugin';
final bool generatePackage = template == 'package';
......@@ -172,6 +173,9 @@ class CreateCommand extends FlutterCommand {
case 'app':
generatedFileCount += await _generateApp(dirPath, templateContext);
break;
case 'module':
generatedFileCount += await _generateModule(dirPath, templateContext);
break;
case 'package':
generatedFileCount += await _generatePackage(dirPath, templateContext);
break;
......@@ -185,6 +189,9 @@ class CreateCommand extends FlutterCommand {
if (generatePackage) {
final String relativePath = fs.path.relative(dirPath);
printStatus('Your package code is in lib/${templateContext['projectName']}.dart in the $relativePath directory.');
} else if (generateModule) {
final String relativePath = fs.path.relative(dirPath);
printStatus('Your module code is in lib/main.dart in the $relativePath directory.');
} else {
// Run doctor; tell the user the next steps.
final String relativeAppPath = fs.path.relative(appPath);
......@@ -226,6 +233,25 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
}
}
Future<int> _generateModule(String dirPath, Map<String, dynamic> templateContext) async {
int generatedCount = 0;
final String description = argResults.wasParsed('description')
? argResults['description']
: 'A new flutter module project.';
templateContext['description'] = description;
generatedCount += _renderTemplate(fs.path.join('module', 'common'), dirPath, templateContext);
if (argResults['pub']) {
await pubGet(
context: PubContext.create,
directory: dirPath,
offline: argResults['offline'],
);
final FlutterProject project = new FlutterProject(fs.directory(dirPath));
await project.ensureReadyForPlatformSpecificTooling();
}
return generatedCount;
}
Future<int> _generatePackage(String dirPath, Map<String, dynamic> templateContext) async {
int generatedCount = 0;
final String description = argResults.wasParsed('description')
......
......@@ -87,6 +87,23 @@ class FlutterManifest {
return _flutterDescriptor['uses-material-design'] ?? false;
}
/// Properties defining how to expose this Flutter project as a module
/// for integration into an unspecified host app.
Map<String, dynamic> get moduleDescriptor {
return _flutterDescriptor.containsKey('module')
? _flutterDescriptor['module'] ?? const <String, dynamic>{}
: null;
}
/// True if this manifest declares a Flutter module project.
///
/// A Flutter project is considered a module when it has a `module:`
/// descriptor. A Flutter module project supports integration into an
/// existing host app.
///
/// Such a project can be created using `flutter create -t module`.
bool get isModule => moduleDescriptor != null;
List<Map<String, dynamic>> get fontsDescriptor {
return _flutterDescriptor['fonts'] ?? const <Map<String, dynamic>>[];
}
......
......@@ -51,6 +51,8 @@ Future<void> generateXcodeProperties(String projectPath) async {
///
/// targetOverride: Optional parameter, if null or unspecified the default value
/// from xcode_backend.sh is used 'lib/main.dart'.
///
/// Returns the number of files written.
Future<void> updateGeneratedXcodeProperties({
@required String projectPath,
@required BuildInfo buildInfo,
......
......@@ -148,7 +148,7 @@ void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) {
final String pluginRegistry =
new mustache.Template(_androidPluginRegistryTemplate).renderString(context);
final String javaSourcePath = fs.path.join(directory, 'android', 'app', 'src', 'main', 'java');
final String javaSourcePath = fs.path.join(directory, 'src', 'main', 'java');
final Directory registryDirectory =
fs.directory(fs.path.join(javaSourcePath, 'io', 'flutter', 'plugins'));
registryDirectory.createSync(recursive: true);
......@@ -233,9 +233,11 @@ void injectPlugins({String directory}) {
directory ??= fs.currentDirectory.path;
final List<Plugin> plugins = _findPlugins(directory);
final bool changed = _writeFlutterPluginsList(directory, plugins);
if (fs.isDirectorySync(fs.path.join(directory, 'android')))
_writeAndroidPluginRegistrant(directory, plugins);
if (fs.isDirectorySync(fs.path.join(directory, '.android', 'Flutter'))) {
_writeAndroidPluginRegistrant(fs.path.join(directory, '.android', 'Flutter'), plugins);
} else if (fs.isDirectorySync(fs.path.join(directory, 'android', 'app'))) {
_writeAndroidPluginRegistrant(fs.path.join(directory, 'android', 'app'), plugins);
}
if (fs.isDirectorySync(fs.path.join(directory, 'ios'))) {
_writeIOSPluginRegistrant(directory, plugins);
final CocoaPods cocoaPods = new CocoaPods();
......
......@@ -5,10 +5,14 @@
import 'dart:async';
import 'dart:convert';
import 'android/gradle.dart' as gradle;
import 'base/file_system.dart';
import 'ios/xcodeproj.dart';
import 'cache.dart';
import 'flutter_manifest.dart';
import 'ios/xcodeproj.dart' as xcode;
import 'plugins.dart';
import 'template.dart';
/// Represents the contents of a Flutter project at the specified [directory].
class FlutterProject {
......@@ -47,6 +51,9 @@ class FlutterProject {
/// The Android sub project of this project.
AndroidProject get android => new AndroidProject(directory.childDirectory('android'));
/// The generated AndroidModule sub project of this module project.
AndroidModuleProject get androidModule => new AndroidModuleProject(directory.childDirectory('.android'));
/// Returns true if this project has an example application
bool get hasExampleApp => directory.childDirectory('example').childFile('pubspec.yaml').existsSync();
......@@ -54,13 +61,19 @@ class FlutterProject {
FlutterProject get example => new FlutterProject(directory.childDirectory('example'));
/// Generates project files necessary to make Gradle builds work on Android
/// and CocoaPods+Xcode work on iOS, for app projects only
/// and CocoaPods+Xcode work on iOS, for app and module projects only.
///
/// Returns the number of files written.
Future<void> ensureReadyForPlatformSpecificTooling() async {
if (!directory.existsSync() || hasExampleApp) {
return;
return 0;
}
final FlutterManifest manifest = await FlutterManifest.createFromPath(directory.childFile('pubspec.yaml').path);
if (manifest.isModule) {
await androidModule.ensureReadyForPlatformSpecificTooling(manifest);
}
injectPlugins(directory: directory.path);
await generateXcodeProperties(directory.path);
await xcode.generateXcodeProperties(directory.path);
}
}
......@@ -97,6 +110,36 @@ class AndroidProject {
}
}
/// Represents the contents of the .android-generated/ folder of a Flutter module
/// project.
class AndroidModuleProject {
AndroidModuleProject(this.directory);
final Directory directory;
Future<void> ensureReadyForPlatformSpecificTooling(FlutterManifest manifest) async {
if (_shouldRegenerate()) {
final Template template = new Template.fromName(fs.path.join('module', 'android'));
template.render(directory, <String, dynamic>{
'androidIdentifier': manifest.moduleDescriptor['androidPackage'],
}, printStatusWhenWriting: false);
gradle.injectGradleWrapper(directory);
}
gradle.updateLocalPropertiesSync(directory, manifest);
}
bool _shouldRegenerate() {
final File flutterToolsStamp = Cache.instance.getStampFileFor('flutter_tools');
final File buildDotGradleFile = directory.childFile('build.gradle');
if (!buildDotGradleFile.existsSync())
return true;
return flutterToolsStamp.existsSync() &&
flutterToolsStamp
.lastModifiedSync()
.isAfter(buildDotGradleFile.lastModifiedSync());
}
}
/// Asynchronously returns the first line-based match for [regExp] in [file].
///
/// Assumes UTF8 encoding.
......
......@@ -66,6 +66,7 @@ class Template {
Directory destination,
Map<String, dynamic> context, {
bool overwriteExisting = true,
bool printStatusWhenWriting = true,
}) {
destination.createSync(recursive: true);
int fileCount = 0;
......@@ -117,14 +118,17 @@ class Template {
if (finalDestinationFile.existsSync()) {
if (overwriteExisting) {
finalDestinationFile.deleteSync(recursive: true);
printStatus(' $relativePathForLogging (overwritten)');
if (printStatusWhenWriting)
printStatus(' $relativePathForLogging (overwritten)');
} else {
// The file exists but we cannot overwrite it, move on.
printTrace(' $relativePathForLogging (existing - skipped)');
if (printStatusWhenWriting)
printTrace(' $relativePathForLogging (existing - skipped)');
return;
}
} else {
printStatus(' $relativePathForLogging (created)');
if (printStatusWhenWriting)
printStatus(' $relativePathForLogging (created)');
}
fileCount++;
......
......@@ -43,6 +43,13 @@
}
}
},
"module": {
"type": "object",
"additionalProperties": false,
"properties": {
"androidPackage": { "type": "string" }
}
},
"plugin": {
"type": "object",
"additionalProperties": false,
......
// Generated file. Do not edit.
def localProperties = new Properties()
def localPropertiesFile = new File(buildscript.sourceFile.parentFile.parentFile, 'local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
throw new GradleException("versionCode not found. Define flutter.versionCode in the local.properties file.")
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
throw new GradleException("versionName not found. Define flutter.versionName in the local.properties file.")
}
apply plugin: 'com.android.library'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 16
targetSdkVersion 27
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
flutter {
source '../..'
}
dependencies {
testImplementation 'junit:junit:4.12'
implementation 'com.android.support:support-v13:27.1.1'
}
<!-- Generated file. Do not edit. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="{{androidIdentifier}}">
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
package io.flutter.facade;
import android.app.Activity;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.OnLifecycleEvent;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.View;
import io.flutter.app.FlutterActivityDelegate;
import io.flutter.view.FlutterMain;
import io.flutter.view.FlutterNativeView;
import io.flutter.view.FlutterView;
import io.flutter.plugins.GeneratedPluginRegistrant;
/**
* Main entry point for using Flutter in Android applications.
*
* <p><strong>Warning:</strong> This file is auto-generated by Flutter tooling. Do not edit.
* It may be moved into flutter.jar or another library dependency of the Flutter module project
* at a later point.</p>
*/
public final class Flutter {
private Flutter() {
// to prevent instantiation
}
public static void startInitialization(Context applicationContext) {
FlutterMain.startInitialization(applicationContext, null);
}
public static Fragment createFragment(String route) {
final FlutterFragment fragment = new FlutterFragment();
final Bundle args = new Bundle();
args.putString(FlutterFragment.ARG_ROUTE, route);
fragment.setArguments(args);
return fragment;
}
public static View createView(final Activity activity, final Lifecycle lifecycle, final String route) {
FlutterMain.startInitialization(activity.getApplicationContext());
FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), null);
final FlutterActivityDelegate delegate = new FlutterActivityDelegate(activity, new FlutterActivityDelegate.ViewFactory() {
@Override
public FlutterView createFlutterView(Context context) {
final FlutterNativeView nativeView = new FlutterNativeView(context);
final FlutterView flutterView = new FlutterView(activity, null, nativeView);
flutterView.setInitialRoute(route);
return flutterView;
}
@Override
public boolean retainFlutterNativeView() {
return false;
}
@Override
public FlutterNativeView createFlutterNativeView() {
throw new UnsupportedOperationException();
}
});
lifecycle.addObserver(new LifecycleObserver() {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {
delegate.onCreate(null);
GeneratedPluginRegistrant.registerWith(delegate);
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
delegate.onStart();
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
delegate.onResume();
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
delegate.onPause();
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
delegate.onStop();
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
delegate.onDestroy();
}
});
return delegate.getFlutterView();
}
}
package io.flutter.facade;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A {@link Fragment} managing a Flutter view.
*
* <p><strong>Warning:</strong> This file is auto-generated by Flutter tooling. Do not edit.
* It may be moved into flutter.jar or another library dependency of the Flutter module project
* at a later point.</p>
*/
public class FlutterFragment extends Fragment {
public static final String ARG_ROUTE = "route";
private String mRoute = "/";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mRoute = getArguments().getString(ARG_ROUTE);
}
}
@Override
public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
super.onInflate(context, attrs, savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return Flutter.createView(getActivity(), getLifecycle(), mRoute);
}
}
// Generated file. Do not edit.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/android_gen"
}
subprojects {
project.evaluationDependsOn(':flutter')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
// Generated file. Do not edit.
def scriptFile = getClass().protectionDomain.codeSource.location.path
def flutterProjectRoot = new File(scriptFile).parentFile.parentFile
gradle.include ':flutter'
gradle.project(':flutter').projectDir = new File(flutterProjectRoot, '.android/Flutter')
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve('android').toFile()
gradle.include ":$name"
gradle.project(":$name").projectDir = pluginDirectory
}
// Generated file. Do not edit.
rootProject.name = 'android_generated'
setBinding(new Binding([gradle: this]))
evaluate(new File('include_flutter.groovy'))
.DS_Store
.dart_tool/
.packages
.pub/
.idea/
.vagrant/
.sconsign.dblite
.svn/
*.swp
profile
DerivedData/
.generated/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
build/
android_gen/
.flutter-plugins
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: {{flutterRevision}}
channel: {{flutterChannel}}
# {{projectName}}
{{description}}
## Getting Started
For help getting started with Flutter, view our online
[documentation](https://flutter.io/).
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:package_info/package_info.dart';
Future<void> main() async {
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
runApp(Directionality(textDirection: TextDirection.ltr, child: Router(packageInfo)));
}
class Router extends StatelessWidget {
Router(this.packageInfo);
final PackageInfo packageInfo;
@override
Widget build(BuildContext context) {
final String route = window.defaultRouteName;
switch (route) {
case 'route1':
return Container(
child: Center(child: Text('Route 1\n${packageInfo.appName}')),
color: Colors.green,
);
case 'route2':
return Container(
child: Center(child: Text('Route 2\n${packageInfo.packageName}')),
color: Colors.blue,
);
default:
return Container(
child: Center(child: Text('Unknown route: $route')),
color: Colors.red,
);
}
}
}
name: {{projectName}}
description: {{description}}
version: 1.0.0+1
dependencies:
package_info:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
module:
androidPackage: {{androidIdentifier}}
......@@ -186,6 +186,59 @@ void main() {
);
}, timeout: allowForRemotePubInvocation);
testUsingContext('module', () async {
return _createProject(
projectDir,
<String>['--no-pub', '--template=module'],
<String>[
'.gitignore',
'.metadata',
'lib/main.dart',
'pubspec.yaml',
'README.md',
],
unexpectedPaths: <String>[
'.android/',
'android/',
'ios/',
]
);
}, timeout: allowForCreateFlutterProject);
testUsingContext('module with pub', () async {
return _createProject(
projectDir,
<String>['-t', 'module'],
<String>[
'.gitignore',
'.metadata',
'lib/main.dart',
'pubspec.lock',
'pubspec.yaml',
'README.md',
'.packages',
'.android/build.gradle',
'.android/Flutter/build.gradle',
'.android/Flutter/src/main/java/io/flutter/facade/Flutter.java',
'.android/Flutter/src/main/java/io/flutter/facade/FlutterFragment.java',
'.android/Flutter/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
'.android/Flutter/src/main/AndroidManifest.xml',
'.android/gradle.properties',
'.android/gradle/wrapper/gradle-wrapper.jar',
'.android/gradle/wrapper/gradle-wrapper.properties',
'.android/gradlew',
'.android/gradlew.bat',
'.android/local.properties',
'.android/include_flutter.groovy',
'.android/settings.gradle',
],
unexpectedPaths: <String>[
'android/',
'ios/',
]
);
}, timeout: allowForRemotePubInvocation);
// Verify content and formatting
testUsingContext('content', () async {
Cache.flutterRoot = '../..';
......@@ -423,11 +476,16 @@ Future<Null> _createProject(
args.add(dir.path);
await runner.run(args);
bool pathExists(String path) {
final String fullPath = fs.path.join(dir.path, path);
return fs.typeSync(fullPath) != FileSystemEntityType.notFound;
}
for (String path in expectedPaths) {
expect(fs.file(fs.path.join(dir.path, path)).existsSync(), true, reason: '$path does not exist');
expect(pathExists(path), true, reason: '$path does not exist');
}
for (String path in unexpectedPaths) {
expect(fs.file(fs.path.join(dir.path, path)).existsSync(), false, reason: '$path exists');
expect(pathExists(path), false, reason: '$path exists');
}
}
......
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