Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rust): add flutter_rust_bridge #347

Merged
merged 25 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1f1a4e7
feat(rust): add flutter_rust_bridge tool
bkioshn Nov 4, 2024
657c66f
fix(rust): flutter_rust_bridge tool package name
bkioshn Nov 4, 2024
10d0e07
fix(rust): flutter_rust_bridge install
bkioshn Nov 4, 2024
c3369a2
fix(rust): add builder for flutter_rust_bridge
bkioshn Nov 4, 2024
6414b31
fix(flutter): create install flutter function
bkioshn Nov 4, 2024
a29cc10
fix(rust): create install rust function
bkioshn Nov 4, 2024
4e01564
fix: add word to dict
bkioshn Nov 4, 2024
c207ec6
fix: add code gen web
bkioshn Nov 4, 2024
29b29b8
fix: code gen web as a function
bkioshn Nov 4, 2024
b073227
fix: remove save artifact
bkioshn Nov 4, 2024
4677507
fix(rust): rust install
bkioshn Nov 4, 2024
08d9a09
fix: flutter_rust_bridge builder
bkioshn Nov 4, 2024
fdf9ee8
fix: typo
bkioshn Nov 4, 2024
0ae7c4c
fix: add flutter_rust_bridge to existing flutter example
bkioshn Nov 5, 2024
50219cc
fix: doc and comment
bkioshn Nov 5, 2024
163c49c
fix: bash check
bkioshn Nov 5, 2024
3f23239
fix: flutter_rust_bridge
bkioshn Nov 6, 2024
3819260
fix: auto gen file
bkioshn Nov 6, 2024
c1c516c
Merge branch 'master' into feat/add-flutter-rust-bridge
bkioshn Nov 6, 2024
13c2417
fix: cp file command
bkioshn Nov 6, 2024
ea6c434
fix: rm file command
bkioshn Nov 6, 2024
8097131
fix: copy contents of pkg folder, not the folder itself
dtscalac Nov 8, 2024
a34563f
Merge branch 'master' into feat/add-flutter-rust-bridge
minikin Nov 8, 2024
db0dd39
fix: remove commented code
bkioshn Nov 8, 2024
8fd00c1
doc: update flutter readme
bkioshn Nov 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .config/dictionaries/project.dic
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
aarch
bindgen
binstall
bkioshn
buildkit
camelcase
canvaskit
Expand Down Expand Up @@ -46,6 +47,7 @@ gopls
gosec
graphviz
idents
JDBC
jorm
jormungandr
junitreport
Expand Down Expand Up @@ -89,6 +91,7 @@ PYTHONDONTWRITEBYTECODE
rankdir
rivo
runewidth
rustc
rustdoc
rustdocflags
rustflags
Expand Down Expand Up @@ -122,4 +125,3 @@ xerrors
xvfb
zstd
zstdcat
JDBC
33 changes: 33 additions & 0 deletions docs/src/guides/languages/flutter.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,39 @@ please follow this [guide](./../../onboarding/index.md).
It is pretty strait forward for this builder process,
because as a part of `+build` target we already creating a docker image.

## Enhancing Flutter

### Integrating Flutter with Rust using `flutter_rust_bridge`

The `flutter_rust_bridge` allows you to integrate Rust with Flutter app, while maintaining the rest of the app in
Dart.
This can be useful for situations where you need to run complex algorithms, handle data
processing, or interact with low-level system APIs, but still want to leverage the Flutter ecosystem
for UI and app management.

Start by creating a new builder where all the necessary setup is done under the `flutter_rust_bridge+builder`,
then copy the Flutter project that already have `flutter_rust_bridge` setup.
Refer to <https://cjycode.com/flutter_rust_bridge/> for how to setup the project.

```Earthfile
builder-frb:
FROM flutter_rust_bridge+builder
COPY . .
```

Then generate a binding between Rust and Flutter

