Skip to content

Commit 0e2f51d

Browse files
authored
FFI plugins (#96225)
1 parent f15dd78 commit 0e2f51d

File tree

59 files changed

+1441
-254
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1441
-254
lines changed

dev/devicelab/bin/tasks/plugin_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@ Future<void> main() async {
1818
<String, String>{'ENABLE_ANDROID_EMBEDDING_V2': 'true'}),
1919
// Test that Dart-only plugins are supported.
2020
PluginTest('apk', <String>['--platforms=android'], dartOnlyPlugin: true),
21+
// Test that FFI plugins are supported.
22+
PluginTest('apk', <String>['--platforms=android'], template: 'plugin_ffi'),
2123
]));
2224
}

dev/devicelab/bin/tasks/plugin_test_ios.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,8 @@ Future<void> main() async {
1313
// Test that Dart-only plugins are supported.
1414
PluginTest('ios', <String>['--platforms=ios'], dartOnlyPlugin: true),
1515
PluginTest('macos', <String>['--platforms=macos'], dartOnlyPlugin: true),
16+
// Test that FFI plugins are supported.
17+
PluginTest('ios', <String>['--platforms=ios'], template: 'plugin_ffi'),
18+
PluginTest('macos', <String>['--platforms=macos'], template: 'plugin_ffi'),
1619
]));
1720
}

dev/devicelab/lib/tasks/plugin_tests.dart

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,35 @@ class PluginTest {
3232
this.pluginCreateEnvironment,
3333
this.appCreateEnvironment,
3434
this.dartOnlyPlugin = false,
35+
this.template = 'plugin',
3536
});
3637

3738
final String buildTarget;
3839
final List<String> options;
3940
final Map<String, String>? pluginCreateEnvironment;
4041
final Map<String, String>? appCreateEnvironment;
4142
final bool dartOnlyPlugin;
43+
final String template;
4244

4345
Future<TaskResult> call() async {
4446
final Directory tempDir =
4547
Directory.systemTemp.createTempSync('flutter_devicelab_plugin_test.');
48+
// FFI plugins do not have support for `flutter test`.
49+
// `flutter test` does not do a native build.
50+
// Supporting `flutter test` would require invoking a native build.
51+
final bool runFlutterTest = template != 'plugin_ffi';
4652
try {
4753
section('Create plugin');
4854
final _FlutterProject plugin = await _FlutterProject.create(
4955
tempDir, options, buildTarget,
50-
name: 'plugintest', template: 'plugin', environment: pluginCreateEnvironment);
56+
name: 'plugintest', template: template, environment: pluginCreateEnvironment);
5157
if (dartOnlyPlugin) {
5258
await plugin.convertDefaultPluginToDartPlugin();
5359
}
5460
section('Test plugin');
55-
await plugin.test();
61+
if (runFlutterTest) {
62+
await plugin.test();
63+
}
5664
section('Create Flutter app');
5765
final _FlutterProject app = await _FlutterProject.create(tempDir, options, buildTarget,
5866
name: 'plugintestapp', template: 'app', environment: appCreateEnvironment);
@@ -63,8 +71,10 @@ class PluginTest {
6371
await app.addPlugin('path_provider');
6472
section('Build app');
6573
await app.build(buildTarget, validateNativeBuildProject: !dartOnlyPlugin);
66-
section('Test app');
67-
await app.test();
74+
if (runFlutterTest) {
75+
section('Test app');
76+
await app.test();
77+
}
6878
} finally {
6979
await plugin.delete();
7080
await app.delete();

dev/integration_tests/flutter_gallery/windows/flutter/generated_plugins.cmake

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ list(APPEND FLUTTER_PLUGIN_LIST
66
url_launcher_windows
77
)
88

9+
list(APPEND FLUTTER_FFI_PLUGIN_LIST
10+
)
11+
912
set(PLUGIN_BUNDLED_LIBRARIES)
1013

1114
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -14,3 +17,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
1417
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
1518
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
1619
endforeach(plugin)
20+
21+
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
22+
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
23+
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
24+
endforeach(ffi_plugin)

packages/flutter_tools/gradle/flutter.gradle

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ class FlutterExtension {
3838
/** Sets the targetSdkVersion used by default in Flutter app projects. */
3939
static int targetSdkVersion = 31
4040

41+
/**
42+
* Sets the ndkVersion used by default in Flutter app projects.
43+
* Chosen as default version of the AGP version below.
44+
*/
45+
static String ndkVersion = "21.1.6352462"
46+
4147
/**
4248
* Specifies the relative directory to the Flutter project directory.
4349
* In an app project, this is ../.. since the app's build.gradle is under android/app.
@@ -54,6 +60,7 @@ buildscript {
5460
mavenCentral()
5561
}
5662
dependencies {
63+
/* When bumping, also update ndkVersion above. */
5764
classpath 'com.android.tools.build:gradle:4.1.0'
5865
}
5966
}
@@ -409,24 +416,63 @@ class FlutterPlugin implements Plugin<Project> {
409416
}
410417
}
411418

