diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 034392e..59e4c99 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -1,11 +1,11 @@
FROM mcr.microsoft.com/devcontainers/base:debian
# Install needed packages
-RUN apt-get update && apt-get install -y curl git unzip xz-utils zip
+RUN apt-get update && apt-get install -y curl git unzip xz-utils zip nano
USER 1000:1000
-ARG FLUTTER_VERSION=3.22.1
+ARG FLUTTER_VERSION=3.38.3
RUN git clone -b $FLUTTER_VERSION https://github.com/flutter/flutter.git /home/vscode/flutter
ENV PATH /home/vscode/flutter/bin:/home/vscode/.pub-cache/bin:$PATH
diff --git a/.github/workflows/build-app.yml b/.github/workflows/build-app.yml
index 9603939..ab6becb 100644
--- a/.github/workflows/build-app.yml
+++ b/.github/workflows/build-app.yml
@@ -2,19 +2,22 @@ name: Build Test App
on:
push:
- branches: [ "main" ]
+ branches: ["main"]
pull_request:
- branches: [ "main" ]
+ branches: ["main"]
-permissions:
- contents: read
+env:
+ FLUTTER_VERSION: 3.38.4
jobs:
build:
- name: Build Flutter-Pi Bundle (${{ matrix.arch }}, ${{ matrix.cpu}})
- runs-on: ubuntu-latest
+ name: Build Flutter-Pi Bundle (${{ matrix.runner}}, ${{ matrix.arch }}, ${{ matrix.cpu}})
+ runs-on: ${{ matrix.runner }}
strategy:
matrix:
+ runner:
+ - windows-latest
+ - ubuntu-latest
arch:
- arm
- arm64
@@ -22,24 +25,42 @@ jobs:
- riscv64
cpu:
- generic
+
+ # TODO: Maybe find a better way to do this.
include:
- - arch: arm
+ - runner: windows-latest
+ arch: arm
+ cpu: pi3
+ - runner: ubuntu-latest
+ arch: arm
cpu: pi3
- - arch: arm
+ - runner: windows-latest
+ arch: arm
cpu: pi4
- - arch: arm64
+ - runner: ubuntu-latest
+ arch: arm
+ cpu: pi4
+ - runner: windows-latest
+ arch: arm64
+ cpu: pi3
+ - runner: ubuntu-latest
+ arch: arm64
cpu: pi3
- - arch: arm64
+ - runner: windows-latest
+ arch: arm64
+ cpu: pi4
+ - runner: ubuntu-latest
+ arch: arm64
cpu: pi4
steps:
- uses: actions/checkout@v4
-
+
- uses: subosito/flutter-action@v2
with:
cache: true
channel: stable
- flutter-version: 3.38.4
-
+ flutter-version: ${{ env.FLUTTER_VERSION }}
+
- name: Install dependencies & Activate as global executable
run: |
flutter pub get
@@ -51,7 +72,7 @@ jobs:
- name: Run flutterpi_tool build
working-directory: test_app
env:
- GITHUB_TOKEN: ${{ secrets.TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.PUBLIC_ONLY_PAT }}
run: |
echo '::group::flutterpi_tool build ... --debug-unoptimized'
flutterpi_tool build --arch=${{ matrix.arch }} --cpu=${{ matrix.cpu }} --debug-unoptimized --debug-symbols --verbose
@@ -60,7 +81,7 @@ jobs:
echo '::group::flutterpi_tool build ... --debug'
flutterpi_tool build --arch=${{ matrix.arch }} --cpu=${{ matrix.cpu }} --debug --debug-symbols --verbose
echo '::endgroup::'
-
+
echo '::group::flutterpi_tool build ... --profile'
flutterpi_tool build --arch=${{ matrix.arch }} --cpu=${{ matrix.cpu }} --profile --debug-symbols --verbose
echo '::endgroup::'
diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml
index cabccc1..45432ed 100644
--- a/.github/workflows/flutter.yml
+++ b/.github/workflows/flutter.yml
@@ -7,39 +7,112 @@ name: Flutter
on:
push:
- branches: [ "main" ]
+ branches: ["main"]
pull_request:
- branches: [ "main" ]
+ branches: ["main"]
permissions:
contents: read
+env:
+ FLUTTER_VERSION: 3.38.4
+
jobs:
- build:
+ analyze:
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
steps:
- uses: actions/checkout@v4
-
+
- uses: subosito/flutter-action@v2
with:
cache: true
channel: stable
- flutter-version: 3.38.4
-
+ flutter-version: ${{ env.FLUTTER_VERSION }}
+
- name: Install dependencies
- run: flutter pub get
-
+ run: dart pub get
+
- name: Verify formatting
run: dart format --output=none --set-exit-if-changed .
- # Consider passing '--fatal-infos' for slightly stricter analysis.
- - name: Analyze project source
- run: flutter analyze
+ - name: Analyze
+ run: dart analyze
+
+ - name: Analyze e2e/hooks_test_package
+ working-directory: e2e/hooks_test_package
+ run: |
+ echo '::group::dart pub get'
+ dart pub get --enforce-lockfile
+ echo '::endgroup::'
+
+ echo '::group::dart format'
+ dart format --output=none --set-exit-if-changed .
+ echo '::endgroup::'
+
+ echo '::group::dart analyze'
+ dart analyze
+ echo '::endgroup::'
+
+ test:
+ runs-on: ${{ matrix.runner }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.token }}
+ strategy:
+ matrix:
+ runner:
+ - windows-latest
+ - ubuntu-latest
+ - macos-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: subosito/flutter-action@v2
+ with:
+ cache: true
+ channel: stable
+ flutter-version: ${{ env.FLUTTER_VERSION }}
+
+ - name: Install dependencies
+ run: flutter pub get
- # Your project will need to have tests in test/ and a dependency on
- # package:test for this step to succeed. Note that Flutter projects will
- # want to change this to 'flutter test'.
- name: Run tests
run: flutter test
+
+ e2e:
+ name: E2E Tests (${{ matrix.runner }})
+ runs-on: ${{ matrix.runner }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.PUBLIC_ONLY_PAT }}
+ strategy:
+ matrix:
+ runner:
+ - windows-latest
+ - ubuntu-latest
+ - ubuntu-24.04-arm
+ - macos-latest
+ include:
+ # we need to use the main channel,
+ # as flutter does apparently not officially release SDKs for arm64 linux.
+ # see: https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json
+ - runner: ubuntu-24.04-arm
+ channel: main
+ fail-fast: false
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: subosito/flutter-action@v2
+ with:
+ cache: true
+ channel: ${{ matrix.channel || 'stable' }}
+ flutter-version: ${{ env.FLUTTER_VERSION }}
+
+ - name: Install dependencies
+ run: flutter pub get
+
+ - name: Activate flutterpi_tool globally
+ run: flutter pub global activate -spath .
+
+ - name: Run e2e tests
+ run: dart test e2e
diff --git a/.gitignore b/.gitignore
index 84683cf..a513d72 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,8 +4,9 @@
.dart_tool/
.packages
build/
+
# If you're building an application, you may want to check-in your pubspec.lock
-pubspec.lock
+/pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
@@ -52,4 +53,4 @@ Icon
.AppleDesktop
Network Trash Folder
Temporary Items
-.apdisk
\ No newline at end of file
+.apdisk
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 0c09e66..7d871df 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -21,6 +21,9 @@ analyzer:
exclude:
- lib/src/archive
+ # separate package with additional dependencies not contained
+ # in the root pubspec
+ - e2e/hooks_test_package
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
diff --git a/e2e/hooks_test.dart b/e2e/hooks_test.dart
new file mode 100644
index 0000000..5393c36
--- /dev/null
+++ b/e2e/hooks_test.dart
@@ -0,0 +1,347 @@
+import 'dart:ffi';
+import 'dart:io';
+
+import 'package:path/path.dart' as pathlib;
+import 'package:test/test.dart';
+
+/// Custom matcher that checks if a ProcessResult succeeded
+/// and provides helpful error messages with stdout/stderr on failure.
+class _ProcessExitedSuccessfully extends Matcher {
+ _ProcessExitedSuccessfully({Object? exitCode, Object? stdout, Object? stderr})
+ : exitCode = wrapMatcher(exitCode ?? equals(0)),
+ stdout = wrapMatcher(stdout ?? anything),
+ stderr = wrapMatcher(stderr ?? anything);
+
+ final Matcher exitCode;
+ final Matcher stdout;
+ final Matcher stderr;
+
+ @override
+ bool matches(dynamic item, Map matchState) {
+ if (item is! ProcessResult) return false;
+
+ final exitCode = this.exitCode;
+ if (!exitCode.matches(item.exitCode, matchState)) {
+ matchState['exitCodeMatcher'] = exitCode;
+ matchState['field'] = 'exitCode';
+ return false;
+ }
+
+ if (!stdout.matches(item.stdout, matchState)) {
+ matchState['stdoutMatcher'] = stdout;
+ matchState['field'] = 'stdout';
+ return false;
+ }
+
+ if (!stderr.matches(item.stderr, matchState)) {
+ matchState['stderrMatcher'] = stderr;
+ matchState['field'] = 'stderr';
+ return false;
+ }
+
+ return true;
+ }
+
+ @override
+ Description describe(Description description) {
+ description.add('process to succeed');
+
+ description.add(' with exit code ');
+ exitCode.describe(description);
+
+ description.add(' and stdout ');
+ stdout.describe(description);
+
+ description.add(' and stderr ');
+ stderr.describe(description);
+
+ return description;
+ }
+
+ @override
+ Description describeMismatch(
+ dynamic item,
+ Description mismatchDescription,
+ Map matchState,
+ bool verbose,
+ ) {
+ if (item is! ProcessResult) {
+ return mismatchDescription.add('is not a ProcessResult');
+ }
+
+ final field = matchState['field'] as String?;
+
+ if (field == 'exitCode') {
+ final matcher = matchState['exitCodeMatcher'] as Matcher;
+ mismatchDescription.add('exit code ');
+ matcher.describeMismatch(
+ item.exitCode,
+ mismatchDescription,
+ matchState,
+ verbose,
+ );
+ } else if (field == 'stdout') {
+ final matcher = matchState['stdoutMatcher'] as Matcher;
+ mismatchDescription.add('stdout ');
+ matcher.describeMismatch(
+ item.stdout,
+ mismatchDescription,
+ matchState,
+ verbose,
+ );
+ } else if (field == 'stderr') {
+ final matcher = matchState['stderrMatcher'] as Matcher;
+ mismatchDescription.add('stderr ');
+ matcher.describeMismatch(
+ item.stderr,
+ mismatchDescription,
+ matchState,
+ verbose,
+ );
+ }
+
+ // Always include the full process output for context
+ return mismatchDescription
+ .add('\n\nProcess output:')
+ .add('\nexit code: ${item.exitCode}')
+ .add('\nstdout: ${item.stdout}')
+ .add('\nstderr: ${item.stderr}');
+ }
+}
+
+Matcher exitedSuccessfully({
+ Matcher? exitCode,
+ Matcher? stdout,
+ Matcher? stderr,
+}) =>
+ _ProcessExitedSuccessfully(
+ exitCode: exitCode,
+ stdout: stdout,
+ stderr: stderr,
+ );
+
+Matcher buildExitedSuccessfully() => _ProcessExitedSuccessfully(
+ stdout: isNot(contains('Failed to build bundle.')),
+ stderr: isNot(contains('Failed to build bundle.')),
+ );
+
+Iterable<(A, B)> cartesianProduct2(Iterable a, Iterable b) sync* {
+ for (final fst in a) {
+ for (final snd in b) {
+ yield (fst, snd);
+ }
+ }
+}
+
+Iterable<(A, B, C)> cartesianProduct3(
+ Iterable a,
+ Iterable b,
+ Iterable c,
+) sync* {
+ for (final fst in a) {
+ for (final snd in b) {
+ for (final thrd in c) {
+ yield (fst, snd, thrd);
+ }
+ }
+ }
+}
+
+enum Arch {
+ arm,
+ arm64,
+ ia32,
+ x64,
+ riscv32,
+ riscv64;
+
+ factory Arch.fromAbi(Abi abi) {
+ return switch (abi) {
+ Abi.androidArm => Arch.arm,
+ Abi.androidArm64 => Arch.arm64,
+ Abi.androidIA32 => Arch.ia32,
+ Abi.androidX64 => Arch.x64,
+ Abi.androidRiscv64 => Arch.riscv64,
+ Abi.fuchsiaArm64 => Arch.arm64,
+ Abi.fuchsiaX64 => Arch.x64,
+ Abi.fuchsiaRiscv64 => Arch.riscv64,
+ Abi.iosArm => Arch.arm,
+ Abi.iosArm64 => Arch.arm64,
+ Abi.iosX64 => Arch.x64,
+ Abi.linuxArm => Arch.arm,
+ Abi.linuxArm64 => Arch.arm64,
+ Abi.linuxIA32 => Arch.ia32,
+ Abi.linuxX64 => Arch.x64,
+ Abi.linuxRiscv32 => Arch.riscv32,
+ Abi.linuxRiscv64 => Arch.riscv64,
+ Abi.macosArm64 => Arch.arm64,
+ Abi.macosX64 => Arch.x64,
+ Abi.windowsArm64 => Arch.arm64,
+ Abi.windowsIA32 => Arch.ia32,
+ Abi.windowsX64 => Arch.x64,
+ _ => throw ArgumentError.value(abi, 'abi', 'unsupported abi')
+ };
+ }
+
+ factory Arch.current() {
+ return Arch.fromAbi(Abi.current());
+ }
+
+ @override
+ String toString() => name;
+}
+
+void main() {
+ setUpAll(() async {
+ expect(
+ await Process.run('flutter', ['--version']),
+ exitedSuccessfully(),
+ reason: 'flutter must be available in PATH.',
+ );
+
+ expect(
+ await Process.run('flutterpi_tool', ['--version']),
+ exitedSuccessfully(),
+ reason:
+ 'flutterpi_tool must be globally activated and available in PATH.',
+ );
+
+ expect(
+ await Process.run('file', ['--version']),
+ exitedSuccessfully(),
+ reason: '"file" utility must be available in PATH.',
+ );
+
+ final result = await Process.run('dart', ['pub', 'global', 'list']);
+ expect(
+ result,
+ exitedSuccessfully(),
+ reason: 'dart must be available in PATH.',
+ );
+
+ final regex = RegExp(r'flutterpi_tool [^ ]+ at path "([^"]+)"');
+ expect(result.stdout, matches(regex));
+
+ final match = regex.firstMatch(result.stdout);
+ expect(
+ Directory(match!.group(1)!).resolveSymbolicLinksSync(),
+ pathlib.canonicalize(Directory.current.path),
+ reason:
+ 'flutterpi_tool should be globally activated from the same path that is currently being tested.',
+ );
+ });
+
+ // Only tested on linux right now, see testOn below.
+ // On windows and macOS it's hard to get a working linux
+ // cross compiler. Best thing we can do maybe is just
+ // verify we provide an understandable error message.
+ group(
+ 'hooks_test native assets e2e',
+ () {
+ const exampleDir = 'e2e/hooks_test_package/example';
+
+ setUp(() async {
+ // Ensure dependencies are installed
+ final pubGetResult = await Process.run(
+ 'flutter',
+ [
+ 'pub',
+ 'get',
+ '--enforce-lockfile',
+ ],
+ workingDirectory: exampleDir,
+ );
+ expect(pubGetResult, exitedSuccessfully());
+ });
+
+ tearDown(() async {
+ final clean = await Process.run(
+ 'flutter',
+ ['clean'],
+ workingDirectory: exampleDir,
+ );
+ expect(clean, exitedSuccessfully());
+ });
+
+ for (final (flavor, arch, layout) in cartesianProduct3(
+ ['debug', 'profile', 'release'],
+ [Arch.arm, Arch.arm64, Arch.x64, Arch.riscv64],
+ ['flutter-pi', 'meta-flutter'],
+ )) {
+ test(
+ 'builds successfully in $flavor, for $arch, $layout layout',
+ () async {
+ if (arch == Arch.arm) {
+ return markTestSkipped(
+ 'armv7 does not currently support native assets',
+ );
+ } else if (arch != Arch.current()) {
+ return markTestSkipped(
+ 'cross-compiling native assets is not currently supported',
+ );
+ }
+
+ final result = await Process.run(
+ 'flutterpi_tool',
+ [
+ 'build',
+ '--$flavor',
+ '--arch=$arch',
+ '--fs-layout=$layout',
+ ],
+ workingDirectory: exampleDir,
+ );
+
+ final layoutPart = switch (layout) {
+ 'flutter-pi' => '',
+ 'meta-flutter' => 'meta-flutter-',
+ _ => fail('unexpected layout: $layout')
+ };
+ final archPart = switch (arch) {
+ Arch.arm => 'armv7-generic',
+ Arch.arm64 => 'aarch64-generic',
+ Arch.ia32 => 'i386-generic',
+ Arch.x64 => 'x86_64-generic',
+ Arch.riscv32 => 'riscv32-generic',
+ Arch.riscv64 => 'riscv64-generic',
+ };
+ final outputDir = pathlib.join(
+ exampleDir,
+ 'build',
+ 'flutter-pi',
+ '$layoutPart$archPart',
+ );
+ final testAsset = switch (layout) {
+ 'flutter-pi' =>
+ pathlib.join(outputDir, 'libhooks_test_package.so'),
+ 'meta-flutter' =>
+ pathlib.join(outputDir, 'lib', 'libhooks_test_package.so'),
+ _ => fail('unexpected layout: $layout'),
+ };
+
+ expect(result, buildExitedSuccessfully());
+ expect(
+ File(testAsset).existsSync(),
+ isTrue,
+ reason:
+ 'libhooks_test_package.so code asset should be present in bundle',
+ );
+
+ final fileResult = await Process.run('file', [testAsset]);
+ expect(fileResult, exitedSuccessfully());
+
+ final fileArchMatcher = switch (arch) {
+ Arch.arm64 => contains('ARM aarch64'),
+ _ => isNot(anything),
+ };
+ expect(fileResult.stdout, fileArchMatcher);
+ },
+ timeout: const Timeout(Duration(minutes: 5)),
+ );
+ }
+ },
+ testOn: 'linux',
+ );
+
+ test('empty test to make all-skipped runs succeed', () {});
+}
diff --git a/e2e/hooks_test_package/.gitignore b/e2e/hooks_test_package/.gitignore
new file mode 100644
index 0000000..cd5fa12
--- /dev/null
+++ b/e2e/hooks_test_package/.gitignore
@@ -0,0 +1,29 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+.dart_tool/
+.flutter-plugins-dependencies
+/build/
+/coverage/
diff --git a/e2e/hooks_test_package/.metadata b/e2e/hooks_test_package/.metadata
new file mode 100644
index 0000000..c422502
--- /dev/null
+++ b/e2e/hooks_test_package/.metadata
@@ -0,0 +1,27 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "3b62efc2a3da49882f43c372e0bc53daef7295a6"
+ channel: "stable"
+
+project_type: package_ffi
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
+ base_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/e2e/hooks_test_package/example/.gitignore b/e2e/hooks_test_package/example/.gitignore
new file mode 100644
index 0000000..3820a95
--- /dev/null
+++ b/e2e/hooks_test_package/example/.gitignore
@@ -0,0 +1,45 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.build/
+.buildlog/
+.history
+.svn/
+.swiftpm/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+/coverage/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/e2e/hooks_test_package/example/README.md b/e2e/hooks_test_package/example/README.md
new file mode 100644
index 0000000..a7bde44
--- /dev/null
+++ b/e2e/hooks_test_package/example/README.md
@@ -0,0 +1,16 @@
+# hooks_test_example
+
+Demonstrates how to use the hooks_test package.
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
+- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev/), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
diff --git a/e2e/hooks_test_package/example/lib/main.dart b/e2e/hooks_test_package/example/lib/main.dart
new file mode 100644
index 0000000..db923ca
--- /dev/null
+++ b/e2e/hooks_test_package/example/lib/main.dart
@@ -0,0 +1,13 @@
+import 'package:integration_test/integration_test.dart';
+import 'package:hooks_test_package/hooks_test_package.dart' as hooks_test;
+import 'package:test/test.dart';
+
+void main() {
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+ test('native hooks sum works', () async {
+ expect(hooks_test.sum(2, 1), equals(3));
+
+ await expectLater(hooks_test.sumAsync(2, 1), equals(3));
+ });
+}
diff --git a/e2e/hooks_test_package/example/pubspec.lock b/e2e/hooks_test_package/example/pubspec.lock
new file mode 100644
index 0000000..b6c0de3
--- /dev/null
+++ b/e2e/hooks_test_package/example/pubspec.lock
@@ -0,0 +1,571 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+ _fe_analyzer_shared:
+ dependency: transitive
+ description:
+ name: _fe_analyzer_shared
+ sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d
+ url: "https://pub.dev"
+ source: hosted
+ version: "91.0.0"
+ analyzer:
+ dependency: transitive
+ description:
+ name: analyzer
+ sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08
+ url: "https://pub.dev"
+ source: hosted
+ version: "8.4.1"
+ args:
+ dependency: transitive
+ description:
+ name: args
+ sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.7.0"
+ async:
+ dependency: transitive
+ description:
+ name: async
+ sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.13.0"
+ boolean_selector:
+ dependency: transitive
+ description:
+ name: boolean_selector
+ sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.2"
+ characters:
+ dependency: transitive
+ description:
+ name: characters
+ sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.0"
+ cli_config:
+ dependency: transitive
+ description:
+ name: cli_config
+ sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.0"
+ clock:
+ dependency: transitive
+ description:
+ name: clock
+ sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.2"
+ code_assets:
+ dependency: transitive
+ description:
+ name: code_assets
+ sha256: ae0db647e668cbb295a3527f0938e4039e004c80099dce2f964102373f5ce0b5
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.19.10"
+ collection:
+ dependency: transitive
+ description:
+ name: collection
+ sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.19.1"
+ convert:
+ dependency: transitive
+ description:
+ name: convert
+ sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.2"
+ coverage:
+ dependency: transitive
+ description:
+ name: coverage
+ sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.15.0"
+ crypto:
+ dependency: transitive
+ description:
+ name: crypto
+ sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.7"
+ cupertino_icons:
+ dependency: "direct main"
+ description:
+ name: cupertino_icons
+ sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.8"
+ fake_async:
+ dependency: transitive
+ description:
+ name: fake_async
+ sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.3"
+ file:
+ dependency: transitive
+ description:
+ name: file
+ sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
+ url: "https://pub.dev"
+ source: hosted
+ version: "7.0.1"
+ flutter:
+ dependency: "direct main"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_driver:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_lints:
+ dependency: "direct dev"
+ description:
+ name: flutter_lints
+ sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.0.0"
+ flutter_test:
+ dependency: "direct dev"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ frontend_server_client:
+ dependency: transitive
+ description:
+ name: frontend_server_client
+ sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.0"
+ fuchsia_remote_debug_protocol:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ glob:
+ dependency: transitive
+ description:
+ name: glob
+ sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.3"
+ hooks:
+ dependency: transitive
+ description:
+ name: hooks
+ sha256: "5410b9f4f6c9f01e8ff0eb81c9801ea13a3c3d39f8f0b1613cda08e27eab3c18"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.20.5"
+ hooks_test_package:
+ dependency: "direct main"
+ description:
+ path: ".."
+ relative: true
+ source: path
+ version: "0.0.1"
+ http_multi_server:
+ dependency: transitive
+ description:
+ name: http_multi_server
+ sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.2"
+ http_parser:
+ dependency: transitive
+ description:
+ name: http_parser
+ sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.1.2"
+ integration_test:
+ dependency: "direct main"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ io:
+ dependency: transitive
+ description:
+ name: io
+ sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.5"
+ js:
+ dependency: transitive
+ description:
+ name: js
+ sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.7.2"
+ leak_tracker:
+ dependency: transitive
+ description:
+ name: leak_tracker
+ sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
+ url: "https://pub.dev"
+ source: hosted
+ version: "11.0.2"
+ leak_tracker_flutter_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_flutter_testing
+ sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.10"
+ leak_tracker_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_testing
+ sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.2"
+ lints:
+ dependency: transitive
+ description:
+ name: lints
+ sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.1.0"
+ logging:
+ dependency: transitive
+ description:
+ name: logging
+ sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.0"
+ matcher:
+ dependency: transitive
+ description:
+ name: matcher
+ sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.12.17"
+ material_color_utilities:
+ dependency: transitive
+ description:
+ name: material_color_utilities
+ sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.11.1"
+ meta:
+ dependency: transitive
+ description:
+ name: meta
+ sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.17.0"
+ mime:
+ dependency: transitive
+ description:
+ name: mime
+ sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.0"
+ native_toolchain_c:
+ dependency: transitive
+ description:
+ name: native_toolchain_c
+ sha256: f8872ea6c7a50ce08db9ae280ca2b8efdd973157ce462826c82f3c3051d154ce
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.17.2"
+ node_preamble:
+ dependency: transitive
+ description:
+ name: node_preamble
+ sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.2"
+ package_config:
+ dependency: transitive
+ description:
+ name: package_config
+ sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.0"
+ path:
+ dependency: transitive
+ description:
+ name: path
+ sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.9.1"
+ platform:
+ dependency: transitive
+ description:
+ name: platform
+ sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.6"
+ pool:
+ dependency: transitive
+ description:
+ name: pool
+ sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.5.2"
+ process:
+ dependency: transitive
+ description:
+ name: process
+ sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.0.5"
+ pub_semver:
+ dependency: transitive
+ description:
+ name: pub_semver
+ sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.0"
+ shelf:
+ dependency: transitive
+ description:
+ name: shelf
+ sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.2"
+ shelf_packages_handler:
+ dependency: transitive
+ description:
+ name: shelf_packages_handler
+ sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.2"
+ shelf_static:
+ dependency: transitive
+ description:
+ name: shelf_static
+ sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.3"
+ shelf_web_socket:
+ dependency: transitive
+ description:
+ name: shelf_web_socket
+ sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.0"
+ sky_engine:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ source_map_stack_trace:
+ dependency: transitive
+ description:
+ name: source_map_stack_trace
+ sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.2"
+ source_maps:
+ dependency: transitive
+ description:
+ name: source_maps
+ sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.10.13"
+ source_span:
+ dependency: transitive
+ description:
+ name: source_span
+ sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.10.2"
+ stack_trace:
+ dependency: transitive
+ description:
+ name: stack_trace
+ sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.12.1"
+ stream_channel:
+ dependency: transitive
+ description:
+ name: stream_channel
+ sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ string_scanner:
+ dependency: transitive
+ description:
+ name: string_scanner
+ sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.1"
+ sync_http:
+ dependency: transitive
+ description:
+ name: sync_http
+ sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.1"
+ term_glyph:
+ dependency: transitive
+ description:
+ name: term_glyph
+ sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.2"
+ test:
+ dependency: "direct main"
+ description:
+ name: test
+ sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.26.3"
+ test_api:
+ dependency: transitive
+ description:
+ name: test_api
+ sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.7.7"
+ test_core:
+ dependency: transitive
+ description:
+ name: test_core
+ sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.6.12"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.0"
+ vector_math:
+ dependency: transitive
+ description:
+ name: vector_math
+ sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.0"
+ vm_service:
+ dependency: transitive
+ description:
+ name: vm_service
+ sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
+ url: "https://pub.dev"
+ source: hosted
+ version: "15.0.2"
+ watcher:
+ dependency: transitive
+ description:
+ name: watcher
+ sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ web:
+ dependency: transitive
+ description:
+ name: web
+ sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+ web_socket:
+ dependency: transitive
+ description:
+ name: web_socket
+ sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
+ web_socket_channel:
+ dependency: transitive
+ description:
+ name: web_socket_channel
+ sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.3"
+ webdriver:
+ dependency: transitive
+ description:
+ name: webdriver
+ sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.0"
+ webkit_inspection_protocol:
+ dependency: transitive
+ description:
+ name: webkit_inspection_protocol
+ sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ yaml:
+ dependency: transitive
+ description:
+ name: yaml
+ sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.3"
+sdks:
+ dart: ">=3.10.3 <4.0.0"
+ flutter: ">=3.18.0-18.0.pre.54"
diff --git a/e2e/hooks_test_package/example/pubspec.yaml b/e2e/hooks_test_package/example/pubspec.yaml
new file mode 100644
index 0000000..7f51b01
--- /dev/null
+++ b/e2e/hooks_test_package/example/pubspec.yaml
@@ -0,0 +1,99 @@
+name: hooks_test_example
+description: "Demonstrates how to use the hooks_test package."
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: "none" # Remove this line if you wish to publish to pub.dev
+
+# The following defines the version and build number for your application.
+# A version number is three numbers separated by dots, like 1.2.43
+# followed by an optional build number separated by a +.
+# Both the version and the builder number may be overridden in flutter
+# build by specifying --build-name and --build-number, respectively.
+# In Android, build-name is used as versionName while build-number used as versionCode.
+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
+# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+# In Windows, build-name is used as the major, minor, and patch parts
+# of the product and file versions while build-number is used as the build suffix.
+version: 1.0.0+1
+
+environment:
+ sdk: ^3.10.3
+
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+ flutter:
+ sdk: flutter
+ integration_test:
+ sdk: flutter
+
+ hooks_test_package:
+ # When depending on this package from a real application you should use:
+ # hooks_test: ^x.y.z
+ # See https://dart.dev/tools/pub/dependencies#version-constraints
+ # The example app is bundled with the plugin so we use a path dependency on
+ # the parent directory to use the current plugin's version.
+ path: ../
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^1.0.8
+ test: ^1.26.3
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^6.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # To add assets to your application, add an assets section, like this:
+ # assets:
+ # - images/a_dot_burr.jpeg
+ # - images/a_dot_ham.jpeg
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/to/resolution-aware-images
+
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.dev/to/asset-from-package
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/to/font-from-package
diff --git a/e2e/hooks_test_package/ffigen.yaml b/e2e/hooks_test_package/ffigen.yaml
new file mode 100644
index 0000000..31f33bb
--- /dev/null
+++ b/e2e/hooks_test_package/ffigen.yaml
@@ -0,0 +1,20 @@
+# Run with `dart run ffigen --config ffigen.yaml`.
+name: HooksTestBindings
+description: |
+ Bindings for `src/hooks_test.h`.
+
+ Regenerate bindings with `dart run ffigen --config ffigen.yaml`.
+output: 'lib/hooks_test_bindings_generated.dart'
+headers:
+ entry-points:
+ - 'src/hooks_test.h'
+ include-directives:
+ - 'src/hooks_test.h'
+ffi-native:
+preamble: |
+ // ignore_for_file: always_specify_types
+ // ignore_for_file: camel_case_types
+ // ignore_for_file: non_constant_identifier_names
+comments:
+ style: any
+ length: full
diff --git a/e2e/hooks_test_package/hook/build.dart b/e2e/hooks_test_package/hook/build.dart
new file mode 100644
index 0000000..3c82887
--- /dev/null
+++ b/e2e/hooks_test_package/hook/build.dart
@@ -0,0 +1,21 @@
+import 'package:native_toolchain_c/native_toolchain_c.dart';
+import 'package:logging/logging.dart';
+import 'package:hooks/hooks.dart';
+
+void main(List args) async {
+ await build(args, (input, output) async {
+ final packageName = input.packageName;
+ final cbuilder = CBuilder.library(
+ name: packageName,
+ assetName: 'hooks_test_bindings_generated.dart',
+ sources: ['src/hooks_test.c'],
+ );
+ await cbuilder.run(
+ input: input,
+ output: output,
+ logger: Logger('')
+ ..level = Level.ALL
+ ..onRecord.listen((record) => print(record.message)),
+ );
+ });
+}
diff --git a/e2e/hooks_test_package/lib/hooks_test_bindings_generated.dart b/e2e/hooks_test_package/lib/hooks_test_bindings_generated.dart
new file mode 100644
index 0000000..d61c422
--- /dev/null
+++ b/e2e/hooks_test_package/lib/hooks_test_bindings_generated.dart
@@ -0,0 +1,24 @@
+// ignore_for_file: always_specify_types
+// ignore_for_file: camel_case_types
+// ignore_for_file: non_constant_identifier_names
+
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+/// A very short-lived native function.
+///
+/// For very short-lived functions, it is fine to call them on the main isolate.
+/// They will block the Dart execution while running the native function, so
+/// only do this for native functions which are guaranteed to be short-lived.
+@ffi.Native()
+external int sum(int a, int b);
+
+/// A longer lived native function, which occupies the thread calling it.
+///
+/// Do not call these kind of native functions in the main isolate. They will
+/// block Dart execution. This will cause dropped frames in Flutter applications.
+/// Instead, call these native functions on a separate isolate.
+@ffi.Native()
+external int sum_long_running(int a, int b);
diff --git a/e2e/hooks_test_package/lib/hooks_test_package.dart b/e2e/hooks_test_package/lib/hooks_test_package.dart
new file mode 100644
index 0000000..326d32c
--- /dev/null
+++ b/e2e/hooks_test_package/lib/hooks_test_package.dart
@@ -0,0 +1,108 @@
+import 'dart:async';
+import 'dart:isolate';
+
+import 'hooks_test_bindings_generated.dart' as bindings;
+
+/// A very short-lived native function.
+///
+/// For very short-lived functions, it is fine to call them on the main isolate.
+/// They will block the Dart execution while running the native function, so
+/// only do this for native functions which are guaranteed to be short-lived.
+int sum(int a, int b) => bindings.sum(a, b);
+
+/// A longer lived native function, which occupies the thread calling it.
+///
+/// Do not call these kind of native functions in the main isolate. They will
+/// block Dart execution. This will cause dropped frames in Flutter applications.
+/// Instead, call these native functions on a separate isolate.
+///
+/// Modify this to suit your own use case. Example use cases:
+///
+/// 1. Reuse a single isolate for various different kinds of requests.
+/// 2. Use multiple helper isolates for parallel execution.
+Future sumAsync(int a, int b) async {
+ final SendPort helperIsolateSendPort = await _helperIsolateSendPort;
+ final int requestId = _nextSumRequestId++;
+ final _SumRequest request = _SumRequest(requestId, a, b);
+ final Completer completer = Completer();
+ _sumRequests[requestId] = completer;
+ helperIsolateSendPort.send(request);
+ return completer.future;
+}
+
+/// A request to compute `sum`.
+///
+/// Typically sent from one isolate to another.
+class _SumRequest {
+ final int id;
+ final int a;
+ final int b;
+
+ const _SumRequest(this.id, this.a, this.b);
+}
+
+/// A response with the result of `sum`.
+///
+/// Typically sent from one isolate to another.
+class _SumResponse {
+ final int id;
+ final int result;
+
+ const _SumResponse(this.id, this.result);
+}
+
+/// Counter to identify [_SumRequest]s and [_SumResponse]s.
+int _nextSumRequestId = 0;
+
+/// Mapping from [_SumRequest] `id`s to the completers corresponding to the correct future of the pending request.
+final Map> _sumRequests = >{};
+
+/// The SendPort belonging to the helper isolate.
+Future _helperIsolateSendPort = () async {
+ // The helper isolate is going to send us back a SendPort, which we want to
+ // wait for.
+ final Completer completer = Completer();
+
+ // Receive port on the main isolate to receive messages from the helper.
+ // We receive two types of messages:
+ // 1. A port to send messages on.
+ // 2. Responses to requests we sent.
+ final ReceivePort receivePort = ReceivePort()
+ ..listen((dynamic data) {
+ if (data is SendPort) {
+ // The helper isolate sent us the port on which we can sent it requests.
+ completer.complete(data);
+ return;
+ }
+ if (data is _SumResponse) {
+ // The helper isolate sent us a response to a request we sent.
+ final Completer completer = _sumRequests[data.id]!;
+ _sumRequests.remove(data.id);
+ completer.complete(data.result);
+ return;
+ }
+ throw UnsupportedError('Unsupported message type: ${data.runtimeType}');
+ });
+
+ // Start the helper isolate.
+ await Isolate.spawn((SendPort sendPort) async {
+ final ReceivePort helperReceivePort = ReceivePort()
+ ..listen((dynamic data) {
+ // On the helper isolate listen to requests and respond to them.
+ if (data is _SumRequest) {
+ final int result = bindings.sum_long_running(data.a, data.b);
+ final _SumResponse response = _SumResponse(data.id, result);
+ sendPort.send(response);
+ return;
+ }
+ throw UnsupportedError('Unsupported message type: ${data.runtimeType}');
+ });
+
+ // Send the port to the main isolate on which we can receive requests.
+ sendPort.send(helperReceivePort.sendPort);
+ }, receivePort.sendPort);
+
+ // Wait until the helper isolate has sent us back the SendPort on which we
+ // can start sending requests.
+ return completer.future;
+}();
diff --git a/e2e/hooks_test_package/pubspec.lock b/e2e/hooks_test_package/pubspec.lock
new file mode 100644
index 0000000..87753b6
--- /dev/null
+++ b/e2e/hooks_test_package/pubspec.lock
@@ -0,0 +1,461 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+ _fe_analyzer_shared:
+ dependency: transitive
+ description:
+ name: _fe_analyzer_shared
+ sha256: "796d97d925add7ffcdf5595f33a2066a6e3cee97971e6dbef09b76b7880fd760"
+ url: "https://pub.dev"
+ source: hosted
+ version: "94.0.0"
+ analyzer:
+ dependency: transitive
+ description:
+ name: analyzer
+ sha256: "9c8ebb304d72c0a0c8764344627529d9503fc83d7d73e43ed727dc532f822e4b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "10.0.2"
+ args:
+ dependency: transitive
+ description:
+ name: args
+ sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.7.0"
+ async:
+ dependency: transitive
+ description:
+ name: async
+ sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.13.0"
+ boolean_selector:
+ dependency: transitive
+ description:
+ name: boolean_selector
+ sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.2"
+ cli_config:
+ dependency: transitive
+ description:
+ name: cli_config
+ sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.0"
+ cli_util:
+ dependency: transitive
+ description:
+ name: cli_util
+ sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.4.2"
+ code_assets:
+ dependency: "direct main"
+ description:
+ name: code_assets
+ sha256: ae0db647e668cbb295a3527f0938e4039e004c80099dce2f964102373f5ce0b5
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.19.10"
+ collection:
+ dependency: transitive
+ description:
+ name: collection
+ sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.19.1"
+ convert:
+ dependency: transitive
+ description:
+ name: convert
+ sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.2"
+ coverage:
+ dependency: transitive
+ description:
+ name: coverage
+ sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.15.0"
+ crypto:
+ dependency: transitive
+ description:
+ name: crypto
+ sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.7"
+ ffi:
+ dependency: "direct dev"
+ description:
+ name: ffi
+ sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.5"
+ ffigen:
+ dependency: "direct dev"
+ description:
+ name: ffigen
+ sha256: "10cb41647d73e0204f8d35138a3f20eb52418cce96599ad49167b1111e59a557"
+ url: "https://pub.dev"
+ source: hosted
+ version: "13.0.0"
+ file:
+ dependency: transitive
+ description:
+ name: file
+ sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
+ url: "https://pub.dev"
+ source: hosted
+ version: "7.0.1"
+ flutter_lints:
+ dependency: "direct dev"
+ description:
+ name: flutter_lints
+ sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.0.0"
+ frontend_server_client:
+ dependency: transitive
+ description:
+ name: frontend_server_client
+ sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.0"
+ glob:
+ dependency: transitive
+ description:
+ name: glob
+ sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.3"
+ hooks:
+ dependency: "direct main"
+ description:
+ name: hooks
+ sha256: "5410b9f4f6c9f01e8ff0eb81c9801ea13a3c3d39f8f0b1613cda08e27eab3c18"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.20.5"
+ http_multi_server:
+ dependency: transitive
+ description:
+ name: http_multi_server
+ sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.2"
+ http_parser:
+ dependency: transitive
+ description:
+ name: http_parser
+ sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.1.2"
+ io:
+ dependency: transitive
+ description:
+ name: io
+ sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.5"
+ lints:
+ dependency: transitive
+ description:
+ name: lints
+ sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.1.0"
+ logging:
+ dependency: "direct main"
+ description:
+ name: logging
+ sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.0"
+ matcher:
+ dependency: transitive
+ description:
+ name: matcher
+ sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.12.18"
+ meta:
+ dependency: transitive
+ description:
+ name: meta
+ sha256: "9f29b9bcc8ee287b1a31e0d01be0eae99a930dbffdaecf04b3f3d82a969f296f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.18.1"
+ mime:
+ dependency: transitive
+ description:
+ name: mime
+ sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.0"
+ native_toolchain_c:
+ dependency: "direct main"
+ description:
+ name: native_toolchain_c
+ sha256: f8872ea6c7a50ce08db9ae280ca2b8efdd973157ce462826c82f3c3051d154ce
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.17.2"
+ node_preamble:
+ dependency: transitive
+ description:
+ name: node_preamble
+ sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.2"
+ package_config:
+ dependency: transitive
+ description:
+ name: package_config
+ sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.0"
+ path:
+ dependency: transitive
+ description:
+ name: path
+ sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.9.1"
+ pool:
+ dependency: transitive
+ description:
+ name: pool
+ sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.5.2"
+ pub_semver:
+ dependency: transitive
+ description:
+ name: pub_semver
+ sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.0"
+ quiver:
+ dependency: transitive
+ description:
+ name: quiver
+ sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.2"
+ shelf:
+ dependency: transitive
+ description:
+ name: shelf
+ sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.2"
+ shelf_packages_handler:
+ dependency: transitive
+ description:
+ name: shelf_packages_handler
+ sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.2"
+ shelf_static:
+ dependency: transitive
+ description:
+ name: shelf_static
+ sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.3"
+ shelf_web_socket:
+ dependency: transitive
+ description:
+ name: shelf_web_socket
+ sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.0"
+ source_map_stack_trace:
+ dependency: transitive
+ description:
+ name: source_map_stack_trace
+ sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.2"
+ source_maps:
+ dependency: transitive
+ description:
+ name: source_maps
+ sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.10.13"
+ source_span:
+ dependency: transitive
+ description:
+ name: source_span
+ sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.10.2"
+ stack_trace:
+ dependency: transitive
+ description:
+ name: stack_trace
+ sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.12.1"
+ stream_channel:
+ dependency: transitive
+ description:
+ name: stream_channel
+ sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ string_scanner:
+ dependency: transitive
+ description:
+ name: string_scanner
+ sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.1"
+ term_glyph:
+ dependency: transitive
+ description:
+ name: term_glyph
+ sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.2"
+ test:
+ dependency: "direct dev"
+ description:
+ name: test
+ sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.29.0"
+ test_api:
+ dependency: transitive
+ description:
+ name: test_api
+ sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.7.9"
+ test_core:
+ dependency: transitive
+ description:
+ name: test_core
+ sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.6.15"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.0"
+ vm_service:
+ dependency: transitive
+ description:
+ name: vm_service
+ sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
+ url: "https://pub.dev"
+ source: hosted
+ version: "15.0.2"
+ watcher:
+ dependency: transitive
+ description:
+ name: watcher
+ sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ web:
+ dependency: transitive
+ description:
+ name: web
+ sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+ web_socket:
+ dependency: transitive
+ description:
+ name: web_socket
+ sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
+ web_socket_channel:
+ dependency: transitive
+ description:
+ name: web_socket_channel
+ sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.3"
+ webkit_inspection_protocol:
+ dependency: transitive
+ description:
+ name: webkit_inspection_protocol
+ sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ yaml:
+ dependency: transitive
+ description:
+ name: yaml
+ sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.3"
+ yaml_edit:
+ dependency: transitive
+ description:
+ name: yaml_edit
+ sha256: ec709065bb2c911b336853b67f3732dd13e0336bd065cc2f1061d7610ddf45e3
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.3"
+sdks:
+ dart: ">=3.10.3 <4.0.0"
diff --git a/e2e/hooks_test_package/pubspec.yaml b/e2e/hooks_test_package/pubspec.yaml
new file mode 100644
index 0000000..6de7b3f
--- /dev/null
+++ b/e2e/hooks_test_package/pubspec.yaml
@@ -0,0 +1,18 @@
+name: hooks_test_package
+description: "A new Dart FFI package project."
+version: 0.0.1
+
+environment:
+ sdk: ^3.10.3
+
+dependencies:
+ code_assets: ^0.19.7
+ hooks: ^0.20.1
+ logging: ^1.3.0
+ native_toolchain_c: ^0.17.1
+
+dev_dependencies:
+ ffi: ^2.1.3
+ ffigen: ^13.0.0
+ flutter_lints: ^6.0.0
+ test: ^1.25.8
diff --git a/e2e/hooks_test_package/src/hooks_test.c b/e2e/hooks_test_package/src/hooks_test.c
new file mode 100644
index 0000000..41b4c2f
--- /dev/null
+++ b/e2e/hooks_test_package/src/hooks_test.c
@@ -0,0 +1,29 @@
+#include "hooks_test.h"
+
+// A very short-lived native function.
+//
+// For very short-lived functions, it is fine to call them on the main isolate.
+// They will block the Dart execution while running the native function, so
+// only do this for native functions which are guaranteed to be short-lived.
+FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b) {
+#ifdef DEBUG
+ return a + b + 1000;
+#else
+ return a + b;
+#endif
+}
+
+// A longer-lived native function, which occupies the thread calling it.
+//
+// Do not call these kind of native functions in the main isolate. They will
+// block Dart execution. This will cause dropped frames in Flutter applications.
+// Instead, call these native functions on a separate isolate.
+FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b) {
+ // Simulate work.
+#if _WIN32
+ Sleep(5000);
+#else
+ usleep(5000 * 1000);
+#endif
+ return a + b;
+}
diff --git a/e2e/hooks_test_package/src/hooks_test.h b/e2e/hooks_test_package/src/hooks_test.h
new file mode 100644
index 0000000..084c642
--- /dev/null
+++ b/e2e/hooks_test_package/src/hooks_test.h
@@ -0,0 +1,30 @@
+#include
+#include
+#include
+
+#if _WIN32
+#include
+#else
+#include
+#include
+#endif
+
+#if _WIN32
+#define FFI_PLUGIN_EXPORT __declspec(dllexport)
+#else
+#define FFI_PLUGIN_EXPORT
+#endif
+
+// A very short-lived native function.
+//
+// For very short-lived functions, it is fine to call them on the main isolate.
+// They will block the Dart execution while running the native function, so
+// only do this for native functions which are guaranteed to be short-lived.
+FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b);
+
+// A longer lived native function, which occupies the thread calling it.
+//
+// Do not call these kind of native functions in the main isolate. They will
+// block Dart execution. This will cause dropped frames in Flutter applications.
+// Instead, call these native functions on a separate isolate.
+FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b);
diff --git a/lib/src/build_system/targets.dart b/lib/src/build_system/targets.dart
index e3544a0..c1a43e9 100644
--- a/lib/src/build_system/targets.dart
+++ b/lib/src/build_system/targets.dart
@@ -7,6 +7,9 @@ import 'package:flutterpi_tool/src/build_system/extended_environment.dart';
import 'package:flutterpi_tool/src/cli/flutterpi_command.dart';
import 'package:flutterpi_tool/src/common.dart';
import 'package:flutterpi_tool/src/fltool/common.dart';
+import 'package:flutterpi_tool/src/fltool/common.dart' as fl;
+import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'
+ as fl;
import 'package:flutterpi_tool/src/fltool/globals.dart';
import 'package:flutterpi_tool/src/more_os_utils.dart';
@@ -20,6 +23,7 @@ class ReleaseBundleFlutterpiAssets extends CompositeTarget {
CopyFlutterAssets(
layout: layout,
buildMode: BuildMode.release,
+ target: target,
),
CopyIcudtl(layout: layout),
const DartBuildForNative(),
@@ -60,6 +64,7 @@ class ProfileBundleFlutterpiAssets extends CompositeTarget {
CopyFlutterAssets(
layout: layout,
buildMode: BuildMode.profile,
+ target: target,
),
CopyIcudtl(layout: layout),
const DartBuildForNative(),
@@ -100,6 +105,7 @@ class DebugBundleFlutterpiAssets extends CompositeTarget {
CopyFlutterAssets(
layout: layout,
buildMode: BuildMode.debug,
+ target: target,
),
CopyIcudtl(layout: layout),
const DartBuildForNative(),
@@ -468,17 +474,23 @@ class CopyFlutterAssets extends Target {
const CopyFlutterAssets({
required this.layout,
required this.buildMode,
+ required this.target,
});
final FilesystemLayout layout;
final BuildMode buildMode;
+ final FlutterpiTargetPlatform target;
@override
- String get name => 'copy_flutterpi_assets_${layout}_$buildMode';
+ String get name => 'copy_flutterpi_assets_${layout}_${buildMode}_$target';
@override
List get dependencies => [
const KernelSnapshot(),
+ CopyCodeAssets(
+ target: target,
+ layout: layout,
+ ),
];
@override
@@ -559,3 +571,92 @@ class CopyFlutterAssets extends Target {
);
}
}
+
+/// Inspired by flutter_tools InstallCodeAssets,
+/// but install into output folder directly, instead of
+/// into build/native_asets
+class CopyCodeAssets extends Target {
+ const CopyCodeAssets({
+ required this.target,
+ required this.layout,
+ });
+
+ final FlutterpiTargetPlatform target;
+ final FilesystemLayout layout;
+
+ @override
+ Future build(Environment environment) async {
+ final projectUri = environment.projectDir.uri;
+ final fs = environment.fileSystem;
+
+ // And install/copy the code assets to the right place and create a
+ // native_asset.yaml that can be used by the final AOT compilation.
+ final nativeAssetsJson =
+ environment.buildDir.childFile(nativeAssetsFilename);
+
+ final nativeAssetsDir =
+ fs.directory(fl.nativeAssetsBuildUri(projectUri, 'linux'));
+
+ assert(fs.file(nativeAssetsJson).existsSync());
+
+ final outputDir = switch (layout) {
+ FilesystemLayout.flutterPi => environment.outputDir,
+ FilesystemLayout.metaFlutter =>
+ environment.outputDir.childDirectory('lib'),
+ };
+
+ final inputs = [];
+ final outputs = [];
+
+ final outputNativeAssetsJson =
+ fs.file(environment.outputDir.childFile(nativeAssetsFilename));
+
+ await nativeAssetsJson.copy(outputNativeAssetsJson.path);
+ inputs.add(nativeAssetsJson);
+ outputs.add(outputNativeAssetsJson);
+
+ // copy all files from build/native_assets/linux to build/flutter-pi/.../
+ await Future.wait(
+ nativeAssetsDir.listSync().map((entity) async {
+ if (entity is! File) return;
+
+ inputs.add(entity);
+ outputs.add(entity);
+
+ entity.copy(outputDir.childFile(entity.basename).path);
+ }),
+ eagerError: true,
+ );
+
+ final outputDepfile = environment.buildDir.childFile(depFilename);
+ environment.depFileService.writeToFile(
+ fl.Depfile(inputs, outputs),
+ outputDepfile,
+ );
+ if (!outputDepfile.existsSync()) {
+ throwToolExit("${outputDepfile.path} doesn't exist.");
+ }
+ }
+
+ @override
+ List get depfiles => [depFilename];
+
+ @override
+ List get dependencies => const [InstallCodeAssets()];
+
+ @override
+ List get inputs => const [
+ Source.pattern('{BUILD_DIR}/$nativeAssetsFilename'),
+ ];
+
+ @override
+ String get name => 'copy_code_assets';
+
+ @override
+ List get outputs => const [
+ Source.pattern('{OUTPUT_DIR}/$nativeAssetsFilename'),
+ ];
+
+ static const nativeAssetsFilename = 'native_assets.json';
+ static const depFilename = 'copy_code_assets.d';
+}
diff --git a/lib/src/context.dart b/lib/src/context.dart
index 10560fe..b0eee14 100644
--- a/lib/src/context.dart
+++ b/lib/src/context.dart
@@ -7,6 +7,7 @@ import 'package:flutterpi_tool/src/build_system/build_app.dart';
import 'package:flutterpi_tool/src/config.dart';
import 'package:flutterpi_tool/src/devices/device_manager.dart';
import 'package:flutterpi_tool/src/devices/flutterpi_ssh/ssh_utils.dart';
+import 'package:github/github.dart' as gh;
import 'package:unified_analytics/unified_analytics.dart';
import 'package:http/io_client.dart' as http;
@@ -28,20 +29,28 @@ Future runInContext(
overrides: {
Analytics: () => const NoOpAnalytics(),
fl.TemplateRenderer: () => const fl.MustacheTemplateRenderer(),
- fl.Cache: () => FlutterpiCache(
- hooks: globals.shutdownHooks,
- logger: globals.logger,
- fileSystem: globals.fs,
- platform: globals.platform,
- osUtils: globals.os as MoreOperatingSystemUtils,
- projectFactory: globals.projectFactory,
- processManager: globals.processManager,
- github: MyGithub.caching(
- httpClient: http.IOClient(
- globals.httpClientFactory?.call() ?? io.HttpClient(),
- ),
+ fl.Cache: () {
+ final auth = switch (globals.platform.environment['GITHUB_TOKEN']) {
+ final token? => gh.Authentication.bearerToken(token),
+ _ => null,
+ };
+
+ return FlutterpiCache(
+ hooks: globals.shutdownHooks,
+ logger: globals.logger,
+ fileSystem: globals.fs,
+ platform: globals.platform,
+ osUtils: globals.os as MoreOperatingSystemUtils,
+ projectFactory: globals.projectFactory,
+ processManager: globals.processManager,
+ github: MyGithub.caching(
+ httpClient: http.IOClient(
+ globals.httpClientFactory?.call() ?? io.HttpClient(),
),
+ auth: auth,
),
+ );
+ },
fl.OperatingSystemUtils: () => MoreOperatingSystemUtils(
fileSystem: globals.fs,
logger: globals.logger,
diff --git a/test/app_builder_test.dart b/test/app_builder_test.dart
index 609194d..83bf118 100644
--- a/test/app_builder_test.dart
+++ b/test/app_builder_test.dart
@@ -114,33 +114,66 @@ void main() {
expect(buildWasCalled, isTrue);
});
- test('passes target path correctly', () async {
- var buildWasCalled = false;
- buildSystem.buildFn = (
- fl.Target target,
- fl.Environment environment, {
- fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
- }) async {
- expect(
- environment.defines[fl.kTargetFile],
- equals('lib/main_flutterpi.dart'),
+ group('passes target path correctly', () {
+ test('posix', () async {
+ var buildWasCalled = false;
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ expect(
+ environment.defines[fl.kTargetFile],
+ equals(p.posix.join('lib', 'main_flutterpi.dart')),
+ );
+
+ buildWasCalled = true;
+ return fl.BuildResult(success: true);
+ };
+
+ await _runInTestContext(
+ () async => await appBuilder.build(
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.flutterPi,
+ mainPath: p.posix.join('lib', 'main_flutterpi.dart'),
+ ),
);
- buildWasCalled = true;
- return fl.BuildResult(success: true);
- };
+ expect(buildWasCalled, isTrue);
+ });
- await _runInTestContext(
- () async => await appBuilder.build(
- host: FlutterpiHostPlatform.linuxRV64,
- target: FlutterpiTargetPlatform.genericRiscv64,
- buildInfo: fl.BuildInfo.debug,
- fsLayout: FilesystemLayout.flutterPi,
- mainPath: 'lib/main_flutterpi.dart',
- ),
- );
+ test('windows', () async {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
- expect(buildWasCalled, isTrue);
+ var buildWasCalled = false;
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ expect(
+ environment.defines[fl.kTargetFile],
+ equals(p.windows.join('lib', 'main_flutterpi.dart')),
+ );
+
+ buildWasCalled = true;
+ return fl.BuildResult(success: true);
+ };
+
+ await _runInTestContext(
+ () async => await appBuilder.build(
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.flutterPi,
+ mainPath: p.windows.join('lib', 'main_flutterpi.dart'),
+ ),
+ );
+
+ expect(buildWasCalled, isTrue);
+ });
});
group('--fs-layout', () {
@@ -259,34 +292,82 @@ void main() {
expect(bundle.includesFlutterpiBinary, isTrue);
});
- test('default output directory is build/-meta-flutter', () async {
- var buildWasCalled = false;
- buildSystem.buildFn = (
- fl.Target target,
- fl.Environment environment, {
- fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
- }) async {
- expect(
- environment.outputDir.path,
- equals('build/flutter-pi/meta-flutter-riscv64-generic'),
+ group('default output directory is build/-meta-flutter', () {
+ test('posix', () async {
+ var buildWasCalled = false;
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig =
+ const fl.BuildSystemConfig(),
+ }) async {
+ expect(
+ environment.outputDir.path,
+ equals(
+ p.posix.join(
+ 'build',
+ 'flutter-pi',
+ 'meta-flutter-riscv64-generic',
+ ),
+ ),
+ );
+
+ buildWasCalled = true;
+ return fl.BuildResult(success: true);
+ };
+
+ await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.metaFlutter,
+ forceBundleFlutterpi: true,
+ ),
);
- buildWasCalled = true;
- return fl.BuildResult(success: true);
- };
-
- await _runInTestContext(
- () async => await appBuilder.buildBundle(
- id: 'test-id',
- host: FlutterpiHostPlatform.linuxRV64,
- target: FlutterpiTargetPlatform.genericRiscv64,
- buildInfo: fl.BuildInfo.debug,
- fsLayout: FilesystemLayout.metaFlutter,
- forceBundleFlutterpi: true,
- ),
- );
+ expect(buildWasCalled, isTrue);
+ });
+
+ test('windows', () async {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
+
+ var buildWasCalled = false;
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig =
+ const fl.BuildSystemConfig(),
+ }) async {
+ expect(
+ environment.outputDir.path,
+ equals(
+ p.windows.join(
+ 'build',
+ 'flutter-pi',
+ 'meta-flutter-riscv64-generic',
+ ),
+ ),
+ );
+
+ buildWasCalled = true;
+ return fl.BuildResult(success: true);
+ };
+
+ await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.metaFlutter,
+ forceBundleFlutterpi: true,
+ ),
+ );
- expect(buildWasCalled, isTrue);
+ expect(buildWasCalled, isTrue);
+ });
});
});
@@ -366,34 +447,74 @@ void main() {
expect(buildWasCalled, isTrue);
});
- test('default output directory is build/', () async {
- var buildWasCalled = false;
- buildSystem.buildFn = (
- fl.Target target,
- fl.Environment environment, {
- fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
- }) async {
- expect(
- environment.outputDir.path,
- equals('build/flutter-pi/riscv64-generic'),
+ group('default output directory is build/', () {
+ test('posix', () async {
+ var buildWasCalled = false;
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig =
+ const fl.BuildSystemConfig(),
+ }) async {
+ expect(
+ environment.outputDir.path,
+ equals(
+ p.posix.join('build', 'flutter-pi', 'riscv64-generic'),
+ ),
+ );
+
+ buildWasCalled = true;
+ return fl.BuildResult(success: true);
+ };
+
+ await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.flutterPi,
+ forceBundleFlutterpi: true,
+ ),
);
- buildWasCalled = true;
- return fl.BuildResult(success: true);
- };
-
- await _runInTestContext(
- () async => await appBuilder.buildBundle(
- id: 'test-id',
- host: FlutterpiHostPlatform.linuxRV64,
- target: FlutterpiTargetPlatform.genericRiscv64,
- buildInfo: fl.BuildInfo.debug,
- fsLayout: FilesystemLayout.flutterPi,
- forceBundleFlutterpi: true,
- ),
- );
+ expect(buildWasCalled, isTrue);
+ });
+
+ test('windows', () async {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
+
+ var buildWasCalled = false;
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig =
+ const fl.BuildSystemConfig(),
+ }) async {
+ expect(
+ environment.outputDir.path,
+ equals(
+ p.windows.join('build', 'flutter-pi', 'riscv64-generic'),
+ ),
+ );
+
+ buildWasCalled = true;
+ return fl.BuildResult(success: true);
+ };
+
+ await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.flutterPi,
+ forceBundleFlutterpi: true,
+ ),
+ );
- expect(buildWasCalled, isTrue);
+ expect(buildWasCalled, isTrue);
+ });
});
});
});
@@ -469,176 +590,379 @@ void main() {
});
group('bundle binaries', () {
- test('binary paths for --fs-layout=flutter-pi', () async {
- buildSystem.buildFn = (
- fl.Target target,
- fl.Environment environment, {
- fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
- }) async {
- return fl.BuildResult(success: true);
- };
+ group('binary paths for --fs-layout=flutter-pi', () {
+ test('posix', () async {
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
- final bundle = await _runInTestContext(
- () async => await appBuilder.buildBundle(
- id: 'test-id',
- host: FlutterpiHostPlatform.linuxRV64,
- target: FlutterpiTargetPlatform.genericRiscv64,
- buildInfo: fl.BuildInfo.debug,
- fsLayout: FilesystemLayout.flutterPi,
- forceBundleFlutterpi: false,
- ),
- ) as PrebuiltFlutterpiAppBundle;
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.flutterPi,
+ forceBundleFlutterpi: false,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
- expect(
- bundle.binaries.map(
- (file) =>
- p.relative(file.path, from: 'build/flutter-pi/riscv64-generic'),
- ),
- unorderedEquals([
- 'flutter-pi',
- 'libflutter_engine.so',
- ]),
- );
+ expect(
+ bundle.binaries.map(
+ (file) => p.posix.relative(
+ file.path,
+ from: p.posix.join('build', 'flutter-pi', 'riscv64-generic'),
+ ),
+ ),
+ unorderedEquals([
+ 'flutter-pi',
+ 'libflutter_engine.so',
+ ]),
+ );
+ });
+
+ test('windows', () async {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
+
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
+
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.flutterPi,
+ forceBundleFlutterpi: false,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
+
+ expect(
+ bundle.binaries.map(
+ (file) => p.windows.relative(
+ file.path,
+ from: p.windows.join('build', 'flutter-pi', 'riscv64-generic'),
+ ),
+ ),
+ unorderedEquals([
+ 'flutter-pi',
+ 'libflutter_engine.so',
+ ]),
+ );
+ });
});
- test('binary paths for --fs-layout=flutter-pi and include debug symbols',
- () async {
- buildSystem.buildFn = (
- fl.Target target,
- fl.Environment environment, {
- fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
- }) async {
- return fl.BuildResult(success: true);
- };
+ group('binary paths for --fs-layout=flutter-pi and include debug symbols',
+ () {
+ test('posix', () async {
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
- final bundle = await _runInTestContext(
- () async => await appBuilder.buildBundle(
- id: 'test-id',
- host: FlutterpiHostPlatform.linuxRV64,
- target: FlutterpiTargetPlatform.genericRiscv64,
- buildInfo: fl.BuildInfo.debug,
- fsLayout: FilesystemLayout.flutterPi,
- includeDebugSymbols: true,
- forceBundleFlutterpi: false,
- ),
- ) as PrebuiltFlutterpiAppBundle;
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.flutterPi,
+ includeDebugSymbols: true,
+ forceBundleFlutterpi: false,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
- expect(
- bundle.binaries.map(
- (file) =>
- p.relative(file.path, from: 'build/flutter-pi/riscv64-generic'),
- ),
- unorderedEquals([
- 'flutter-pi',
- 'libflutter_engine.dbgsyms',
- 'libflutter_engine.so',
- ]),
- );
+ expect(
+ bundle.binaries.map(
+ (file) => p.posix.relative(
+ file.path,
+ from: p.posix.join('build', 'flutter-pi', 'riscv64-generic'),
+ ),
+ ),
+ unorderedEquals([
+ 'flutter-pi',
+ 'libflutter_engine.dbgsyms',
+ 'libflutter_engine.so',
+ ]),
+ );
+ });
+
+ test('windows', () async {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
+
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
+
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.flutterPi,
+ includeDebugSymbols: true,
+ forceBundleFlutterpi: false,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
+
+ expect(
+ bundle.binaries.map(
+ (file) => p.windows.relative(
+ file.path,
+ from: p.windows.join('build', 'flutter-pi', 'riscv64-generic'),
+ ),
+ ),
+ unorderedEquals([
+ 'flutter-pi',
+ 'libflutter_engine.dbgsyms',
+ 'libflutter_engine.so',
+ ]),
+ );
+ });
});
- test('binary paths for --fs-layout=meta-flutter', () async {
- buildSystem.buildFn = (
- fl.Target target,
- fl.Environment environment, {
- fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
- }) async {
- return fl.BuildResult(success: true);
- };
+ group('binary paths for --fs-layout=meta-flutter', () {
+ test('posix', () async {
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
- final bundle = await _runInTestContext(
- () async => await appBuilder.buildBundle(
- id: 'test-id',
- host: FlutterpiHostPlatform.linuxRV64,
- target: FlutterpiTargetPlatform.genericRiscv64,
- buildInfo: fl.BuildInfo.debug,
- fsLayout: FilesystemLayout.metaFlutter,
- forceBundleFlutterpi: false,
- ),
- ) as PrebuiltFlutterpiAppBundle;
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.metaFlutter,
+ forceBundleFlutterpi: false,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
- expect(
- bundle.binaries.map(
- (file) => p.relative(
- file.path,
- from: 'build/flutter-pi/meta-flutter-riscv64-generic',
+ expect(
+ bundle.binaries.map(
+ (file) => p.posix.relative(
+ file.path,
+ from: p.posix
+ .join('build', 'flutter-pi', 'meta-flutter-riscv64-generic'),
+ ),
),
- ),
- unorderedEquals([
- 'lib/libflutter_engine.so',
- ]),
- );
+ unorderedEquals([
+ p.posix.join('lib', 'libflutter_engine.so'),
+ ]),
+ );
+ });
+
+ test('windows', () async {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
+
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
+
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.metaFlutter,
+ forceBundleFlutterpi: false,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
+
+ expect(
+ bundle.binaries.map(
+ (file) => p.windows.relative(
+ file.path,
+ from: p.windows
+ .join('build', 'flutter-pi', 'meta-flutter-riscv64-generic'),
+ ),
+ ),
+ unorderedEquals([
+ p.windows.join('lib', 'libflutter_engine.so'),
+ ]),
+ );
+ });
});
- test(
+ group(
'binary paths for --fs-layout=meta-flutter with force bundle flutterpi',
- () async {
- buildSystem.buildFn = (
- fl.Target target,
- fl.Environment environment, {
- fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
- }) async {
- return fl.BuildResult(success: true);
- };
+ () {
+ test('posix', () async {
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
- final bundle = await _runInTestContext(
- () async => await appBuilder.buildBundle(
- id: 'test-id',
- host: FlutterpiHostPlatform.linuxRV64,
- target: FlutterpiTargetPlatform.genericRiscv64,
- buildInfo: fl.BuildInfo.debug,
- fsLayout: FilesystemLayout.metaFlutter,
- forceBundleFlutterpi: true,
- ),
- ) as PrebuiltFlutterpiAppBundle;
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.metaFlutter,
+ forceBundleFlutterpi: true,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
- expect(
- bundle.binaries.map(
- (file) => p.relative(
- file.path,
- from: 'build/flutter-pi/meta-flutter-riscv64-generic',
+ expect(
+ bundle.binaries.map(
+ (file) => p.posix.relative(
+ file.path,
+ from: p.posix
+ .join('build', 'flutter-pi', 'meta-flutter-riscv64-generic'),
+ ),
),
- ),
- unorderedEquals([
- 'bin/flutter-pi',
- 'lib/libflutter_engine.so',
- ]),
- );
+ unorderedEquals([
+ p.posix.join('bin', 'flutter-pi'),
+ p.posix.join('lib', 'libflutter_engine.so'),
+ ]),
+ );
+ });
+
+ test('windows', () async {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
+
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
+
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.metaFlutter,
+ forceBundleFlutterpi: true,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
+
+ expect(
+ bundle.binaries.map(
+ (file) => p.windows.relative(
+ file.path,
+ from: p.windows
+ .join('build', 'flutter-pi', 'meta-flutter-riscv64-generic'),
+ ),
+ ),
+ unorderedEquals([
+ p.windows.join('bin', 'flutter-pi'),
+ p.windows.join('lib', 'libflutter_engine.so'),
+ ]),
+ );
+ });
});
- test('binary paths for --fs-layout=meta-flutter with include debug symbols',
- () async {
- buildSystem.buildFn = (
- fl.Target target,
- fl.Environment environment, {
- fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
- }) async {
- return fl.BuildResult(success: true);
- };
+ group(
+ 'binary paths for --fs-layout=meta-flutter with include debug symbols',
+ () {
+ test('posix', () async {
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
- final bundle = await _runInTestContext(
- () async => await appBuilder.buildBundle(
- id: 'test-id',
- host: FlutterpiHostPlatform.linuxRV64,
- target: FlutterpiTargetPlatform.genericRiscv64,
- buildInfo: fl.BuildInfo.debug,
- fsLayout: FilesystemLayout.metaFlutter,
- includeDebugSymbols: true,
- forceBundleFlutterpi: false,
- ),
- ) as PrebuiltFlutterpiAppBundle;
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.metaFlutter,
+ includeDebugSymbols: true,
+ forceBundleFlutterpi: false,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
- expect(
- bundle.binaries.map(
- (file) => p.relative(
- file.path,
- from: 'build/flutter-pi/meta-flutter-riscv64-generic',
+ expect(
+ bundle.binaries.map(
+ (file) => p.posix.relative(
+ file.path,
+ from: p.posix
+ .join('build', 'flutter-pi', 'meta-flutter-riscv64-generic'),
+ ),
),
- ),
- unorderedEquals([
- 'lib/libflutter_engine.dbgsyms',
- 'lib/libflutter_engine.so',
- ]),
- );
+ unorderedEquals([
+ p.posix.join('lib', 'libflutter_engine.dbgsyms'),
+ p.posix.join('lib', 'libflutter_engine.so'),
+ ]),
+ );
+ });
+
+ test('windows', () async {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
+
+ buildSystem.buildFn = (
+ fl.Target target,
+ fl.Environment environment, {
+ fl.BuildSystemConfig buildSystemConfig = const fl.BuildSystemConfig(),
+ }) async {
+ return fl.BuildResult(success: true);
+ };
+
+ final bundle = await _runInTestContext(
+ () async => await appBuilder.buildBundle(
+ id: 'test-id',
+ host: FlutterpiHostPlatform.linuxRV64,
+ target: FlutterpiTargetPlatform.genericRiscv64,
+ buildInfo: fl.BuildInfo.debug,
+ fsLayout: FilesystemLayout.metaFlutter,
+ includeDebugSymbols: true,
+ forceBundleFlutterpi: false,
+ ),
+ ) as PrebuiltFlutterpiAppBundle;
+
+ expect(
+ bundle.binaries.map(
+ (file) => p.windows.relative(
+ file.path,
+ from: p.windows
+ .join('build', 'flutter-pi', 'meta-flutter-riscv64-generic'),
+ ),
+ ),
+ unorderedEquals([
+ p.windows.join('lib', 'libflutter_engine.dbgsyms'),
+ p.windows.join('lib', 'libflutter_engine.so'),
+ ]),
+ );
+ });
});
});
}