```Earthfile
# Generated necessary files for running Flutter web locally and save it locally.
code-generator-web:
FROM +builder-frb
DO flutter_rust_bridge+CODE_GENERATOR_WEB

SAVE ARTIFACT ./assets/js AS LOCAL ./assets/js
SAVE ARTIFACT ./rust/src/frb_generated.rs AS LOCAL ./rust/src/frb_generated.rs
SAVE ARTIFACT ./lib/src AS LOCAL ./lib/src
```

## Conclusion

You can see the final `Earthfile`
Expand Down
49 changes: 26 additions & 23 deletions earthly/flutter/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,47 @@ VERSION 0.8

IMPORT ./installer AS installer

# flutter-src save Flutter source code as artifact.
flutter-src:
FROM busybox
# TODO(bkioshn): https://github.com/input-output-hk/catalyst-ci/issues/322
# Install flutter.
INSTALL_FLUTTER:
FUNCTION
ARG version=3.24.1
ARG TARGETARCH

RUN mkdir -p /flutter
# Install Flutter
IF [ "$TARGETARCH" = "amd64" ]
RUN wget -qO - https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_$version-stable.tar.xz \
| tar -xJ -C /flutter
| tar -xJ -C /usr/local
ELSE IF [ "$TARGETARCH" = "arm64" ]
GIT CLONE --branch $version https://github.com/flutter/flutter.git /usr/local
ELSE
GIT CLONE --branch $version https://github.com/flutter/flutter.git /flutter
RUN echo >&2 "unsupported architecture: ${TARGETARCH}"; exit 1
END
SAVE ARTIFACT /flutter flutter

RUN git config --global --add safe.directory /usr/local/flutter
ENV PATH="/usr/local/flutter/bin:/usr/local/flutter/bin/cache/dart-sdk/bin:$HOME/.pub-cache/bin:${PATH}"

ENV CI="true"
RUN flutter config --no-analytics
RUN flutter --version
RUN flutter doctor -v
RUN flutter config --enable-web
RUN dart pub global activate melos
RUN dart pub global activate junitreport
RUN dart pub global activate coverage
RUN dart pub global activate combine_coverage
RUN dart pub global activate license_checker

# flutter-base installs required tools and packages.
flutter-base:
FROM debian:bookworm-20240513-slim

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update --fix-missing
RUN apt-get install -y apt-utils git curl gzip unzip bzip2 bash jq gpg lcov
RUN apt-get install -y apt-utils git curl gzip unzip bzip2 bash jq gpg lcov tar wget xz-utils

DO +INSTALL_FLUTTER

WORKDIR frontend

Expand All @@ -37,21 +55,6 @@ flutter-base:
ARG edge_package_release = 1
DO installer+INSTALL_EDGE_LINUX64 --edge_version=$edge_version --edge_package_release=$edge_package_release

COPY +flutter-src/flutter /usr/local
ENV PATH="/usr/local/flutter/bin:/usr/local/flutter/bin/cache/dart-sdk/bin:$HOME/.pub-cache/bin:${PATH}"
# Flutter prints warnings when used by root user but omits them if has CI env flag found.
# script: https://github.com/flutter/flutter/blob/master/bin/internal/shared.sh#L214
ENV CI="true"
RUN flutter config --no-analytics
RUN flutter --version
RUN flutter doctor -v
RUN flutter config --enable-web
RUN dart pub global activate melos
RUN dart pub global activate junitreport
RUN dart pub global activate coverage
RUN dart pub global activate combine_coverage
RUN dart pub global activate license_checker

# test-flutter-base-amd64 : installs required tools and packages for amd64.
test-flutter-base-amd64:
BUILD --platform=linux/amd64 +flutter-base
Expand Down
38 changes: 38 additions & 0 deletions earthly/flutter_rust_bridge/Earthfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
VERSION 0.8

IMPORT ../flutter AS flutter-ci
IMPORT ../rust AS rust-ci

# This will be refactored in the future
# TODO(bkioshn): https://github.com/input-output-hk/catalyst-ci/issues/322
# builder: Setup necessary tools for `flutter_rust_bridge`
builder:
FROM debian:stable-slim

