diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 7dcfaef6bc..15d0ff2c64 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -1021,6 +1021,7 @@ Future _androidGradleTests(String subShard) async { await _runDevicelabTest('gradle_plugin_light_apk_test', env: env); await _runDevicelabTest('gradle_plugin_fat_apk_test', env: env); await _runDevicelabTest('gradle_r8_test', env: env); + await _runDevicelabTest('gradle_non_android_plugin_test', env: env); } if (subShard == 'gradle2') { await _runDevicelabTest('gradle_plugin_bundle_test', env: env); diff --git a/dev/devicelab/bin/tasks/gradle_non_android_plugin_test.dart b/dev/devicelab/bin/tasks/gradle_non_android_plugin_test.dart new file mode 100644 index 0000000000..5cf66c42f3 --- /dev/null +++ b/dev/devicelab/bin/tasks/gradle_non_android_plugin_test.dart @@ -0,0 +1,107 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/framework/utils.dart'; +import 'package:path/path.dart' as path; + +/// Tests that a flutter app that depends on a non-Android plugin +/// (an iOS only plugin in this case) can still build for Android. +Future main() async { + await task(() async { + + section('Find Java'); + + final String javaHome = await findJavaHome(); + if (javaHome == null) + return TaskResult.failure('Could not find Java'); + print('\nUsing JAVA_HOME=$javaHome'); + + section('Create Flutter plugin project'); + + final Directory tempDir = Directory.systemTemp.createTempSync('flutter_plugin_test.'); + final Directory projectDir = Directory(path.join(tempDir.path, 'ios_only')); + try { + await inDirectory(tempDir, () async { + await flutter( + 'create', + options: [ + '--org', 'io.flutter.devicelab', + '-t', 'plugin', + 'ios_only', + ], + ); + }); + + section('Delete plugin\'s Android folder'); + + final File androidFolder = File(path.join( + projectDir.path, + 'android', + )); + androidFolder.deleteSync(recursive: true); + + section('Update pubspec.yaml to iOS only plugin'); + final File pubspecFile = File(path.join(projectDir.path, 'pubspec.yaml')); + final String pubspecString = pubspecFile.readAsStringSync(); + + final StringBuffer iosOnlyPubspec = StringBuffer(); + for (String line in pubspecString.split('\n')) { + if (line.startsWith(' androidPackage:')) { + continue; + } + if (line.startsWith(' pluginClass:')) { + iosOnlyPubspec.write(' platforms:\n'); + iosOnlyPubspec.write(' ios:\n'); + iosOnlyPubspec.write(' pluginClass: IosOnlyPlugin\n'); + continue; + } + iosOnlyPubspec.write('$line\n'); + } + + pubspecFile.writeAsStringSync(iosOnlyPubspec.toString()); + + section('Build example APK'); + + final StringBuffer stderr = StringBuffer(); + + final Directory exampleDir = Directory(path.join(projectDir.path, 'example')); + await inDirectory(exampleDir, () async { + await evalFlutter( + 'build', + options: [ + 'apk', + '--target-platform', 'android-arm', + '--verbose', + ], + canFail: true, + stderr: stderr, + ); + }); + + section('Check that the example APK was built'); + + final String exampleAppApk = path.join( + exampleDir.path, + 'build', + 'app', + 'outputs', + 'apk', + 'release', + 'app-release.apk', + ); + if (!exists(File(exampleAppApk))) { + return TaskResult.failure('Failed to build example app'); + } + return TaskResult.success(null); + } catch (e) { + return TaskResult.failure(e.toString()); + } finally { + rmTree(tempDir); + } + }); +} diff --git a/packages/flutter_tools/gradle/flutter.gradle b/packages/flutter_tools/gradle/flutter.gradle index 3e76802ea0..527a081daa 100644 --- a/packages/flutter_tools/gradle/flutter.gradle +++ b/packages/flutter_tools/gradle/flutter.gradle @@ -329,7 +329,18 @@ class FlutterPlugin implements Plugin { private Properties getPluginList() { File pluginsFile = new File(project.projectDir.parentFile.parentFile, '.flutter-plugins') - return readPropertiesIfExist(pluginsFile) + Properties allPlugins = readPropertiesIfExist(pluginsFile) + Properties androidPlugins = new Properties() + allPlugins.each { name, path -> + File editableAndroidProject = new File(path, 'android' + File.separator + 'build.gradle') + if (editableAndroidProject.exists()) { + androidPlugins.setProperty(name, path) + } + // TODO(amirh): log an error if this plugin was specified to be an Android + // plugin according to the new schema, and was missing a build.gradle file. + // https://github.com/flutter/flutter/issues/40784 + } + return androidPlugins } private void addPluginTasks() {