412-
/** Prints error message and fix for any plugin compileSdkVersion that are higher than the project. */
413-
private void detectLowCompileSdkVersion() {
419+
/**
420+
* Compares semantic versions ignoring labels.
421+
*
422+
* If the versions are equal (ignoring labels), returns one of the two strings arbitrarily.
423+
*
424+
* If minor or patch are omitted (non-conformant to semantic versioning), they are considered zero.
425+
* If the provided versions in both are equal, the longest version string is returned.
426+
* For example, "2.8.0" vs "2.8" will always consider "2.8.0" to be the most recent version.
427+
*/
428+
static String mostRecentSemanticVersion(String version1, String version2) {
429+
List version1Tokenized = version1.tokenize('.')
430+
List version2Tokenized = version2.tokenize('.')
431+
def version1numTokens = version1Tokenized.size()
432+
def version2numTokens = version2Tokenized.size()
433+
def minNumTokens = Math.min(version1numTokens, version2numTokens)
434+
for (int i = 0; i < minNumTokens; i++) {
435+
def num1 = version1Tokenized[i].toInteger()
436+
def num2 = version2Tokenized[i].toInteger()
437+
if (num1 > num2) {
438+
return version1
439+
}
440+
if (num2 > num1) {
441+
return version2
442+
}
443+
}
444+
if (version1numTokens > version2numTokens) {
445+
return version1
446+
}
447+
return version2
448+
}
449+
450+
/** Prints error message and fix for any plugin compileSdkVersion or ndkVersion that are higher than the project. */
451+
private void detectLowCompileSdkVersionOrNdkVersion() {
414452
project.afterEvaluate {
415453
int projectCompileSdkVersion = project.android.compileSdkVersion.substring(8) as int
416454
int maxPluginCompileSdkVersion = projectCompileSdkVersion
455+
String ndkVersionIfUnspecified = "21.1.6352462" /* The default for AGP 4.1.0 used in old templates. */
456+
String projectNdkVersion = project.android.ndkVersion ?: ndkVersionIfUnspecified
457+
String maxPluginNdkVersion = projectNdkVersion
417458
int numProcessedPlugins = getPluginList().size()
418459

419460
getPluginList().each { plugin ->
420461
Project pluginProject = project.rootProject.findProject(plugin.key)
421462
pluginProject.afterEvaluate {
422463
int pluginCompileSdkVersion = pluginProject.android.compileSdkVersion.substring(8) as int
423464
maxPluginCompileSdkVersion = Math.max(pluginCompileSdkVersion, maxPluginCompileSdkVersion)
465+
String pluginNdkVersion = pluginProject.android.ndkVersion ?: ndkVersionIfUnspecified
466+
maxPluginNdkVersion = mostRecentSemanticVersion(pluginNdkVersion, maxPluginNdkVersion)
424467

425468
numProcessedPlugins--
426469
if (numProcessedPlugins == 0) {
427470
if (maxPluginCompileSdkVersion > projectCompileSdkVersion) {
428471
project.logger.error("One or more plugins require a higher Android SDK version.\nFix this issue by adding the following to ${project.projectDir}${File.separator}build.gradle:\nandroid {\n compileSdkVersion ${maxPluginCompileSdkVersion}\n ...\n}\n")
429472
}
473+
if (maxPluginNdkVersion != projectNdkVersion) {
474+
project.logger.error("One or more plugins require a higher Android NDK version.\nFix this issue by adding the following to ${project.projectDir}${File.separator}build.gradle:\nandroid {\n ndkVersion ${maxPluginNdkVersion}\n ...\n}\n")
475+
}
430476
}
431477
}
432478
}
@@ -963,7 +1009,7 @@ class FlutterPlugin implements Plugin<Project> {
9631009
}
9641010
}
9651011
configurePlugins()
966-
detectLowCompileSdkVersion()
1012+
detectLowCompileSdkVersionOrNdkVersion()
9671013
return
9681014
}
9691015
// Flutter host module project (Add-to-app).
@@ -1015,7 +1061,7 @@ class FlutterPlugin implements Plugin<Project> {
10151061
}
10161062
}
10171063
configurePlugins()
1018-
detectLowCompileSdkVersion()
1064+
detectLowCompileSdkVersionOrNdkVersion()
10191065
}
10201066
}
10211067

0 commit comments

Comments
 (0)