WORKDIR /work

RUN apt-get update \
&& apt-get install -y \
apt-utils \
wget \
tar \
xz-utils \
git \
build-essential \
curl \
unzip

DO flutter-ci+INSTALL_FLUTTER
DO rust-ci+INSTALL_RUST
DO rust-ci+INSTALL_TOOLS

# Generated necessary files for running Flutter web.
CODE_GENERATOR_WEB:
FUNCTION

RUN flutter_rust_bridge_codegen generate --default-external-library-loader-web-prefix=/assets/packages/catalyst_key_derivation/assets/js/
RUN flutter_rust_bridge_codegen build-web

RUN mkdir -p assets/js && cp -rf ./web/pkg/* assets/js/
# Don't want this gitignore file.
RUN rm -rf ./assets/js/.gitignore
92 changes: 90 additions & 2 deletions earthly/rust/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ COPY_TOOL:
FUNCTION

ARG --required tool
COPY rust-tools+tool-$tool/$tool $CARGO_HOME/bin/$tool
ARG bin = $tool
COPY rust-tools+tool-$tool/$bin $CARGO_HOME/bin/$bin


# rust-base-plus-tools : Add all tools we use for rust builds to the base builder image.
Expand Down Expand Up @@ -360,4 +361,91 @@ REMOVE_SOURCE_FINGERPRINTS:
find . -maxdepth 1 -regex "\./$source_lib-[^-]+" -exec bash -c 'echo "deleting $(readlink -f {})"; rm -rf {}' \; ; \
done \
fi; \
done;
done;

# TODO(bkioshn): https://github.com/input-output-hk/catalyst-ci/issues/322
# Installing Rust
# Code reference from [rust1.81.0-slim-bookworm](https://github.com/rust-lang/docker-rust/blob/63f877a36f8ba9d9b4b35cd49df3327264510886/stable/bookworm/slim/Dockerfile)
INSTALL_RUST:
FUNCTION

ARG TARGETARCH

ENV RUSTUP_HOME=/usr/local/rustup
ENV CARGO_HOME=/usr/local/cargo
ENV PATH=/usr/local/cargo/bin:$PATH
ENV RUST_VERSION=1.81.0

IF [ "$TARGETARCH" = "amd64" ]
LET PLATFORM = "x86_64-unknown-linux-gnu"
LET RUSTUP_SHA = "6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d"
ELSE IF [ "$TARGETARCH" = "arm64" ]
LET PLATFORM = "aarch64-unknown-linux-gnu"
LET RUSTUP_SHA = "1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2"
ELSE
RUN echo >&2 "unsupported architecture: ${TARGETARCH}"; exit 1
END

LET URL = "https://static.rust-lang.org/rustup/archive/1.27.1/${PLATFORM}/rustup-init"
RUN wget $URL && echo "${RUSTUP_SHA} *rustup-init" | sha256sum -c - \
&& chmod +x rustup-init \
&& ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host $PLATFORM \
&& rm rustup-init \
&& chmod -R a+w $RUSTUP_HOME $CARGO_HOME \
&& rustup --version \
&& cargo --version \
&& rustc --version \
&& rm -rf /var/lib/apt/lists/*

# Make sure we have cargo.
RUN rustup component add cargo

# Make sure we have the clippy linter.
RUN rustup component add clippy

# Needed to generate code coverage.
RUN rustup component add llvm-tools-preview

# Install a nightly toolchain which matches.
RUN rustup toolchain install nightly --component miri --component rust-src --component rustfmt --component clippy --component cargo

# Ensure we have all the necessary targets
RUN rustup target add wasm32-unknown-unknown
RUN rustup target add wasm32-wasip1
# RUN rustup target add wasm32-wasip2 # wasm32-wasip2 not yet available in stable - Try again in 1.82
RUN rustup target add x86_64-unknown-linux-gnu
RUN rustup target add x86_64-apple-darwin
RUN rustup target add x86_64-pc-windows-gnu
RUN rustup target add aarch64-unknown-linux-gnu
RUN rustup target add aarch64-apple-darwin

RUN rustup target add wasm32-unknown-unknown --toolchain nightly
RUN rustup target add wasm32-wasip1 --toolchain nightly
RUN rustup target add wasm32-wasip2 --toolchain nightly
RUN rustup target add x86_64-unknown-linux-gnu --toolchain nightly
RUN rustup target add x86_64-apple-darwin --toolchain nightly
RUN rustup target add x86_64-pc-windows-gnu --toolchain nightly
RUN rustup target add aarch64-unknown-linux-gnu --toolchain nightly
RUN rustup target add aarch64-apple-darwin --toolchain nightly

# Install necessary tools for Rust.
INSTALL_TOOLS:
FUNCTION
# Install cargo-binstall so we can speed up tool installation.
DO rust-tools+CARGO_BINSTALL_INSTALL

DO +COPY_TOOL --tool="cargo-nextest"
DO +COPY_TOOL --tool="cargo-machete"
DO +COPY_TOOL --tool="refinery"
DO +COPY_TOOL --tool="cargo-deny"
DO +COPY_TOOL --tool="cargo-modules"
DO +COPY_TOOL --tool="cargo-depgraph"
DO +COPY_TOOL --tool="cargo-llvm-cov"
DO +COPY_TOOL --tool="wasm-tools"
DO +COPY_TOOL --tool="cargo-expand"
DO +COPY_TOOL --tool="wit-bindgen"
DO +COPY_TOOL --tool="cargo-sweep"
DO +COPY_TOOL --tool="cargo-component"
DO +COPY_TOOL --tool="wasm-pack"
DO +COPY_TOOL --tool="flutter-rust-bridge-codegen" --bin="flutter_rust_bridge_codegen"

3 changes: 3 additions & 0 deletions earthly/rust/tools/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,6 @@ tool-cargo-component:

tool-wasm-pack:
DO +CARGO_BINSTALL --package=wasm-pack --version=0.13.0

tool-flutter-rust-bridge-codegen:
DO +CARGO_BINSTALL --package=flutter_rust_bridge_codegen --version=2.5.1 --executable="flutter_rust_bridge_codegen"
16 changes: 16 additions & 0 deletions examples/flutter/example/Earthfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
VERSION 0.8

IMPORT ../../../earthly/flutter AS flutter-ci
IMPORT ../../../earthly/flutter_rust_bridge AS flutter_rust_bridge

# To see more available functions, navigate to earthly/flutter/Earthfile.

Expand Down Expand Up @@ -39,3 +40,18 @@ build-web:
ARG --required SENTRY_DSN

DO flutter-ci+BUILD_WEB --WORKDIR=$WORKDIR --TARGET=$TARGET --SENTRY_DSN=$SENTRY_DSN

# -----------------flutter_rust_bridge-----------------

builder-frb:
FROM flutter_rust_bridge+builder
COPY . .

# Generated necessary files for running Flutter web locally and save it locally.
code-generator-web:
FROM +builder-frb
DO flutter_rust_bridge+CODE_GENERATOR_WEB

SAVE ARTIFACT ./assets/js AS LOCAL ./assets/js
SAVE ARTIFACT ./rust/src/frb_generated.rs AS LOCAL ./rust/src/frb_generated.rs
SAVE ARTIFACT ./lib/src AS LOCAL ./lib/src
3 changes: 3 additions & 0 deletions examples/flutter/example/flutter_rust_bridge.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
rust_input: crate::api
rust_root: rust/
dart_output: lib/src/rust
13 changes: 13 additions & 0 deletions examples/flutter/example/integration_test/simple_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:example/main.dart';
import 'package:example/src/rust/frb_generated.dart';
import 'package:integration_test/integration_test.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() async => await RustLib.init());
testWidgets('Can call rust function', (WidgetTester tester) async {
await tester.pumpWidget(const MyApp());
expect(find.textContaining('Result: `Hello, Tom!`'), findsOneWidget);
});
}
Loading