Skip to content

Commit

Permalink
feat(rust): add flutter_rust_bridge (#347)
Browse files Browse the repository at this point in the history
* feat(rust): add flutter_rust_bridge tool

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix(rust): flutter_rust_bridge tool package name

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix(rust): flutter_rust_bridge install

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix(rust): add builder for flutter_rust_bridge

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix(flutter): create install flutter function

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix(rust): create install rust function

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: add word to dict

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: add code gen web

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: code gen web as a function

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: remove save artifact

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix(rust): rust install

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: flutter_rust_bridge builder

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: typo

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: add flutter_rust_bridge to existing flutter example

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: doc and comment

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: bash check

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: flutter_rust_bridge

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: auto gen file

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: cp file command

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: rm file command

Signed-off-by: bkioshn <bkioshn@gmail.com>

* fix: copy contents of pkg folder, not the folder itself

---------

Signed-off-by: bkioshn <bkioshn@gmail.com>
Co-authored-by: Dominik Toton <dominik.toton@iohk.io>
  • Loading branch information
bkioshn and dtscalac authored Nov 8, 2024
1 parent f746f97 commit 474e2f8
Show file tree
Hide file tree
Showing 70 changed files with 4,929 additions and 135 deletions.
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

0 comments on commit 474e2f8

Please sign in to comment.