mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
Use FlutterProject to locate files (#18913)
This commit is contained in:
parent
e7832a3897
commit
57d78cc739
|
@ -21,6 +21,7 @@ import '../base/utils.dart';
|
|||
import '../build_info.dart';
|
||||
import '../device.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
import '../protocol_discovery.dart';
|
||||
|
||||
import 'adb.dart';
|
||||
|
@ -241,7 +242,7 @@ class AndroidDevice extends Device {
|
|||
|
||||
String _getSourceSha1(ApplicationPackage app) {
|
||||
final AndroidApk apk = app;
|
||||
final File shaFile = fs.file('${apk.apkPath}.sha1');
|
||||
final File shaFile = fs.file('${apk.file.path}.sha1');
|
||||
return shaFile.existsSync() ? shaFile.readAsStringSync() : '';
|
||||
}
|
||||
|
||||
|
@ -269,16 +270,16 @@ class AndroidDevice extends Device {
|
|||
@override
|
||||
Future<bool> installApp(ApplicationPackage app) async {
|
||||
final AndroidApk apk = app;
|
||||
if (!fs.isFileSync(apk.apkPath)) {
|
||||
printError('"${apk.apkPath}" does not exist.');
|
||||
if (!apk.file.existsSync()) {
|
||||
printError('"${apk.file.path}" does not exist.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!await _checkForSupportedAdbVersion() || !await _checkForSupportedAndroidVersion())
|
||||
return false;
|
||||
|
||||
final Status status = logger.startProgress('Installing ${apk.apkPath}...', expectSlowOperation: true);
|
||||
final RunResult installResult = await runAsync(adbCommandForDevice(<String>['install', '-t', '-r', apk.apkPath]));
|
||||
final Status status = logger.startProgress('Installing ${apk.file.path}...', expectSlowOperation: true);
|
||||
final RunResult installResult = await runAsync(adbCommandForDevice(<String>['install', '-t', '-r', apk.file.path]));
|
||||
status.stop();
|
||||
// Some versions of adb exit with exit code 0 even on failure :(
|
||||
// Parsing the output to check for failures.
|
||||
|
@ -374,12 +375,13 @@ class AndroidDevice extends Device {
|
|||
if (!prebuiltApplication) {
|
||||
printTrace('Building APK');
|
||||
await buildApk(
|
||||
project: new FlutterProject(fs.currentDirectory),
|
||||
target: mainPath,
|
||||
buildInfo: buildInfo,
|
||||
);
|
||||
// Package has been built, so we can get the updated application ID and
|
||||
// activity name from the .apk.
|
||||
package = await AndroidApk.fromCurrentDirectory();
|
||||
package = await AndroidApk.fromAndroidProject(new FlutterProject(fs.currentDirectory).android);
|
||||
}
|
||||
|
||||
printTrace("Stopping app '${package.name}' on $name.");
|
||||
|
|
|
@ -4,17 +4,22 @@
|
|||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../base/common.dart';
|
||||
import '../build_info.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
|
||||
import 'android_sdk.dart';
|
||||
import 'gradle.dart';
|
||||
|
||||
Future<Null> buildApk({
|
||||
String target,
|
||||
@required FlutterProject project,
|
||||
@required String target,
|
||||
BuildInfo buildInfo = BuildInfo.debug
|
||||
}) async {
|
||||
if (!isProjectUsingGradle()) {
|
||||
if (!project.android.isUsingGradle()) {
|
||||
throwToolExit(
|
||||
'The build process for Android has changed, and the current project configuration\n'
|
||||
'is no longer valid. Please consult\n\n'
|
||||
|
@ -33,5 +38,9 @@ Future<Null> buildApk({
|
|||
throwToolExit('Try re-installing or updating your Android SDK.');
|
||||
}
|
||||
|
||||
return buildGradleProject(buildInfo, target);
|
||||
return buildGradleProject(
|
||||
project: project,
|
||||
buildInfo: buildInfo,
|
||||
target: target,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../android/android_sdk.dart';
|
||||
import '../artifacts.dart';
|
||||
import '../base/common.dart';
|
||||
|
@ -14,16 +16,13 @@ import '../base/platform.dart';
|
|||
import '../base/process.dart';
|
||||
import '../base/utils.dart';
|
||||
import '../build_info.dart';
|
||||
import '../bundle.dart' as bundle;
|
||||
import '../cache.dart';
|
||||
import '../flutter_manifest.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
import 'android_sdk.dart';
|
||||
import 'android_studio.dart';
|
||||
|
||||
const String gradleManifestPath = 'android/app/src/main/AndroidManifest.xml';
|
||||
const String gradleAppOutV1 = 'android/app/build/outputs/apk/app-debug.apk';
|
||||
const String gradleAppOutDirV1 = 'android/app/build/outputs/apk';
|
||||
const String gradleVersion = '4.1';
|
||||
final RegExp _assembleTaskPattern = new RegExp(r'assemble([^:]+): task ');
|
||||
|
||||
|
@ -45,9 +44,6 @@ final RegExp ndkMessageFilter = new RegExp(r'^(?!NDK is missing a ".*" directory
|
|||
r'|If you are using NDK, verify the ndk.dir is set to a valid NDK directory. It is currently set to .*)');
|
||||
|
||||
|
||||
bool isProjectUsingGradle() {
|
||||
return fs.isFileSync('android/build.gradle');
|
||||
}
|
||||
|
||||
FlutterPluginVersion get flutterPluginVersion {
|
||||
final File plugin = fs.file('android/buildSrc/src/main/groovy/FlutterPlugin.groovy');
|
||||
|
@ -69,18 +65,17 @@ FlutterPluginVersion get flutterPluginVersion {
|
|||
return FlutterPluginVersion.none;
|
||||
}
|
||||
|
||||
/// Returns the path to the apk file created by [buildGradleProject], relative
|
||||
/// to current directory.
|
||||
Future<String> getGradleAppOut() async {
|
||||
/// Returns the apk file created by [buildGradleProject]
|
||||
Future<File> getGradleAppOut(AndroidProject androidProject) async {
|
||||
switch (flutterPluginVersion) {
|
||||
case FlutterPluginVersion.none:
|
||||
// Fall through. Pretend we're v1, and just go with it.
|
||||
case FlutterPluginVersion.v1:
|
||||
return gradleAppOutV1;
|
||||
return androidProject.gradleAppOutV1File;
|
||||
case FlutterPluginVersion.managed:
|
||||
// Fall through. The managed plugin matches plugin v2 for now.
|
||||
case FlutterPluginVersion.v2:
|
||||
return fs.path.relative(fs.path.join((await _gradleProject()).apkDirectory, 'app.apk'));
|
||||
return fs.file((await _gradleProject()).apkDirectory.childFile('app.apk'));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -94,12 +89,13 @@ Future<GradleProject> _gradleProject() async {
|
|||
// of calculating the app properties using Gradle. This may take minutes.
|
||||
Future<GradleProject> _readGradleProject() async {
|
||||
final String gradle = await _ensureGradle();
|
||||
await updateLocalProperties();
|
||||
final FlutterProject flutterProject = new FlutterProject(fs.currentDirectory);
|
||||
await updateLocalProperties(project: flutterProject);
|
||||
try {
|
||||
final Status status = logger.startProgress('Resolving dependencies...', expectSlowOperation: true);
|
||||
final RunResult runResult = await runCheckedAsync(
|
||||
<String>[gradle, 'app:properties'],
|
||||
workingDirectory: 'android',
|
||||
workingDirectory: flutterProject.android.directory.path,
|
||||
environment: _gradleEnv,
|
||||
);
|
||||
final String properties = runResult.stdout.trim();
|
||||
|
@ -117,7 +113,7 @@ Future<GradleProject> _readGradleProject() async {
|
|||
}
|
||||
}
|
||||
// Fall back to the default
|
||||
return new GradleProject(<String>['debug', 'profile', 'release'], <String>[], gradleAppOutDirV1);
|
||||
return new GradleProject(<String>['debug', 'profile', 'release'], <String>[], flutterProject.android.gradleAppOutV1Directory);
|
||||
}
|
||||
|
||||
void handleKnownGradleExceptions(String exceptionString) {
|
||||
|
@ -199,28 +195,19 @@ distributionUrl=https\\://services.gradle.org/distributions/gradle-$gradleVersio
|
|||
/// 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 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) {
|
||||
///
|
||||
/// If [requireSdk] is `true` this will fail with a tool-exit if no Android Sdk
|
||||
/// is found.
|
||||
Future<void> updateLocalProperties({
|
||||
@required FlutterProject project,
|
||||
BuildInfo buildInfo,
|
||||
bool requireAndroidSdk = true,
|
||||
}) async {
|
||||
if (requireAndroidSdk && 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');
|
||||
final File localProperties = await project.androidLocalPropertiesFile;
|
||||
bool changed = false;
|
||||
|
||||
SettingsFile settings;
|
||||
|
@ -238,6 +225,8 @@ void updateLocalPropertiesSync(Directory android, FlutterManifest manifest, [Bui
|
|||
}
|
||||
}
|
||||
|
||||
final FlutterManifest manifest = await project.manifest;
|
||||
|
||||
if (androidSdk != null)
|
||||
changeIfNecessary('sdk.dir', escapePath(androidSdk.directory));
|
||||
changeIfNecessary('flutter.sdk', escapePath(Cache.flutterRoot));
|
||||
|
@ -254,7 +243,11 @@ void updateLocalPropertiesSync(Directory android, FlutterManifest manifest, [Bui
|
|||
settings.writeContents(localProperties);
|
||||
}
|
||||
|
||||
Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async {
|
||||
Future<Null> buildGradleProject({
|
||||
@required FlutterProject project,
|
||||
@required BuildInfo buildInfo,
|
||||
@required String target,
|
||||
}) async {
|
||||
// Update the local.properties file with the build mode, version name and code.
|
||||
// FlutterPlugin v1 reads local.properties to determine build mode. Plugin v2
|
||||
// uses the standard Android way to determine what to build, but we still
|
||||
|
@ -263,7 +256,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async {
|
|||
// and can be overwritten with flutter build command.
|
||||
// The default Gradle script reads the version name and number
|
||||
// from the local.properties file.
|
||||
await updateLocalProperties(buildInfo: buildInfo);
|
||||
await updateLocalProperties(project: project, buildInfo: buildInfo);
|
||||
|
||||
final String gradle = await _ensureGradle();
|
||||
|
||||
|
@ -271,7 +264,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async {
|
|||
case FlutterPluginVersion.none:
|
||||
// Fall through. Pretend it's v1, and just go for it.
|
||||
case FlutterPluginVersion.v1:
|
||||
return _buildGradleProjectV1(gradle);
|
||||
return _buildGradleProjectV1(project, gradle);
|
||||
case FlutterPluginVersion.managed:
|
||||
// Fall through. Managed plugin builds the same way as plugin v2.
|
||||
case FlutterPluginVersion.v2:
|
||||
|
@ -279,7 +272,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async {
|
|||
}
|
||||
}
|
||||
|
||||
Future<Null> _buildGradleProjectV1(String gradle) async {
|
||||
Future<Null> _buildGradleProjectV1(FlutterProject project, String gradle) async {
|
||||
// Run 'gradlew build'.
|
||||
final Status status = logger.startProgress('Running \'gradlew build\'...', expectSlowOperation: true);
|
||||
final int exitCode = await runCommandAndStreamOutput(
|
||||
|
@ -293,7 +286,7 @@ Future<Null> _buildGradleProjectV1(String gradle) async {
|
|||
if (exitCode != 0)
|
||||
throwToolExit('Gradle build failed: $exitCode', exitCode: exitCode);
|
||||
|
||||
printStatus('Built $gradleAppOutV1.');
|
||||
printStatus('Built ${fs.path.relative(project.android.gradleAppOutV1File.path)}.');
|
||||
}
|
||||
|
||||
Future<Null> _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String target) async {
|
||||
|
@ -371,10 +364,10 @@ Future<Null> _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String ta
|
|||
if (apkFile == null)
|
||||
throwToolExit('Gradle build failed to produce an Android package.');
|
||||
// Copy the APK to app.apk, so `flutter run`, `flutter install`, etc. can find it.
|
||||
apkFile.copySync(fs.path.join(project.apkDirectory, 'app.apk'));
|
||||
apkFile.copySync(project.apkDirectory.childFile('app.apk').path);
|
||||
|
||||
printTrace('calculateSha: ${project.apkDirectory}/app.apk');
|
||||
final File apkShaFile = fs.file(fs.path.join(project.apkDirectory, 'app.apk.sha1'));
|
||||
final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1');
|
||||
apkShaFile.writeAsStringSync(calculateSha(apkFile));
|
||||
|
||||
String appSize;
|
||||
|
@ -390,15 +383,15 @@ File _findApkFile(GradleProject project, BuildInfo buildInfo) {
|
|||
final String apkFileName = project.apkFileFor(buildInfo);
|
||||
if (apkFileName == null)
|
||||
return null;
|
||||
File apkFile = fs.file(fs.path.join(project.apkDirectory, apkFileName));
|
||||
File apkFile = fs.file(fs.path.join(project.apkDirectory.path, apkFileName));
|
||||
if (apkFile.existsSync())
|
||||
return apkFile;
|
||||
apkFile = fs.file(fs.path.join(project.apkDirectory, buildInfo.modeName, apkFileName));
|
||||
apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.modeName, apkFileName));
|
||||
if (apkFile.existsSync())
|
||||
return apkFile;
|
||||
if (buildInfo.flavor != null) {
|
||||
// Android Studio Gradle plugin v3 adds flavor to path.
|
||||
apkFile = fs.file(fs.path.join(project.apkDirectory, buildInfo.flavor, buildInfo.modeName, apkFileName));
|
||||
apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.flavor, buildInfo.modeName, apkFileName));
|
||||
if (apkFile.existsSync())
|
||||
return apkFile;
|
||||
}
|
||||
|
@ -453,13 +446,13 @@ class GradleProject {
|
|||
return new GradleProject(
|
||||
buildTypes.toList(),
|
||||
productFlavors.toList(),
|
||||
fs.path.normalize(fs.path.join(buildDir, 'outputs', 'apk')),
|
||||
fs.directory(fs.path.join(buildDir, 'outputs', 'apk')),
|
||||
);
|
||||
}
|
||||
|
||||
final List<String> buildTypes;
|
||||
final List<String> productFlavors;
|
||||
final String apkDirectory;
|
||||
final Directory apkDirectory;
|
||||
|
||||
String _buildTypeFor(BuildInfo buildInfo) {
|
||||
if (buildTypes.contains(buildInfo.modeName))
|
||||
|
|
|
@ -18,6 +18,7 @@ import 'globals.dart';
|
|||
import 'ios/ios_workflow.dart';
|
||||
import 'ios/plist_utils.dart' as plist;
|
||||
import 'ios/xcodeproj.dart';
|
||||
import 'project.dart';
|
||||
import 'tester/flutter_tester.dart';
|
||||
|
||||
abstract class ApplicationPackage {
|
||||
|
@ -31,7 +32,7 @@ abstract class ApplicationPackage {
|
|||
|
||||
String get displayName => name;
|
||||
|
||||
String get packagePath => null;
|
||||
File get packagesFile => null;
|
||||
|
||||
@override
|
||||
String toString() => displayName;
|
||||
|
@ -39,21 +40,21 @@ abstract class ApplicationPackage {
|
|||
|
||||
class AndroidApk extends ApplicationPackage {
|
||||
/// Path to the actual apk file.
|
||||
final String apkPath;
|
||||
final File file;
|
||||
|
||||
/// The path to the activity that should be launched.
|
||||
final String launchActivity;
|
||||
|
||||
AndroidApk({
|
||||
String id,
|
||||
@required this.apkPath,
|
||||
@required this.file,
|
||||
@required this.launchActivity
|
||||
}) : assert(apkPath != null),
|
||||
}) : assert(file != null),
|
||||
assert(launchActivity != null),
|
||||
super(id: id);
|
||||
|
||||
/// Creates a new AndroidApk from an existing APK.
|
||||
factory AndroidApk.fromApk(String applicationBinary) {
|
||||
factory AndroidApk.fromApk(File apk) {
|
||||
final String aaptPath = androidSdk?.latestVersion?.aaptPath;
|
||||
if (aaptPath == null) {
|
||||
printError('Unable to locate the Android SDK; please run \'flutter doctor\'.');
|
||||
|
@ -64,7 +65,7 @@ class AndroidApk extends ApplicationPackage {
|
|||
aaptPath,
|
||||
'dump',
|
||||
'xmltree',
|
||||
applicationBinary,
|
||||
apk.path,
|
||||
'AndroidManifest.xml',
|
||||
];
|
||||
|
||||
|
@ -72,47 +73,46 @@ class AndroidApk extends ApplicationPackage {
|
|||
.parseFromXmlDump(runCheckedSync(aaptArgs));
|
||||
|
||||
if (data == null) {
|
||||
printError('Unable to read manifest info from $applicationBinary.');
|
||||
printError('Unable to read manifest info from ${apk.path}.');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (data.packageName == null || data.launchableActivityName == null) {
|
||||
printError('Unable to read manifest info from $applicationBinary.');
|
||||
printError('Unable to read manifest info from ${apk.path}.');
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AndroidApk(
|
||||
id: data.packageName,
|
||||
apkPath: applicationBinary,
|
||||
file: apk,
|
||||
launchActivity: '${data.packageName}/${data.launchableActivityName}'
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a new AndroidApk based on the information in the Android manifest.
|
||||
static Future<AndroidApk> fromCurrentDirectory() async {
|
||||
String manifestPath;
|
||||
String apkPath;
|
||||
static Future<AndroidApk> fromAndroidProject(AndroidProject androidProject) async {
|
||||
File apkFile;
|
||||
|
||||
if (isProjectUsingGradle()) {
|
||||
apkPath = await getGradleAppOut();
|
||||
if (fs.file(apkPath).existsSync()) {
|
||||
if (androidProject.isUsingGradle()) {
|
||||
apkFile = await getGradleAppOut(androidProject);
|
||||
if (apkFile.existsSync()) {
|
||||
// Grab information from the .apk. The gradle build script might alter
|
||||
// the application Id, so we need to look at what was actually built.
|
||||
return new AndroidApk.fromApk(apkPath);
|
||||
return new AndroidApk.fromApk(apkFile);
|
||||
}
|
||||
// The .apk hasn't been built yet, so we work with what we have. The run
|
||||
// command will grab a new AndroidApk after building, to get the updated
|
||||
// IDs.
|
||||
manifestPath = gradleManifestPath;
|
||||
} else {
|
||||
manifestPath = fs.path.join('android', 'AndroidManifest.xml');
|
||||
apkPath = fs.path.join(getAndroidBuildDirectory(), 'app.apk');
|
||||
apkFile = fs.file(fs.path.join(getAndroidBuildDirectory(), 'app.apk'));
|
||||
}
|
||||
|
||||
if (!fs.isFileSync(manifestPath))
|
||||
final File manifest = androidProject.gradleManifestFile;
|
||||
|
||||
if (!manifest.existsSync())
|
||||
return null;
|
||||
|
||||
final String manifestString = fs.file(manifestPath).readAsStringSync();
|
||||
final String manifestString = manifest.readAsStringSync();
|
||||
final xml.XmlDocument document = xml.parse(manifestString);
|
||||
|
||||
final Iterable<xml.XmlElement> manifests = document.findElements('manifest');
|
||||
|
@ -138,16 +138,16 @@ class AndroidApk extends ApplicationPackage {
|
|||
|
||||
return new AndroidApk(
|
||||
id: packageId,
|
||||
apkPath: apkPath,
|
||||
file: apkFile,
|
||||
launchActivity: launchActivity
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String get packagePath => apkPath;
|
||||
File get packagesFile => file;
|
||||
|
||||
@override
|
||||
String get name => fs.path.basename(apkPath);
|
||||
String get name => file.basename;
|
||||
}
|
||||
|
||||
/// Tests whether a [FileSystemEntity] is an iOS bundle directory
|
||||
|
@ -158,18 +158,18 @@ abstract class IOSApp extends ApplicationPackage {
|
|||
IOSApp({@required String projectBundleId}) : super(id: projectBundleId);
|
||||
|
||||
/// Creates a new IOSApp from an existing app bundle or IPA.
|
||||
factory IOSApp.fromPrebuiltApp(String applicationBinary) {
|
||||
final FileSystemEntityType entityType = fs.typeSync(applicationBinary);
|
||||
factory IOSApp.fromPrebuiltApp(File applicationBinary) {
|
||||
final FileSystemEntityType entityType = fs.typeSync(applicationBinary.path);
|
||||
if (entityType == FileSystemEntityType.notFound) {
|
||||
printError(
|
||||
'File "$applicationBinary" does not exist. Use an app bundle or an ipa.');
|
||||
'File "${applicationBinary.path}" does not exist. Use an app bundle or an ipa.');
|
||||
return null;
|
||||
}
|
||||
Directory bundleDir;
|
||||
if (entityType == FileSystemEntityType.directory) {
|
||||
final Directory directory = fs.directory(applicationBinary);
|
||||
if (!_isBundleDirectory(directory)) {
|
||||
printError('Folder "$applicationBinary" is not an app bundle.');
|
||||
printError('Folder "${applicationBinary.path}" is not an app bundle.');
|
||||
return null;
|
||||
}
|
||||
bundleDir = fs.directory(applicationBinary);
|
||||
|
@ -305,16 +305,16 @@ class PrebuiltIOSApp extends IOSApp {
|
|||
String get _bundlePath => bundleDir.path;
|
||||
}
|
||||
|
||||
Future<ApplicationPackage> getApplicationPackageForPlatform(TargetPlatform platform, {
|
||||
String applicationBinary
|
||||
}) async {
|
||||
Future<ApplicationPackage> getApplicationPackageForPlatform(
|
||||
TargetPlatform platform,
|
||||
{File applicationBinary}) async {
|
||||
switch (platform) {
|
||||
case TargetPlatform.android_arm:
|
||||
case TargetPlatform.android_arm64:
|
||||
case TargetPlatform.android_x64:
|
||||
case TargetPlatform.android_x86:
|
||||
return applicationBinary == null
|
||||
? await AndroidApk.fromCurrentDirectory()
|
||||
? await AndroidApk.fromAndroidProject(new FlutterProject(fs.currentDirectory).android)
|
||||
: new AndroidApk.fromApk(applicationBinary);
|
||||
case TargetPlatform.ios:
|
||||
return applicationBinary == null
|
||||
|
@ -344,7 +344,7 @@ class ApplicationPackageStore {
|
|||
case TargetPlatform.android_arm64:
|
||||
case TargetPlatform.android_x64:
|
||||
case TargetPlatform.android_x86:
|
||||
android ??= await AndroidApk.fromCurrentDirectory();
|
||||
android ??= await AndroidApk.fromAndroidProject(new FlutterProject(fs.currentDirectory).android);
|
||||
return android;
|
||||
case TargetPlatform.ios:
|
||||
iOS ??= new IOSApp.fromCurrentDirectory();
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
import 'dart:async';
|
||||
|
||||
import '../android/apk.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../project.dart';
|
||||
import 'build.dart';
|
||||
|
||||
class BuildApkCommand extends BuildSubCommand {
|
||||
|
@ -44,6 +46,6 @@ class BuildApkCommand extends BuildSubCommand {
|
|||
@override
|
||||
Future<Null> runCommand() async {
|
||||
await super.runCommand();
|
||||
await buildApk(buildInfo: getBuildInfo(), target: targetFile);
|
||||
await buildApk(project: new FlutterProject(fs.currentDirectory),target: targetFile, buildInfo: getBuildInfo());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,20 +168,19 @@ class CreateCommand extends FlutterCommand {
|
|||
|
||||
printStatus('Creating project ${fs.path.relative(dirPath)}...');
|
||||
int generatedFileCount = 0;
|
||||
String appPath = dirPath;
|
||||
final FlutterProject project = new FlutterProject.fromPath(dirPath);
|
||||
switch (template) {
|
||||
case 'app':
|
||||
generatedFileCount += await _generateApp(dirPath, templateContext);
|
||||
generatedFileCount += await _generateApp(project, templateContext);
|
||||
break;
|
||||
case 'module':
|
||||
generatedFileCount += await _generateModule(dirPath, templateContext);
|
||||
generatedFileCount += await _generateModule(project, templateContext);
|
||||
break;
|
||||
case 'package':
|
||||
generatedFileCount += await _generatePackage(dirPath, templateContext);
|
||||
generatedFileCount += await _generatePackage(project, templateContext);
|
||||
break;
|
||||
case 'plugin':
|
||||
appPath = fs.path.join(dirPath, 'example');
|
||||
generatedFileCount += await _generatePlugin(dirPath, appPath, templateContext);
|
||||
generatedFileCount += await _generatePlugin(project, templateContext);
|
||||
break;
|
||||
}
|
||||
printStatus('Wrote $generatedFileCount files.');
|
||||
|
@ -194,7 +193,8 @@ class CreateCommand extends FlutterCommand {
|
|||
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);
|
||||
final FlutterProject app = project.hasExampleApp ? project.example : project;
|
||||
final String relativeAppPath = fs.path.relative(app.directory.path);
|
||||
final String relativePluginPath = fs.path.relative(dirPath);
|
||||
if (doctor.canLaunchAnything) {
|
||||
// Let them know a summary of the state of their tooling.
|
||||
|
@ -233,60 +233,59 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
|
|||
}
|
||||
}
|
||||
|
||||
Future<int> _generateModule(String path, Map<String, dynamic> templateContext) async {
|
||||
Future<int> _generateModule(FlutterProject project, 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'), path, templateContext);
|
||||
generatedCount += _renderTemplate(fs.path.join('module', 'common'), project.directory, templateContext);
|
||||
if (argResults['pub']) {
|
||||
await pubGet(
|
||||
context: PubContext.create,
|
||||
directory: path,
|
||||
directory: project.directory.path,
|
||||
offline: argResults['offline'],
|
||||
);
|
||||
final FlutterProject project = new FlutterProject.fromPath(path);
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
}
|
||||
return generatedCount;
|
||||
}
|
||||
|
||||
Future<int> _generatePackage(String dirPath, Map<String, dynamic> templateContext) async {
|
||||
Future<int> _generatePackage(FlutterProject project, Map<String, dynamic> templateContext) async {
|
||||
int generatedCount = 0;
|
||||
final String description = argResults.wasParsed('description')
|
||||
? argResults['description']
|
||||
: 'A new flutter package project.';
|
||||
templateContext['description'] = description;
|
||||
generatedCount += _renderTemplate('package', dirPath, templateContext);
|
||||
generatedCount += _renderTemplate('package', project.directory, templateContext);
|
||||
|
||||
if (argResults['pub']) {
|
||||
await pubGet(
|
||||
context: PubContext.createPackage,
|
||||
directory: dirPath,
|
||||
directory: project.directory.path,
|
||||
offline: argResults['offline'],
|
||||
);
|
||||
}
|
||||
return generatedCount;
|
||||
}
|
||||
|
||||
Future<int> _generatePlugin(String dirPath, String appPath, Map<String, dynamic> templateContext) async {
|
||||
Future<int> _generatePlugin(FlutterProject project, Map<String, dynamic> templateContext) async {
|
||||
int generatedCount = 0;
|
||||
final String description = argResults.wasParsed('description')
|
||||
? argResults['description']
|
||||
: 'A new flutter plugin project.';
|
||||
templateContext['description'] = description;
|
||||
generatedCount += _renderTemplate('plugin', dirPath, templateContext);
|
||||
generatedCount += _renderTemplate('plugin', project.directory, templateContext);
|
||||
|
||||
if (argResults['pub']) {
|
||||
await pubGet(
|
||||
context: PubContext.createPlugin,
|
||||
directory: dirPath,
|
||||
directory: project.directory.path,
|
||||
offline: argResults['offline'],
|
||||
);
|
||||
}
|
||||
if (android_sdk.androidSdk != null)
|
||||
await gradle.updateLocalProperties(projectPath: dirPath);
|
||||
await gradle.updateLocalProperties(project: project);
|
||||
|
||||
final String projectName = templateContext['projectName'];
|
||||
final String organization = templateContext['organization'];
|
||||
|
@ -299,27 +298,27 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
|
|||
templateContext['pluginProjectName'] = projectName;
|
||||
templateContext['androidPluginIdentifier'] = androidPluginIdentifier;
|
||||
|
||||
generatedCount += await _generateApp(appPath, templateContext);
|
||||
generatedCount += await _generateApp(project.example, templateContext);
|
||||
return generatedCount;
|
||||
}
|
||||
|
||||
Future<int> _generateApp(String projectPath, Map<String, dynamic> templateContext) async {
|
||||
Future<int> _generateApp(FlutterProject project, Map<String, dynamic> templateContext) async {
|
||||
int generatedCount = 0;
|
||||
generatedCount += _renderTemplate('create', projectPath, templateContext);
|
||||
generatedCount += _injectGradleWrapper(projectPath);
|
||||
generatedCount += _renderTemplate('create', project.directory, templateContext);
|
||||
generatedCount += _injectGradleWrapper(project);
|
||||
|
||||
if (argResults['with-driver-test']) {
|
||||
final String testPath = fs.path.join(projectPath, 'test_driver');
|
||||
generatedCount += _renderTemplate('driver', testPath, templateContext);
|
||||
final Directory testDirectory = project.directory.childDirectory('test_driver');
|
||||
generatedCount += _renderTemplate('driver', testDirectory, templateContext);
|
||||
}
|
||||
|
||||
if (argResults['pub']) {
|
||||
await pubGet(context: PubContext.create, directory: projectPath, offline: argResults['offline']);
|
||||
await new FlutterProject.fromPath(projectPath).ensureReadyForPlatformSpecificTooling();
|
||||
await pubGet(context: PubContext.create, directory: project.directory.path, offline: argResults['offline']);
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
}
|
||||
|
||||
if (android_sdk.androidSdk != null)
|
||||
await gradle.updateLocalProperties(projectPath: projectPath);
|
||||
await gradle.updateLocalProperties(project: project);
|
||||
|
||||
return generatedCount;
|
||||
}
|
||||
|
@ -362,16 +361,16 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
|
|||
};
|
||||
}
|
||||
|
||||
int _renderTemplate(String templateName, String dirPath, Map<String, dynamic> context) {
|
||||
int _renderTemplate(String templateName, Directory directory, Map<String, dynamic> context) {
|
||||
final Template template = new Template.fromName(templateName);
|
||||
return template.render(fs.directory(dirPath), context, overwriteExisting: false);
|
||||
return template.render(directory, context, overwriteExisting: false);
|
||||
}
|
||||
|
||||
int _injectGradleWrapper(String projectDir) {
|
||||
int _injectGradleWrapper(FlutterProject project) {
|
||||
int filesCreated = 0;
|
||||
copyDirectorySync(
|
||||
cache.getArtifactDirectory('gradle_wrapper'),
|
||||
fs.directory(fs.path.join(projectDir, 'android')),
|
||||
project.android.directory,
|
||||
(File sourceFile, File destinationFile) {
|
||||
filesCreated++;
|
||||
final String modes = sourceFile.statSync().modeString();
|
||||
|
|
|
@ -322,7 +322,7 @@ class AppDomain extends Domain {
|
|||
Future<AppInstance> startApp(
|
||||
Device device, String projectDirectory, String target, String route,
|
||||
DebuggingOptions options, bool enableHotReload, {
|
||||
String applicationBinary,
|
||||
File applicationBinary,
|
||||
@required bool trackWidgetCreation,
|
||||
String projectRootPath,
|
||||
String packagesFilePath,
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
import 'dart:async';
|
||||
|
||||
import '../base/file_system.dart';
|
||||
import '../flutter_manifest.dart';
|
||||
import '../globals.dart';
|
||||
import '../plugins.dart';
|
||||
import '../project.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
|
||||
class InjectPluginsCommand extends FlutterCommand {
|
||||
|
@ -26,10 +26,9 @@ class InjectPluginsCommand extends FlutterCommand {
|
|||
|
||||
@override
|
||||
Future<Null> runCommand() async {
|
||||
final String projectPath = fs.currentDirectory.path;
|
||||
final FlutterManifest manifest = await FlutterManifest.createFromPath(projectPath);
|
||||
injectPlugins(projectPath: projectPath, manifest: manifest);
|
||||
final bool result = hasPlugins();
|
||||
final FlutterProject project = new FlutterProject(fs.currentDirectory);
|
||||
await injectPlugins(project);
|
||||
final bool result = hasPlugins(project);
|
||||
if (result) {
|
||||
printStatus('GeneratedPluginRegistrants successfully written.');
|
||||
} else {
|
||||
|
|
|
@ -289,10 +289,13 @@ class RunCommand extends RunCommandBase {
|
|||
notifyingLogger: new NotifyingLogger(), logToStdout: true);
|
||||
AppInstance app;
|
||||
try {
|
||||
final String applicationBinaryPath = argResults['use-application-binary'];
|
||||
app = await daemon.appDomain.startApp(
|
||||
devices.first, fs.currentDirectory.path, targetFile, route,
|
||||
_createDebuggingOptions(), hotMode,
|
||||
applicationBinary: argResults['use-application-binary'],
|
||||
applicationBinary: applicationBinaryPath == null
|
||||
? null
|
||||
: fs.file(applicationBinaryPath),
|
||||
trackWidgetCreation: argResults['track-widget-creation'],
|
||||
projectRootPath: argResults['project-root'],
|
||||
packagesFilePath: globalResults['packages'],
|
||||
|
|
|
@ -15,8 +15,8 @@ import '../base/process.dart';
|
|||
import '../base/process_manager.dart';
|
||||
import '../base/version.dart';
|
||||
import '../cache.dart';
|
||||
import '../flutter_manifest.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
import 'xcodeproj.dart';
|
||||
|
||||
const String noCocoaPodsConsequence = '''
|
||||
|
@ -81,18 +81,18 @@ class CocoaPods {
|
|||
Future<bool> get isCocoaPodsInitialized => fs.isDirectory(fs.path.join(homeDirPath, '.cocoapods', 'repos', 'master'));
|
||||
|
||||
Future<bool> processPods({
|
||||
@required Directory appIosDirectory,
|
||||
@required IosProject iosProject,
|
||||
// For backward compatibility with previously created Podfile only.
|
||||
@required String iosEngineDir,
|
||||
bool isSwift = false,
|
||||
bool dependenciesChanged = true,
|
||||
}) async {
|
||||
if (!(await appIosDirectory.childFile('Podfile').exists())) {
|
||||
if (!(await iosProject.podfile.exists())) {
|
||||
throwToolExit('Podfile missing');
|
||||
}
|
||||
if (await _checkPodCondition()) {
|
||||
if (_shouldRunPodInstall(appIosDirectory, dependenciesChanged)) {
|
||||
await _runPodInstall(appIosDirectory, iosEngineDir);
|
||||
if (_shouldRunPodInstall(iosProject, dependenciesChanged)) {
|
||||
await _runPodInstall(iosProject, iosEngineDir);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -151,18 +151,18 @@ class CocoaPods {
|
|||
/// Ensures the `ios` sub-project of the Flutter project at [appDirectory]
|
||||
/// contains a suitable `Podfile` and that its `Flutter/Xxx.xcconfig` files
|
||||
/// include pods configuration.
|
||||
void setupPodfile(String appDirectory, FlutterManifest manifest) {
|
||||
void setupPodfile(IosProject iosProject) {
|
||||
if (!xcodeProjectInterpreter.isInstalled) {
|
||||
// Don't do anything for iOS when host platform doesn't support it.
|
||||
return;
|
||||
}
|
||||
if (!fs.directory(fs.path.join(appDirectory, 'ios')).existsSync()) {
|
||||
if (!iosProject.directory.existsSync()) {
|
||||
return;
|
||||
}
|
||||
final String podfilePath = fs.path.join(appDirectory, 'ios', 'Podfile');
|
||||
if (!fs.file(podfilePath).existsSync()) {
|
||||
final File podfile = iosProject.podfile;
|
||||
if (!podfile.existsSync()) {
|
||||
final bool isSwift = xcodeProjectInterpreter.getBuildSettings(
|
||||
fs.path.join(appDirectory, 'ios', 'Runner.xcodeproj'),
|
||||
iosProject.directory.childFile('Runner.xcodeproj').path,
|
||||
'Runner',
|
||||
).containsKey('SWIFT_VERSION');
|
||||
final File podfileTemplate = fs.file(fs.path.join(
|
||||
|
@ -173,15 +173,14 @@ class CocoaPods {
|
|||
'cocoapods',
|
||||
isSwift ? 'Podfile-swift' : 'Podfile-objc',
|
||||
));
|
||||
podfileTemplate.copySync(podfilePath);
|
||||
podfileTemplate.copySync(podfile.path);
|
||||
}
|
||||
|
||||
_addPodsDependencyToFlutterXcconfig(appDirectory, 'Debug');
|
||||
_addPodsDependencyToFlutterXcconfig(appDirectory, 'Release');
|
||||
_addPodsDependencyToFlutterXcconfig(iosProject, 'Debug');
|
||||
_addPodsDependencyToFlutterXcconfig(iosProject, 'Release');
|
||||
}
|
||||
|
||||
void _addPodsDependencyToFlutterXcconfig(String appDirectory, String mode) {
|
||||
final File file = fs.file(fs.path.join(appDirectory, 'ios', 'Flutter', '$mode.xcconfig'));
|
||||
void _addPodsDependencyToFlutterXcconfig(IosProject iosProject, String mode) {
|
||||
final File file = iosProject.xcodeConfigFor(mode);
|
||||
if (file.existsSync()) {
|
||||
final String content = file.readAsStringSync();
|
||||
final String include = '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.${mode
|
||||
|
@ -192,12 +191,11 @@ class CocoaPods {
|
|||
}
|
||||
|
||||
/// Ensures that pod install is deemed needed on next check.
|
||||
void invalidatePodInstallOutput(String appDirectory) {
|
||||
final File manifest = fs.file(
|
||||
fs.path.join(appDirectory, 'ios', 'Pods', 'Manifest.lock'),
|
||||
);
|
||||
if (manifest.existsSync())
|
||||
manifest.deleteSync();
|
||||
void invalidatePodInstallOutput(IosProject iosProject) {
|
||||
final File manifestLock = iosProject.podManifestLock;
|
||||
if (manifestLock.existsSync()) {
|
||||
manifestLock.deleteSync();
|
||||
}
|
||||
}
|
||||
|
||||
// Check if you need to run pod install.
|
||||
|
@ -206,24 +204,25 @@ class CocoaPods {
|
|||
// 2. Podfile.lock doesn't exist or is older than Podfile
|
||||
// 3. Pods/Manifest.lock doesn't exist (It is deleted when plugins change)
|
||||
// 4. Podfile.lock doesn't match Pods/Manifest.lock.
|
||||
bool _shouldRunPodInstall(Directory appIosDirectory, bool dependenciesChanged) {
|
||||
bool _shouldRunPodInstall(IosProject iosProject, bool dependenciesChanged) {
|
||||
if (dependenciesChanged)
|
||||
return true;
|
||||
final File podfileFile = appIosDirectory.childFile('Podfile');
|
||||
final File podfileLockFile = appIosDirectory.childFile('Podfile.lock');
|
||||
final File manifestLockFile =
|
||||
appIosDirectory.childFile(fs.path.join('Pods', 'Manifest.lock'));
|
||||
|
||||
final File podfileFile = iosProject.podfile;
|
||||
final File podfileLockFile = iosProject.podfileLock;
|
||||
final File manifestLockFile = iosProject.podManifestLock;
|
||||
|
||||
return !podfileLockFile.existsSync()
|
||||
|| !manifestLockFile.existsSync()
|
||||
|| podfileLockFile.statSync().modified.isBefore(podfileFile.statSync().modified)
|
||||
|| podfileLockFile.readAsStringSync() != manifestLockFile.readAsStringSync();
|
||||
}
|
||||
|
||||
Future<Null> _runPodInstall(Directory appIosDirectory, String engineDirectory) async {
|
||||
Future<Null> _runPodInstall(IosProject iosProject, String engineDirectory) async {
|
||||
final Status status = logger.startProgress('Running pod install...', expectSlowOperation: true);
|
||||
final ProcessResult result = await processManager.run(
|
||||
<String>['pod', 'install', '--verbose'],
|
||||
workingDirectory: appIosDirectory.path,
|
||||
workingDirectory: iosProject.directory.path,
|
||||
environment: <String, String>{
|
||||
// For backward compatibility with previously created Podfile only.
|
||||
'FLUTTER_FRAMEWORK_DIR': engineDirectory,
|
||||
|
@ -244,7 +243,7 @@ class CocoaPods {
|
|||
}
|
||||
}
|
||||
if (result.exitCode != 0) {
|
||||
invalidatePodInstallOutput(appIosDirectory.parent.path);
|
||||
invalidatePodInstallOutput(iosProject);
|
||||
_diagnosePodInstallFailure(result);
|
||||
throwToolExit('Error running pod install');
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ import '../base/process.dart';
|
|||
import '../base/process_manager.dart';
|
||||
import '../base/utils.dart';
|
||||
import '../build_info.dart';
|
||||
import '../flutter_manifest.dart';
|
||||
import '../globals.dart';
|
||||
import '../plugins.dart';
|
||||
import '../project.dart';
|
||||
import '../services.dart';
|
||||
import 'cocoapods.dart';
|
||||
import 'code_signing.dart';
|
||||
|
@ -221,18 +221,15 @@ Future<XcodeBuildResult> buildXcodeProject({
|
|||
final Directory appDirectory = fs.directory(app.appDirectory);
|
||||
await _addServicesToBundle(appDirectory);
|
||||
|
||||
final FlutterManifest manifest = await FlutterManifest.createFromPath(
|
||||
fs.currentDirectory.childFile('pubspec.yaml').path,
|
||||
);
|
||||
updateGeneratedXcodeProperties(
|
||||
projectPath: fs.currentDirectory.path,
|
||||
buildInfo: buildInfo,
|
||||
final FlutterProject project = new FlutterProject(fs.currentDirectory);
|
||||
await updateGeneratedXcodeProperties(
|
||||
project: project,
|
||||
targetOverride: targetOverride,
|
||||
previewDart2: buildInfo.previewDart2,
|
||||
manifest: manifest,
|
||||
buildInfo: buildInfo,
|
||||
);
|
||||
|
||||
if (hasPlugins()) {
|
||||
if (hasPlugins(project)) {
|
||||
final String iosPath = fs.path.join(fs.currentDirectory.path, app.appDirectory);
|
||||
// If the Xcode project, Podfile, or Generated.xcconfig have changed since
|
||||
// last run, pods should be updated.
|
||||
|
@ -246,7 +243,7 @@ Future<XcodeBuildResult> buildXcodeProject({
|
|||
properties: <String, String>{},
|
||||
);
|
||||
final bool didPodInstall = await cocoaPods.processPods(
|
||||
appIosDirectory: appDirectory,
|
||||
iosProject: project.ios,
|
||||
iosEngineDir: flutterFrameworkDir(buildInfo.mode),
|
||||
isSwift: app.isSwift,
|
||||
dependenciesChanged: !await fingerprinter.doesFingerprintMatch()
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../artifacts.dart';
|
||||
|
@ -17,6 +19,7 @@ import '../bundle.dart' as bundle;
|
|||
import '../cache.dart';
|
||||
import '../flutter_manifest.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
|
||||
final RegExp _settingExpr = new RegExp(r'(\w+)\s*=\s*(.*)$');
|
||||
final RegExp _varExpr = new RegExp(r'\$\((.*)\)');
|
||||
|
@ -25,27 +28,18 @@ String flutterFrameworkDir(BuildMode mode) {
|
|||
return fs.path.normalize(fs.path.dirname(artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, mode)));
|
||||
}
|
||||
|
||||
String _generatedXcodePropertiesPath({@required String projectPath, @required FlutterManifest manifest}) {
|
||||
if (manifest.isModule) {
|
||||
return fs.path.join(projectPath, '.ios', 'Flutter', 'Generated.xcconfig');
|
||||
} else {
|
||||
return fs.path.join(projectPath, 'ios', 'Flutter', 'Generated.xcconfig');
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes default Xcode properties files in the Flutter project at [projectPath],
|
||||
/// if project is an iOS project and such files are out of date or do not
|
||||
/// already exist.
|
||||
void generateXcodeProperties({String projectPath, FlutterManifest manifest}) {
|
||||
if (manifest.isModule || fs.isDirectorySync(fs.path.join(projectPath, 'ios'))) {
|
||||
final File propertiesFile = fs.file(_generatedXcodePropertiesPath(projectPath: projectPath, manifest: manifest));
|
||||
if (!Cache.instance.fileOlderThanToolsStamp(propertiesFile)) {
|
||||
Future<void> generateXcodeProperties({FlutterProject project}) async {
|
||||
if ((await project.manifest).isModule ||
|
||||
project.ios.directory.existsSync()) {
|
||||
if (!Cache.instance.fileOlderThanToolsStamp(await project.generatedXcodePropertiesFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateGeneratedXcodeProperties(
|
||||
projectPath: projectPath,
|
||||
manifest: manifest,
|
||||
await updateGeneratedXcodeProperties(
|
||||
project: project,
|
||||
buildInfo: BuildInfo.debug,
|
||||
targetOverride: bundle.defaultMainPath,
|
||||
previewDart2: true,
|
||||
|
@ -57,13 +51,12 @@ void generateXcodeProperties({String projectPath, FlutterManifest manifest}) {
|
|||
///
|
||||
/// targetOverride: Optional parameter, if null or unspecified the default value
|
||||
/// from xcode_backend.sh is used 'lib/main.dart'.
|
||||
void updateGeneratedXcodeProperties({
|
||||
@required String projectPath,
|
||||
@required FlutterManifest manifest,
|
||||
Future<void> updateGeneratedXcodeProperties({
|
||||
@required FlutterProject project,
|
||||
@required BuildInfo buildInfo,
|
||||
String targetOverride,
|
||||
@required bool previewDart2,
|
||||
}) {
|
||||
}) async {
|
||||
final StringBuffer localsBuffer = new StringBuffer();
|
||||
|
||||
localsBuffer.writeln('// This is a generated file; do not edit or check into version control.');
|
||||
|
@ -72,7 +65,7 @@ void updateGeneratedXcodeProperties({
|
|||
localsBuffer.writeln('FLUTTER_ROOT=$flutterRoot');
|
||||
|
||||
// This holds because requiresProjectRoot is true for this command
|
||||
localsBuffer.writeln('FLUTTER_APPLICATION_PATH=${fs.path.normalize(projectPath)}');
|
||||
localsBuffer.writeln('FLUTTER_APPLICATION_PATH=${fs.path.normalize(project.directory.path)}');
|
||||
|
||||
// Relative to FLUTTER_APPLICATION_PATH, which is [Directory.current].
|
||||
if (targetOverride != null)
|
||||
|
@ -86,6 +79,7 @@ void updateGeneratedXcodeProperties({
|
|||
|
||||
localsBuffer.writeln('SYMROOT=\${SOURCE_ROOT}/../${getIosBuildDirectory()}');
|
||||
|
||||
final FlutterManifest manifest = await project.manifest;
|
||||
if (!manifest.isModule) {
|
||||
// For module projects we do not want to write the FLUTTER_FRAMEWORK_DIR
|
||||
// explicitly. Rather we rely on the xcode backend script and the Podfile
|
||||
|
@ -125,9 +119,9 @@ void updateGeneratedXcodeProperties({
|
|||
localsBuffer.writeln('TRACK_WIDGET_CREATION=true');
|
||||
}
|
||||
|
||||
final File localsFile = fs.file(_generatedXcodePropertiesPath(projectPath: projectPath, manifest: manifest));
|
||||
localsFile.createSync(recursive: true);
|
||||
localsFile.writeAsStringSync(localsBuffer.toString());
|
||||
final File generatedXcodePropertiesFile = await project.generatedXcodePropertiesFile;
|
||||
generatedXcodePropertiesFile.createSync(recursive: true);
|
||||
generatedXcodePropertiesFile.writeAsStringSync(localsBuffer.toString());
|
||||
}
|
||||
|
||||
XcodeProjectInterpreter get xcodeProjectInterpreter => context[XcodeProjectInterpreter];
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:mustache/mustache.dart' as mustache;
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'base/file_system.dart';
|
||||
import 'dart/package_map.dart';
|
||||
import 'flutter_manifest.dart';
|
||||
import 'globals.dart';
|
||||
import 'ios/cocoapods.dart';
|
||||
import 'project.dart';
|
||||
|
||||
void _renderTemplateToFile(String template, dynamic context, String filePath) {
|
||||
final String renderedTemplate =
|
||||
|
@ -69,11 +70,11 @@ Plugin _pluginFromPubspec(String name, Uri packageRoot) {
|
|||
return new Plugin.fromYaml(name, packageRootPath, flutterConfig['plugin']);
|
||||
}
|
||||
|
||||
List<Plugin> findPlugins(String directory) {
|
||||
List<Plugin> findPlugins(FlutterProject project) {
|
||||
final List<Plugin> plugins = <Plugin>[];
|
||||
Map<String, Uri> packages;
|
||||
try {
|
||||
final String packagesFile = fs.path.join(directory, PackageMap.globalPackagesPath);
|
||||
final String packagesFile = fs.path.join(project.directory.path, PackageMap.globalPackagesPath);
|
||||
packages = new PackageMap(packagesFile).map;
|
||||
} on FormatException catch (e) {
|
||||
printTrace('Invalid .packages file: $e');
|
||||
|
@ -89,9 +90,9 @@ List<Plugin> findPlugins(String directory) {
|
|||
}
|
||||
|
||||
/// Returns true if .flutter-plugins has changed, otherwise returns false.
|
||||
bool _writeFlutterPluginsList(String directory, List<Plugin> plugins) {
|
||||
final File pluginsFile = fs.file(fs.path.join(directory, '.flutter-plugins'));
|
||||
final String oldContents = _readFlutterPluginsList(directory);
|
||||
bool _writeFlutterPluginsList(FlutterProject project, List<Plugin> plugins) {
|
||||
final File pluginsFile = project.flutterPluginsFile;
|
||||
final String oldContents = _readFlutterPluginsList(project);
|
||||
final String pluginManifest =
|
||||
plugins.map((Plugin p) => '${p.name}=${escapePath(p.path)}').join('\n');
|
||||
if (pluginManifest.isNotEmpty) {
|
||||
|
@ -100,15 +101,16 @@ bool _writeFlutterPluginsList(String directory, List<Plugin> plugins) {
|
|||
if (pluginsFile.existsSync())
|
||||
pluginsFile.deleteSync();
|
||||
}
|
||||
final String newContents = _readFlutterPluginsList(directory);
|
||||
final String newContents = _readFlutterPluginsList(project);
|
||||
return oldContents != newContents;
|
||||
}
|
||||
|
||||
/// Returns the contents of the `.flutter-plugins` file in [directory], or
|
||||
/// null if that file does not exist.
|
||||
String _readFlutterPluginsList(String directory) {
|
||||
final File pluginsFile = fs.file(fs.path.join(directory, '.flutter-plugins'));
|
||||
return pluginsFile.existsSync() ? pluginsFile.readAsStringSync() : null;
|
||||
String _readFlutterPluginsList(FlutterProject project) {
|
||||
return project.flutterPluginsFile.existsSync()
|
||||
? project.flutterPluginsFile.readAsStringSync()
|
||||
: null;
|
||||
}
|
||||
|
||||
const String _androidPluginRegistryTemplate = '''package io.flutter.plugins;
|
||||
|
@ -142,7 +144,7 @@ public final class GeneratedPluginRegistrant {
|
|||
}
|
||||
''';
|
||||
|
||||
void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) {
|
||||
Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
|
||||
final List<Map<String, dynamic>> androidPlugins = plugins
|
||||
.where((Plugin p) => p.androidPackage != null && p.pluginClass != null)
|
||||
.map((Plugin p) => <String, dynamic>{
|
||||
|
@ -155,8 +157,19 @@ void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) {
|
|||
'plugins': androidPlugins,
|
||||
};
|
||||
|
||||
final String javaSourcePath = fs.path.join(directory, 'src', 'main', 'java');
|
||||
final String registryPath = fs.path.join(javaSourcePath, 'io', 'flutter', 'plugins', 'GeneratedPluginRegistrant.java');
|
||||
final String javaSourcePath = fs.path.join(
|
||||
(await project.androidPluginRegistrantHost).path,
|
||||
'src',
|
||||
'main',
|
||||
'java',
|
||||
);
|
||||
final String registryPath = fs.path.join(
|
||||
javaSourcePath,
|
||||
'io',
|
||||
'flutter',
|
||||
'plugins',
|
||||
'GeneratedPluginRegistrant.java',
|
||||
);
|
||||
_renderTemplateToFile(_androidPluginRegistryTemplate, context, registryPath);
|
||||
}
|
||||
|
||||
|
@ -221,7 +234,7 @@ Depends on all your plugins, and provides a function to register them.
|
|||
end
|
||||
''';
|
||||
|
||||
void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List<Plugin> plugins) {
|
||||
Future<void> _writeIOSPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
|
||||
final List<Map<String, dynamic>> iosPlugins = plugins
|
||||
.where((Plugin p) => p.pluginClass != null)
|
||||
.map((Plugin p) => <String, dynamic>{
|
||||
|
@ -234,10 +247,8 @@ void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List<
|
|||
'plugins': iosPlugins,
|
||||
};
|
||||
|
||||
if (manifest.isModule) {
|
||||
// In a module create the GeneratedPluginRegistrant as a pod to be included
|
||||
// from a hosting app.
|
||||
final String registryDirectory = fs.path.join(directory, 'Flutter', 'FlutterPluginRegistrant');
|
||||
final String registryDirectory = (await project.iosPluginRegistrantHost).path;
|
||||
if ((await project.manifest).isModule) {
|
||||
final String registryClassesDirectory = fs.path.join(registryDirectory, 'Classes');
|
||||
_renderTemplateToFile(
|
||||
_iosPluginRegistrantPodspecTemplate,
|
||||
|
@ -255,57 +266,37 @@ void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List<
|
|||
fs.path.join(registryClassesDirectory, 'GeneratedPluginRegistrant.m'),
|
||||
);
|
||||
} else {
|
||||
// For a non-module create the GeneratedPluginRegistrant as source files
|
||||
// directly in the ios project.
|
||||
final String runnerDirectory = fs.path.join(directory, 'Runner');
|
||||
_renderTemplateToFile(
|
||||
_iosPluginRegistryHeaderTemplate,
|
||||
context,
|
||||
fs.path.join(runnerDirectory, 'GeneratedPluginRegistrant.h'),
|
||||
fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.h'),
|
||||
);
|
||||
_renderTemplateToFile(
|
||||
_iosPluginRegistryImplementationTemplate,
|
||||
context,
|
||||
fs.path.join(runnerDirectory, 'GeneratedPluginRegistrant.m'),
|
||||
fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.m'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class InjectPluginsResult{
|
||||
InjectPluginsResult({
|
||||
@required this.hasPlugin,
|
||||
@required this.hasChanged,
|
||||
});
|
||||
/// True if any flutter plugin exists, otherwise false.
|
||||
final bool hasPlugin;
|
||||
/// True if plugins have changed since last build.
|
||||
final bool hasChanged;
|
||||
}
|
||||
|
||||
/// Injects plugins found in `pubspec.yaml` into the platform-specific projects.
|
||||
void injectPlugins({@required String projectPath, @required FlutterManifest manifest}) {
|
||||
final List<Plugin> plugins = findPlugins(projectPath);
|
||||
final bool changed = _writeFlutterPluginsList(projectPath, plugins);
|
||||
if (manifest.isModule) {
|
||||
_writeAndroidPluginRegistrant(fs.path.join(projectPath, '.android', 'Flutter'), plugins);
|
||||
} else if (fs.isDirectorySync(fs.path.join(projectPath, 'android', 'app'))) {
|
||||
_writeAndroidPluginRegistrant(fs.path.join(projectPath, 'android', 'app'), plugins);
|
||||
}
|
||||
if (manifest.isModule) {
|
||||
_writeIOSPluginRegistrant(fs.path.join(projectPath, '.ios'), manifest, plugins);
|
||||
} else if (fs.isDirectorySync(fs.path.join(projectPath, 'ios'))) {
|
||||
_writeIOSPluginRegistrant(fs.path.join(projectPath, 'ios'), manifest, plugins);
|
||||
Future<void> injectPlugins(FlutterProject project) async {
|
||||
final List<Plugin> plugins = findPlugins(project);
|
||||
final bool changed = _writeFlutterPluginsList(project, plugins);
|
||||
await _writeAndroidPluginRegistrant(project, plugins);
|
||||
await _writeIOSPluginRegistrant(project, plugins);
|
||||
|
||||
if (project.ios.directory.existsSync()) {
|
||||
final CocoaPods cocoaPods = new CocoaPods();
|
||||
if (plugins.isNotEmpty)
|
||||
cocoaPods.setupPodfile(projectPath, manifest);
|
||||
cocoaPods.setupPodfile(project.ios);
|
||||
if (changed)
|
||||
cocoaPods.invalidatePodInstallOutput(projectPath);
|
||||
cocoaPods.invalidatePodInstallOutput(project.ios);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the Flutter project at the specified [directory]
|
||||
/// has any plugin dependencies.
|
||||
bool hasPlugins({String directory}) {
|
||||
directory ??= fs.currentDirectory.path;
|
||||
return _readFlutterPluginsList(directory) != null;
|
||||
bool hasPlugins(FlutterProject project) {
|
||||
return _readFlutterPluginsList(project) != null;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
|
||||
import 'android/gradle.dart' as gradle;
|
||||
import 'base/file_system.dart';
|
||||
import 'bundle.dart' as bundle;
|
||||
|
@ -67,6 +66,57 @@ class FlutterProject {
|
|||
/// The generated IosModule sub project of this module project.
|
||||
IosModuleProject get iosModule => new IosModuleProject(directory.childDirectory('.ios'));
|
||||
|
||||
Future<File> get androidLocalPropertiesFile {
|
||||
return _androidLocalPropertiesFile ??= manifest.then<File>((FlutterManifest manifest) {
|
||||
return directory.childDirectory(manifest.isModule ? '.android' : 'android')
|
||||
.childFile('local.properties');
|
||||
});
|
||||
}
|
||||
Future<File> _androidLocalPropertiesFile;
|
||||
|
||||
Future<File> get generatedXcodePropertiesFile {
|
||||
return _generatedXcodeProperties ??= manifest.then<File>((FlutterManifest manifest) {
|
||||
return directory.childDirectory(manifest.isModule ? '.ios' : 'ios')
|
||||
.childDirectory('Flutter')
|
||||
.childFile('Generated.xcconfig');
|
||||
});
|
||||
}
|
||||
Future<File> _generatedXcodeProperties;
|
||||
|
||||
File get flutterPluginsFile {
|
||||
return _flutterPluginsFile ??= directory.childFile('.flutter-plugins');
|
||||
}
|
||||
File _flutterPluginsFile;
|
||||
|
||||
Future<Directory> get androidPluginRegistrantHost async {
|
||||
return _androidPluginRegistrantHost ??= manifest.then((FlutterManifest manifest) {
|
||||
if (manifest.isModule) {
|
||||
return directory.childDirectory('.android').childDirectory('Flutter');
|
||||
} else {
|
||||
return directory.childDirectory('android').childDirectory('app');
|
||||
}
|
||||
});
|
||||
}
|
||||
Future<Directory> _androidPluginRegistrantHost;
|
||||
|
||||
Future<Directory> get iosPluginRegistrantHost async {
|
||||
return _iosPluginRegistrantHost ??= manifest.then((FlutterManifest manifest) {
|
||||
if (manifest.isModule) {
|
||||
// In a module create the GeneratedPluginRegistrant as a pod to be included
|
||||
// from a hosting app.
|
||||
return directory
|
||||
.childDirectory('.ios')
|
||||
.childDirectory('Flutter')
|
||||
.childDirectory('FlutterPluginRegistrant');
|
||||
} else {
|
||||
// For a non-module create the GeneratedPluginRegistrant as source files
|
||||
// directly in the iOS project.
|
||||
return directory.childDirectory('ios').childDirectory('Runner');
|
||||
}
|
||||
});
|
||||
}
|
||||
Future<Directory> _iosPluginRegistrantHost;
|
||||
|
||||
/// Returns true if this project has an example application
|
||||
bool get hasExampleApp => _exampleDirectory.childFile('pubspec.yaml').existsSync();
|
||||
|
||||
|
@ -86,11 +136,11 @@ class FlutterProject {
|
|||
}
|
||||
final FlutterManifest manifest = await this.manifest;
|
||||
if (manifest.isModule) {
|
||||
await androidModule.ensureReadyForPlatformSpecificTooling(manifest);
|
||||
await iosModule.ensureReadyForPlatformSpecificTooling(manifest);
|
||||
await androidModule.ensureReadyForPlatformSpecificTooling(this);
|
||||
await iosModule.ensureReadyForPlatformSpecificTooling();
|
||||
}
|
||||
xcode.generateXcodeProperties(projectPath: directory.path, manifest: manifest);
|
||||
injectPlugins(projectPath: directory.path, manifest: manifest);
|
||||
await xcode.generateXcodeProperties(project: this);
|
||||
await injectPlugins(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +151,20 @@ class IosProject {
|
|||
|
||||
final Directory directory;
|
||||
|
||||
/// The xcode config file for [mode].
|
||||
File xcodeConfigFor(String mode) {
|
||||
return directory.childDirectory('Flutter').childFile('$mode.xcconfig');
|
||||
}
|
||||
|
||||
/// The 'Podfile'.
|
||||
File get podfile => directory.childFile('Podfile');
|
||||
|
||||
/// The 'Podfile.lock'.
|
||||
File get podfileLock => directory.childFile('Podfile.lock');
|
||||
|
||||
/// The 'Manifest.lock'.
|
||||
File get podManifestLock => directory.childDirectory('Pods').childFile('Manifest.lock');
|
||||
|
||||
Future<String> productBundleIdentifier() {
|
||||
final File projectFile = directory.childDirectory('Runner.xcodeproj').childFile('project.pbxproj');
|
||||
return _firstMatchInFile(projectFile, _productBundleIdPattern).then((Match match) => match?.group(1));
|
||||
|
@ -114,7 +178,7 @@ class IosModuleProject {
|
|||
|
||||
final Directory directory;
|
||||
|
||||
Future<void> ensureReadyForPlatformSpecificTooling(FlutterManifest manifest) async {
|
||||
Future<void> ensureReadyForPlatformSpecificTooling() async {
|
||||
if (_shouldRegenerate()) {
|
||||
final Template template = new Template.fromName(fs.path.join('module', 'ios'));
|
||||
template.render(directory, <String, dynamic>{}, printStatusWhenWriting: false);
|
||||
|
@ -133,6 +197,29 @@ class AndroidProject {
|
|||
|
||||
AndroidProject(this.directory);
|
||||
|
||||
File get gradleManifestFile {
|
||||
return _gradleManifestFile ??= isUsingGradle()
|
||||
? fs.file(fs.path.join(directory.path, 'app', 'src', 'main', 'AndroidManifest.xml'))
|
||||
: directory.childFile('AndroidManifest.xml');
|
||||
}
|
||||
File _gradleManifestFile;
|
||||
|
||||
|
||||
File get gradleAppOutV1File {
|
||||
return _gradleAppOutV1File ??= gradleAppOutV1Directory.childFile('app-debug.apk');
|
||||
}
|
||||
File _gradleAppOutV1File;
|
||||
|
||||
Directory get gradleAppOutV1Directory {
|
||||
return _gradleAppOutV1Directory ??= fs.directory(fs.path.join(directory.path, 'app', 'build', 'outputs', 'apk'));
|
||||
}
|
||||
Directory _gradleAppOutV1Directory;
|
||||
|
||||
|
||||
bool isUsingGradle() {
|
||||
return directory.childFile('build.gradle').existsSync();
|
||||
}
|
||||
|
||||
final Directory directory;
|
||||
|
||||
Future<String> applicationId() {
|
||||
|
@ -153,15 +240,15 @@ class AndroidModuleProject {
|
|||
|
||||
final Directory directory;
|
||||
|
||||
Future<void> ensureReadyForPlatformSpecificTooling(FlutterManifest manifest) async {
|
||||
Future<void> ensureReadyForPlatformSpecificTooling(FlutterProject project) async {
|
||||
if (_shouldRegenerate()) {
|
||||
final Template template = new Template.fromName(fs.path.join('module', 'android'));
|
||||
template.render(directory, <String, dynamic>{
|
||||
'androidIdentifier': manifest.moduleDescriptor['androidPackage'],
|
||||
'androidIdentifier': (await project.manifest).moduleDescriptor['androidPackage'],
|
||||
}, printStatusWhenWriting: false);
|
||||
gradle.injectGradleWrapper(directory);
|
||||
}
|
||||
gradle.updateLocalPropertiesSync(directory, manifest);
|
||||
await gradle.updateLocalProperties(project: project, requireAndroidSdk: false);
|
||||
}
|
||||
|
||||
bool _shouldRegenerate() {
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'dart:async';
|
|||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'android/gradle.dart';
|
||||
import 'application_package.dart';
|
||||
import 'artifacts.dart';
|
||||
import 'asset.dart';
|
||||
|
@ -24,6 +23,7 @@ import 'dependency_checker.dart';
|
|||
import 'devfs.dart';
|
||||
import 'device.dart';
|
||||
import 'globals.dart';
|
||||
import 'project.dart';
|
||||
import 'run_cold.dart';
|
||||
import 'run_hot.dart';
|
||||
import 'vmservice.dart';
|
||||
|
@ -814,15 +814,11 @@ abstract class ResidentRunner {
|
|||
new DartDependencySetBuilder(mainPath, packagesFilePath);
|
||||
final DependencyChecker dependencyChecker =
|
||||
new DependencyChecker(dartDependencySetBuilder, assetBundle);
|
||||
final String path = device.package.packagePath;
|
||||
if (path == null)
|
||||
if (device.package.packagesFile == null || !device.package.packagesFile.existsSync()) {
|
||||
return true;
|
||||
final FileStat stat = fs.file(path).statSync();
|
||||
if (stat.type != FileSystemEntityType.FILE) // ignore: deprecated_member_use
|
||||
return true;
|
||||
if (!fs.file(path).existsSync())
|
||||
return true;
|
||||
final DateTime lastBuildTime = stat.modified;
|
||||
}
|
||||
final DateTime lastBuildTime = device.package.packagesFile.statSync().modified;
|
||||
|
||||
return dependencyChecker.check(lastBuildTime);
|
||||
}
|
||||
|
||||
|
@ -906,11 +902,9 @@ String getMissingPackageHintForPlatform(TargetPlatform platform) {
|
|||
case TargetPlatform.android_arm64:
|
||||
case TargetPlatform.android_x64:
|
||||
case TargetPlatform.android_x86:
|
||||
String manifest = 'android/AndroidManifest.xml';
|
||||
if (isProjectUsingGradle()) {
|
||||
manifest = gradleManifestPath;
|
||||
}
|
||||
return 'Is your project missing an $manifest?\nConsider running "flutter create ." to create one.';
|
||||
final FlutterProject project = new FlutterProject(fs.currentDirectory);
|
||||
final String manifestPath = fs.path.relative(project.android.gradleManifestFile.path);
|
||||
return 'Is your project missing an $manifestPath?\nConsider running "flutter create ." to create one.';
|
||||
case TargetPlatform.ios:
|
||||
return 'Is your project missing an ios/Runner/Info.plist?\nConsider running "flutter create ." to create one.';
|
||||
default:
|
||||
|
|
|
@ -30,7 +30,7 @@ class ColdRunner extends ResidentRunner {
|
|||
ipv6: ipv6);
|
||||
|
||||
final bool traceStartup;
|
||||
final String applicationBinary;
|
||||
final File applicationBinary;
|
||||
|
||||
@override
|
||||
Future<int> run({
|
||||
|
|
|
@ -64,7 +64,7 @@ class HotRunner extends ResidentRunner {
|
|||
ipv6: ipv6);
|
||||
|
||||
final bool benchmarkMode;
|
||||
final String applicationBinary;
|
||||
final File applicationBinary;
|
||||
final bool hostIsIde;
|
||||
Set<String> _dartDependencies;
|
||||
final String dillOutputPath;
|
||||
|
|
|
@ -22,21 +22,21 @@ import '../protocol_discovery.dart';
|
|||
import '../version.dart';
|
||||
|
||||
class FlutterTesterApp extends ApplicationPackage {
|
||||
final String _directory;
|
||||
final Directory _directory;
|
||||
|
||||
factory FlutterTesterApp.fromCurrentDirectory() {
|
||||
return new FlutterTesterApp._(fs.currentDirectory.path);
|
||||
return new FlutterTesterApp._(fs.currentDirectory);
|
||||
}
|
||||
|
||||
FlutterTesterApp._(String directory)
|
||||
FlutterTesterApp._(Directory directory)
|
||||
: _directory = directory,
|
||||
super(id: directory);
|
||||
super(id: directory.path);
|
||||
|
||||
@override
|
||||
String get name => fs.path.basename(_directory);
|
||||
String get name => _directory.basename;
|
||||
|
||||
@override
|
||||
String get packagePath => fs.path.join(_directory, '.packages');
|
||||
File get packagesFile => _directory.childFile('.packages');
|
||||
}
|
||||
|
||||
// TODO(scheglov): This device does not currently work with full restarts.
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
|
|||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/flutter_manifest.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:process/process.dart';
|
||||
|
@ -31,7 +32,7 @@ void main() {
|
|||
// This test is written to fail if our bots get Android SDKs in the future: shouldBeToolExit
|
||||
// will be null and our expectation would fail. That would remind us to make these tests
|
||||
// hermetic before adding Android SDKs to the bots.
|
||||
await updateLocalProperties();
|
||||
await updateLocalProperties(project: new FlutterProject(fs.currentDirectory));
|
||||
} on Exception catch (e) {
|
||||
shouldBeToolExit = e;
|
||||
}
|
||||
|
@ -69,7 +70,10 @@ someProperty: someValue
|
|||
buildDir: /Users/some/apps/hello/build/app
|
||||
someOtherProperty: someOtherValue
|
||||
''');
|
||||
expect(project.apkDirectory, fs.path.normalize('/Users/some/apps/hello/build/app/outputs/apk'));
|
||||
expect(
|
||||
fs.path.normalize(project.apkDirectory.path),
|
||||
fs.path.normalize('/Users/some/apps/hello/build/app/outputs/apk'),
|
||||
);
|
||||
});
|
||||
test('should extract default build variants from app properties', () {
|
||||
final GradleProject project = projectFrom('''
|
||||
|
@ -110,27 +114,27 @@ someOtherProperty: someOtherValue
|
|||
expect(project.productFlavors, <String>['free', 'paid']);
|
||||
});
|
||||
test('should provide apk file name for default build types', () {
|
||||
final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>[], '/some/dir');
|
||||
final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir'));
|
||||
expect(project.apkFileFor(BuildInfo.debug), 'app-debug.apk');
|
||||
expect(project.apkFileFor(BuildInfo.profile), 'app-profile.apk');
|
||||
expect(project.apkFileFor(BuildInfo.release), 'app-release.apk');
|
||||
expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
|
||||
});
|
||||
test('should provide apk file name for flavored build types', () {
|
||||
final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], '/some/dir');
|
||||
final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir'));
|
||||
expect(project.apkFileFor(const BuildInfo(BuildMode.debug, 'free')), 'app-free-debug.apk');
|
||||
expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'paid')), 'app-paid-release.apk');
|
||||
expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
|
||||
});
|
||||
test('should provide assemble task name for default build types', () {
|
||||
final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>[], '/some/dir');
|
||||
final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir'));
|
||||
expect(project.assembleTaskFor(BuildInfo.debug), 'assembleDebug');
|
||||
expect(project.assembleTaskFor(BuildInfo.profile), 'assembleProfile');
|
||||
expect(project.assembleTaskFor(BuildInfo.release), 'assembleRelease');
|
||||
expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
|
||||
});
|
||||
test('should provide assemble task name for flavored build types', () {
|
||||
final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], '/some/dir');
|
||||
final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir'));
|
||||
expect(project.assembleTaskFor(const BuildInfo(BuildMode.debug, 'free')), 'assembleFreeDebug');
|
||||
expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'paid')), 'assemblePaidRelease');
|
||||
expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
|
||||
|
@ -185,7 +189,10 @@ someOtherProperty: someOtherValue
|
|||
writeSchemaFile(fs, schemaData);
|
||||
|
||||
try {
|
||||
await updateLocalProperties(projectPath: 'path/to/project', buildInfo: buildInfo);
|
||||
await updateLocalProperties(
|
||||
project: new FlutterProject.fromPath('path/to/project'),
|
||||
buildInfo: buildInfo,
|
||||
);
|
||||
|
||||
final File localPropertiesFile = fs.file('path/to/project/android/local.properties');
|
||||
expect(propertyFor('flutter.versionName', localPropertiesFile), expectedBuildName);
|
||||
|
|
|
@ -57,7 +57,7 @@ void main() {
|
|||
};
|
||||
testUsingContext('Error on non-existing file', () {
|
||||
final PrebuiltIOSApp iosApp =
|
||||
new IOSApp.fromPrebuiltApp('not_existing.ipa');
|
||||
new IOSApp.fromPrebuiltApp(fs.file('not_existing.ipa'));
|
||||
expect(iosApp, isNull);
|
||||
final BufferLogger logger = context[Logger];
|
||||
expect(
|
||||
|
@ -68,7 +68,7 @@ void main() {
|
|||
testUsingContext('Error on non-app-bundle folder', () {
|
||||
fs.directory('regular_folder').createSync();
|
||||
final PrebuiltIOSApp iosApp =
|
||||
new IOSApp.fromPrebuiltApp('regular_folder');
|
||||
new IOSApp.fromPrebuiltApp(fs.file('regular_folder'));
|
||||
expect(iosApp, isNull);
|
||||
final BufferLogger logger = context[Logger];
|
||||
expect(
|
||||
|
@ -76,7 +76,7 @@ void main() {
|
|||
}, overrides: overrides);
|
||||
testUsingContext('Error on no info.plist', () {
|
||||
fs.directory('bundle.app').createSync();
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp('bundle.app');
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('bundle.app'));
|
||||
expect(iosApp, isNull);
|
||||
final BufferLogger logger = context[Logger];
|
||||
expect(
|
||||
|
@ -87,7 +87,7 @@ void main() {
|
|||
testUsingContext('Error on bad info.plist', () {
|
||||
fs.directory('bundle.app').createSync();
|
||||
fs.file('bundle.app/Info.plist').writeAsStringSync(badPlistData);
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp('bundle.app');
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('bundle.app'));
|
||||
expect(iosApp, isNull);
|
||||
final BufferLogger logger = context[Logger];
|
||||
expect(
|
||||
|
@ -99,7 +99,7 @@ void main() {
|
|||
testUsingContext('Success with app bundle', () {
|
||||
fs.directory('bundle.app').createSync();
|
||||
fs.file('bundle.app/Info.plist').writeAsStringSync(plistData);
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp('bundle.app');
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('bundle.app'));
|
||||
final BufferLogger logger = context[Logger];
|
||||
expect(logger.errorText, isEmpty);
|
||||
expect(iosApp.bundleDir.path, 'bundle.app');
|
||||
|
@ -109,7 +109,7 @@ void main() {
|
|||
testUsingContext('Bad ipa zip-file, no payload dir', () {
|
||||
fs.file('app.ipa').createSync();
|
||||
when(os.unzip(fs.file('app.ipa'), any)).thenAnswer((Invocation _) {});
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp('app.ipa');
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('app.ipa'));
|
||||
expect(iosApp, isNull);
|
||||
final BufferLogger logger = context[Logger];
|
||||
expect(
|
||||
|
@ -132,7 +132,7 @@ void main() {
|
|||
fs.directory(bundlePath1).createSync(recursive: true);
|
||||
fs.directory(bundlePath2).createSync(recursive: true);
|
||||
});
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp('app.ipa');
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('app.ipa'));
|
||||
expect(iosApp, isNull);
|
||||
final BufferLogger logger = context[Logger];
|
||||
expect(logger.errorText,
|
||||
|
@ -153,7 +153,7 @@ void main() {
|
|||
.file(fs.path.join(bundleAppDir.path, 'Info.plist'))
|
||||
.writeAsStringSync(plistData);
|
||||
});
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp('app.ipa');
|
||||
final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('app.ipa'));
|
||||
final BufferLogger logger = context[Logger];
|
||||
expect(logger.errorText, isEmpty);
|
||||
expect(iosApp.bundleDir.path, endsWith('bundle.app'));
|
||||
|
|
|
@ -9,7 +9,6 @@ import 'package:file/memory.dart';
|
|||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/flutter_manifest.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/ios/cocoapods.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
|
@ -25,7 +24,7 @@ void main() {
|
|||
FileSystem fs;
|
||||
ProcessManager mockProcessManager;
|
||||
MockXcodeProjectInterpreter mockXcodeProjectInterpreter;
|
||||
Directory projectUnderTest;
|
||||
FlutterProject projectUnderTest;
|
||||
CocoaPods cocoaPodsUnderTest;
|
||||
InvokeProcess resultOfPodVersion;
|
||||
|
||||
|
@ -46,7 +45,8 @@ void main() {
|
|||
fs = new MemoryFileSystem();
|
||||
mockProcessManager = new MockProcessManager();
|
||||
mockXcodeProjectInterpreter = new MockXcodeProjectInterpreter();
|
||||
projectUnderTest = fs.directory(fs.path.join('project', 'ios'))..createSync(recursive: true);
|
||||
projectUnderTest = new FlutterProject(fs.directory('project'));
|
||||
projectUnderTest.ios.directory.createSync(recursive: true);
|
||||
cocoaPodsUnderTest = new CocoaPods();
|
||||
pretendPodVersionIs('1.5.0');
|
||||
fs.file(fs.path.join(
|
||||
|
@ -124,22 +124,10 @@ void main() {
|
|||
});
|
||||
|
||||
group('Setup Podfile', () {
|
||||
File podFile;
|
||||
File debugConfigFile;
|
||||
File releaseConfigFile;
|
||||
|
||||
setUp(() {
|
||||
debugConfigFile = fs.file(fs.path.join('project', 'ios', 'Flutter', 'Debug.xcconfig'));
|
||||
releaseConfigFile = fs.file(fs.path.join('project', 'ios', 'Flutter', 'Release.xcconfig'));
|
||||
podFile = fs.file(fs.path.join('project', 'ios', 'Podfile'));
|
||||
});
|
||||
|
||||
testUsingContext('creates objective-c Podfile when not present', () async {
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('project').manifest;
|
||||
cocoaPodsUnderTest.setupPodfile('project', manifest);
|
||||
cocoaPodsUnderTest.setupPodfile(projectUnderTest.ios);
|
||||
|
||||
expect(podFile.readAsStringSync(), 'Objective-C podfile template');
|
||||
expect(projectUnderTest.ios.podfile.readAsStringSync(), 'Objective-C podfile template');
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
});
|
||||
|
@ -150,24 +138,22 @@ void main() {
|
|||
'SWIFT_VERSION': '4.0',
|
||||
});
|
||||
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('project').manifest;
|
||||
cocoaPodsUnderTest.setupPodfile('project', manifest);
|
||||
final FlutterProject project = new FlutterProject.fromPath('project');
|
||||
cocoaPodsUnderTest.setupPodfile(project.ios);
|
||||
|
||||
expect(podFile.readAsStringSync(), 'Swift podfile template');
|
||||
expect(projectUnderTest.ios.podfile.readAsStringSync(), 'Swift podfile template');
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
|
||||
});
|
||||
|
||||
testUsingContext('does not recreate Podfile when already present', () async {
|
||||
podFile..createSync()..writeAsStringSync('Existing Podfile');
|
||||
projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Existing Podfile');
|
||||
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('project').manifest;
|
||||
cocoaPodsUnderTest.setupPodfile('project', manifest);
|
||||
final FlutterProject project = new FlutterProject.fromPath('project');
|
||||
cocoaPodsUnderTest.setupPodfile(project.ios);
|
||||
|
||||
expect(podFile.readAsStringSync(), 'Existing Podfile');
|
||||
expect(projectUnderTest.ios.podfile.readAsStringSync(), 'Existing Podfile');
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
});
|
||||
|
@ -175,30 +161,32 @@ void main() {
|
|||
testUsingContext('does not create Podfile when we cannot interpret Xcode projects', () async {
|
||||
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(false);
|
||||
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('project').manifest;
|
||||
cocoaPodsUnderTest.setupPodfile('project', manifest);
|
||||
final FlutterProject project = new FlutterProject.fromPath('project');
|
||||
cocoaPodsUnderTest.setupPodfile(project.ios);
|
||||
|
||||
expect(podFile.existsSync(), false);
|
||||
expect(projectUnderTest.ios.podfile.existsSync(), false);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
|
||||
});
|
||||
|
||||
testUsingContext('includes Pod config in xcconfig files, if not present', () async {
|
||||
podFile..createSync()..writeAsStringSync('Existing Podfile');
|
||||
debugConfigFile..createSync(recursive: true)..writeAsStringSync('Existing debug config');
|
||||
releaseConfigFile..createSync(recursive: true)..writeAsStringSync('Existing release config');
|
||||
projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Existing Podfile');
|
||||
projectUnderTest.ios.xcodeConfigFor('Debug')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('Existing debug config');
|
||||
projectUnderTest.ios.xcodeConfigFor('Release')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('Existing release config');
|
||||
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('project').manifest;
|
||||
cocoaPodsUnderTest.setupPodfile('project', manifest);
|
||||
final FlutterProject project = new FlutterProject.fromPath('project');
|
||||
cocoaPodsUnderTest.setupPodfile(project.ios);
|
||||
|
||||
final String debugContents = debugConfigFile.readAsStringSync();
|
||||
final String debugContents = projectUnderTest.ios.xcodeConfigFor('Debug').readAsStringSync();
|
||||
expect(debugContents, contains(
|
||||
'#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"\n'));
|
||||
expect(debugContents, contains('Existing debug config'));
|
||||
final String releaseContents = releaseConfigFile.readAsStringSync();
|
||||
final String releaseContents = projectUnderTest.ios.xcodeConfigFor('Release').readAsStringSync();
|
||||
expect(releaseContents, contains(
|
||||
'#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"\n'));
|
||||
expect(releaseContents, contains('Existing release config'));
|
||||
|
@ -210,9 +198,9 @@ void main() {
|
|||
group('Process pods', () {
|
||||
testUsingContext('prints error, if CocoaPods is not installed', () async {
|
||||
pretendPodIsNotInstalled();
|
||||
projectUnderTest.childFile('Podfile').createSync();
|
||||
projectUnderTest.ios.podfile.createSync();
|
||||
final bool didInstall = await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
);
|
||||
verifyNever(mockProcessManager.run(
|
||||
|
@ -231,7 +219,7 @@ void main() {
|
|||
testUsingContext('throws, if Podfile is missing.', () async {
|
||||
try {
|
||||
await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
);
|
||||
fail('ToolExit expected');
|
||||
|
@ -278,7 +266,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
|||
));
|
||||
try {
|
||||
await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
);
|
||||
fail('ToolExit expected');
|
||||
|
@ -295,14 +283,14 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
|||
});
|
||||
|
||||
testUsingContext('run pod install, if Podfile.lock is missing', () async {
|
||||
projectUnderTest.childFile('Podfile')
|
||||
projectUnderTest.ios.podfile
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing Podfile');
|
||||
projectUnderTest.childFile('Pods/Manifest.lock')
|
||||
projectUnderTest.ios.podManifestLock
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
final bool didInstall = await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
dependenciesChanged: false,
|
||||
);
|
||||
|
@ -318,14 +306,14 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
|||
});
|
||||
|
||||
testUsingContext('runs pod install, if Manifest.lock is missing', () async {
|
||||
projectUnderTest.childFile('Podfile')
|
||||
projectUnderTest.ios.podfile
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing Podfile');
|
||||
projectUnderTest.childFile('Podfile.lock')
|
||||
projectUnderTest.ios.podfileLock
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
final bool didInstall = await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
dependenciesChanged: false,
|
||||
);
|
||||
|
@ -344,17 +332,17 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
|||
});
|
||||
|
||||
testUsingContext('runs pod install, if Manifest.lock different from Podspec.lock', () async {
|
||||
projectUnderTest.childFile('Podfile')
|
||||
projectUnderTest.ios.podfile
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing Podfile');
|
||||
projectUnderTest.childFile('Podfile.lock')
|
||||
projectUnderTest.ios.podfileLock
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
projectUnderTest.childFile('Pods/Manifest.lock')
|
||||
projectUnderTest.ios.podManifestLock
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('Different lock file.');
|
||||
final bool didInstall = await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
dependenciesChanged: false,
|
||||
);
|
||||
|
@ -373,17 +361,17 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
|||
});
|
||||
|
||||
testUsingContext('runs pod install, if flutter framework changed', () async {
|
||||
projectUnderTest.childFile('Podfile')
|
||||
projectUnderTest.ios.podfile
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing Podfile');
|
||||
projectUnderTest.childFile('Podfile.lock')
|
||||
projectUnderTest.ios.podfileLock
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
projectUnderTest.childFile('Pods/Manifest.lock')
|
||||
projectUnderTest.ios.podManifestLock
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
final bool didInstall = await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
dependenciesChanged: true,
|
||||
);
|
||||
|
@ -402,20 +390,20 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
|||
});
|
||||
|
||||
testUsingContext('runs pod install, if Podfile.lock is older than Podfile', () async {
|
||||
projectUnderTest.childFile('Podfile')
|
||||
projectUnderTest.ios.podfile
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing Podfile');
|
||||
projectUnderTest.childFile('Podfile.lock')
|
||||
projectUnderTest.ios.podfileLock
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
projectUnderTest.childFile('Pods/Manifest.lock')
|
||||
projectUnderTest.ios.podManifestLock
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
await new Future<void>.delayed(const Duration(milliseconds: 10));
|
||||
projectUnderTest.childFile('Podfile')
|
||||
projectUnderTest.ios.podfile
|
||||
..writeAsStringSync('Updated Podfile');
|
||||
await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
dependenciesChanged: false,
|
||||
);
|
||||
|
@ -433,17 +421,17 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
|||
});
|
||||
|
||||
testUsingContext('skips pod install, if nothing changed', () async {
|
||||
projectUnderTest.childFile('Podfile')
|
||||
projectUnderTest.ios.podfile
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing Podfile');
|
||||
projectUnderTest.childFile('Podfile.lock')
|
||||
projectUnderTest.ios.podfileLock
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
projectUnderTest.childFile('Pods/Manifest.lock')
|
||||
projectUnderTest.ios.podManifestLock
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
final bool didInstall = await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
dependenciesChanged: false,
|
||||
);
|
||||
|
@ -459,13 +447,13 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
|||
});
|
||||
|
||||
testUsingContext('a failed pod install deletes Pods/Manifest.lock', () async {
|
||||
projectUnderTest.childFile('Podfile')
|
||||
projectUnderTest.ios.podfile
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing Podfile');
|
||||
projectUnderTest.childFile('Podfile.lock')
|
||||
projectUnderTest.ios.podfileLock
|
||||
..createSync()
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
projectUnderTest.childFile('Pods/Manifest.lock')
|
||||
projectUnderTest.ios.podManifestLock
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('Existing lock file.');
|
||||
|
||||
|
@ -482,13 +470,13 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
|
|||
|
||||
try {
|
||||
await cocoaPodsUnderTest.processPods(
|
||||
appIosDirectory: projectUnderTest,
|
||||
iosProject: projectUnderTest.ios,
|
||||
iosEngineDir: 'engine/path',
|
||||
dependenciesChanged: true,
|
||||
);
|
||||
fail('Tool throw expected when pod install fails');
|
||||
} on ToolExit {
|
||||
expect(projectUnderTest.childFile('Pods/Manifest.lock').existsSync(), isFalse);
|
||||
expect(projectUnderTest.ios.podManifestLock.existsSync(), isFalse);
|
||||
}
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
|
|
|
@ -289,11 +289,9 @@ Information about project "Runner":
|
|||
previewDart2: true,
|
||||
targetPlatform: TargetPlatform.ios,
|
||||
);
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('path/to/project').manifest;
|
||||
updateGeneratedXcodeProperties(
|
||||
projectPath: 'path/to/project',
|
||||
manifest: manifest,
|
||||
final FlutterProject project = new FlutterProject.fromPath('path/to/project');
|
||||
await updateGeneratedXcodeProperties(
|
||||
project: project,
|
||||
buildInfo: buildInfo,
|
||||
previewDart2: true,
|
||||
);
|
||||
|
@ -313,11 +311,9 @@ Information about project "Runner":
|
|||
trackWidgetCreation: true,
|
||||
targetPlatform: TargetPlatform.ios,
|
||||
);
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('path/to/project').manifest;
|
||||
updateGeneratedXcodeProperties(
|
||||
projectPath: 'path/to/project',
|
||||
manifest: manifest,
|
||||
final FlutterProject project = new FlutterProject.fromPath('path/to/project');
|
||||
await updateGeneratedXcodeProperties(
|
||||
project: project,
|
||||
buildInfo: buildInfo,
|
||||
previewDart2: true,
|
||||
);
|
||||
|
@ -336,11 +332,9 @@ Information about project "Runner":
|
|||
previewDart2: true,
|
||||
targetPlatform: TargetPlatform.ios,
|
||||
);
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('path/to/project').manifest;
|
||||
updateGeneratedXcodeProperties(
|
||||
projectPath: 'path/to/project',
|
||||
manifest: manifest,
|
||||
final FlutterProject project = new FlutterProject.fromPath('path/to/project');
|
||||
await updateGeneratedXcodeProperties(
|
||||
project: project,
|
||||
buildInfo: buildInfo,
|
||||
previewDart2: true,
|
||||
);
|
||||
|
@ -360,11 +354,9 @@ Information about project "Runner":
|
|||
targetPlatform: TargetPlatform.ios,
|
||||
);
|
||||
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('path/to/project').manifest;
|
||||
updateGeneratedXcodeProperties(
|
||||
projectPath: 'path/to/project',
|
||||
manifest: manifest,
|
||||
final FlutterProject project = new FlutterProject.fromPath('path/to/project');
|
||||
await updateGeneratedXcodeProperties(
|
||||
project: project,
|
||||
buildInfo: buildInfo,
|
||||
previewDart2: true,
|
||||
);
|
||||
|
@ -412,11 +404,8 @@ Information about project "Runner":
|
|||
const String schemaData = '{}';
|
||||
writeSchemaFile(fs, schemaData);
|
||||
|
||||
final FlutterManifest manifest =
|
||||
await new FlutterProject.fromPath('path/to/project').manifest;
|
||||
updateGeneratedXcodeProperties(
|
||||
projectPath: 'path/to/project',
|
||||
manifest: manifest,
|
||||
await updateGeneratedXcodeProperties(
|
||||
project: new FlutterProject.fromPath('path/to/project'),
|
||||
buildInfo: buildInfo,
|
||||
previewDart2: false,
|
||||
);
|
||||
|
|
|
@ -129,13 +129,6 @@ void testInMemory(String description, Future<Null> testMethod()) {
|
|||
);
|
||||
}
|
||||
|
||||
void addPubPackages(Directory directory) {
|
||||
directory.childFile('pubspec.yaml')
|
||||
..createSync(recursive: true);
|
||||
directory.childFile('.packages')
|
||||
..createSync(recursive: true);
|
||||
}
|
||||
|
||||
void addIosWithBundleId(Directory directory, String id) {
|
||||
directory
|
||||
.childDirectory('ios')
|
||||
|
|
|
@ -25,7 +25,7 @@ class MockApplicationPackageStore extends ApplicationPackageStore {
|
|||
MockApplicationPackageStore() : super(
|
||||
android: new AndroidApk(
|
||||
id: 'io.flutter.android.mock',
|
||||
apkPath: '/mock/path/to/android/SkyShell.apk',
|
||||
file: fs.file('/mock/path/to/android/SkyShell.apk'),
|
||||
launchActivity: 'io.flutter.android.mock.MockActivity'
|
||||
),
|
||||
iOS: new BuildableIOSApp(
|
||||
|
|
|
@ -33,7 +33,7 @@ void main() {
|
|||
|
||||
final FlutterTesterApp app = new FlutterTesterApp.fromCurrentDirectory();
|
||||
expect(app.name, 'my_project');
|
||||
expect(app.packagePath, fs.path.join(projectPath, '.packages'));
|
||||
expect(app.packagesFile.path, fs.path.join(projectPath, '.packages'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue