{"id":13554506,"url":"https://github.com/brickpop/flutter-rust-ffi","last_synced_at":"2025-04-05T06:05:15.721Z","repository":{"id":46305510,"uuid":"244608150","full_name":"brickpop/flutter-rust-ffi","owner":"brickpop","description":"Starter project for Flutter plugins willing to access native and synchronous rust code using FFI","archived":false,"fork":false,"pushed_at":"2021-10-31T22:13:18.000Z","size":184,"stargazers_count":598,"open_issues_count":10,"forks_count":51,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-29T05:04:46.196Z","etag":null,"topics":["flutter","mobile","native","rust"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brickpop.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-03T10:34:36.000Z","updated_at":"2025-03-20T11:37:26.000Z","dependencies_parsed_at":"2022-07-26T15:32:05.900Z","dependency_job_id":null,"html_url":"https://github.com/brickpop/flutter-rust-ffi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brickpop%2Fflutter-rust-ffi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brickpop%2Fflutter-rust-ffi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brickpop%2Fflutter-rust-ffi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brickpop%2Fflutter-rust-ffi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brickpop","download_url":"https://codeload.github.com/brickpop/flutter-rust-ffi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247294538,"owners_count":20915340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flutter","mobile","native","rust"],"created_at":"2024-08-01T12:02:49.229Z","updated_at":"2025-04-05T06:05:15.693Z","avatar_url":"https://github.com/brickpop.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# Flutter Rust FFI Template\n\nThis project is a Flutter Plugin template. \n\nIt provides out-of-the box support for cross-compiling native Rust code for all available iOS and Android architectures and call it from plain Dart using [Foreign Function Interface](https://en.wikipedia.org/wiki/Foreign_function_interface).\n\nThis template provides first class FFI support, **the clean way**. \n- No Swift/Kotlin wrappers\n- No message passing\n- No async/await on Dart\n- Write once, use everywhere\n- No garbage collection\n- Mostly automated development\n- No need to export `aar` bundles or `.framework`'s\n\n## Getting started\n\n### Write your native code\n\nEdit your code within `rust/src/lib.rs` and add any dependencies you need.\n\nMake sure to annotate your exported functions with `#[no_mangle]` and `pub extern` so the function names can be matched from Dart.\n\nReturning strings or structs may require using `unsafe` blocks. Returned strings or structs will need to be `free`'d from Dart.\n\n### Compile the library\n\n- Make sure that the Android NDK is installed\n  - You might also need LLVM from the SDK manager\n- Ensure that the env variable `$ANDROID_NDK_HOME` points to the NDK base folder\n  - It may look like `/Users/brickpop/Library/Android/sdk/ndk-bundle` on MacOS\n  - And look like `/home/brickpop/dev/android/ndk-bundle` on Linux\n- On the `rust` folder:\n  - Run `make` to see the available actions\n  - Run `make init` to install the Rust targets\n  - Run `make all` to build the libraries and the `.h` file\n- Update the name of your library in `Cargo.toml`\n  - You'll need to update the symlinks to target the new file names. See iOS and Android below.\n\nGenerated artifacts:\n- Android libraries\n  - `target/aarch64-linux-android/release/libexample.so`\n  - `target/armv7-linux-androideabi/release/libexample.so`\n  - `target/i686-linux-android/release/libexample.so`\n  - `target/x86_64-linux-android/release/libexample.so`\n- iOS library\n  - `target/universal/release/libexample.a`\n- Bindings header\n  - `target/bindings.h`\n\n### Reference the shared objects\n\n#### iOS\n\nEnsure that `ios/mylib.podspec` includes the following directives:\n\n```diff\n...\n   s.source           = { :path =\u003e '.' }\n+  s.public_header_files = 'Classes**/*.h'\n   s.source_files = 'Classes/**/*'\n+  s.static_framework = true\n+  s.vendored_libraries = \"**/*.a\"\n   s.dependency 'Flutter'\n   s.platform = :ios, '8.0'\n...\n```\n\nOn `flutter/ios`, place a symbolic link to the `libexample.a` file\n\n```sh\n$ cd flutter/ios\n$ ln -s ../rust/target/universal/release/libexample.a .\n```\n\nAppend the generated function signatures from `rust/target/bindings.h` into `flutter/ios/Classes/MylibPlugin.h`\n\n```sh \n$ cd flutter/ios\n$ cat ../rust/target/bindings.h \u003e\u003e Classes/MylibPlugin.h\n```\n\nIn our case, it will append `char *rust_greeting(const char *to);` and `void rust_cstr_free(char *s);`\n\nNOTE: By default, XCode will skip bundling the `libexample.a` library if it detects that it is not being used. To force its inclusion, add dummy invocations in `SwiftMylibPlugin.swift` that use every single native function that you use from Flutter:\n\n```kotlin\n...\n  public func dummyMethodToEnforceBundling() {\n    rust_greeting(\"...\");\n    compress_jpeg_file(\"...\");\n    compress_png_file(\"...\");\n    // ...\n    // This code will force the bundler to use these functions, but will never be called\n  }\n}\n```\n\nIf you won't be using Flutter channels, the rest of methods can be left empty.\n\n\u003e Note: Support for avmv7, armv7s and i386 is deprecated. The targets can still be compiled with Rust 1.41 or earlier and by uncommenting the `make init` line on `rust/makefile`\n\n#### Android\n\nSimilarly as we did on iOS with `libexample.a`, create symlinks pointing to the binary libraries on `rust/target`.\n\nYou should have the following structure on `flutter/android` for each architecture:\n\n```\nsrc\n└── main\n    └── jniLibs\n        ├── arm64-v8a\n        │   └── libexample.so@ -\u003e ../../../../../rust/target/aarch64-linux-android/release/libexample.so\n        ├── armeabi-v7a\n        │   └── libexample.so@ -\u003e ../../../../../rust/target/armv7-linux-androideabi/release/libexample.so\n        ├── x86\n        │   └── libexample.so@ -\u003e ../../../../../rust/target/i686-linux-android/release/libexample.so\n        └── x86_64\n            └── libexample.so@ -\u003e ../../../../../rust/target/x86_64-linux-android/release/libexample.so\n```\n\nAs before, if you are not using Flutter channels, the methods within `android/src/main/kotlin/org/mylib/mylib/MylibPlugin.kt` can be left empty.\n\n### Exposing a Dart API to use the bindings\n\nTo invoke the native code: load the library, locate the symbols and `typedef` the Dart functions. You can automate this process from `rust/target/bindings.h` or do it manually.\n\n#### Automatic binding generation\n\nTo use [ffigen](https://pub.dev/packages/ffigen), add the dependency in `pubspec.yaml`.\n\n```diff\n dev_dependencies:\n   flutter_test:\n     sdk: flutter\n+  ffigen: ^1.2.0\n```\n\nAlso, add the following lines at the end of `pubspec.yaml`:\n\n```yaml\nffigen:\n  output: lib/bindings.dart\n  headers:\n    entry-points:\n    - rust/target/bindings.h\n  name: GreeterBindings\n  description: Dart bindings to call mylib functions\n```\n\n**On MacOS**:\n```sh\nbrew install llvm\nflutter pub run ffigen:setup -I/usr/local/opt/llvm/include -L/usr/local/opt/llvm/lib\n```\n\n**On Linux**:\n```sh\nsudo apt-get install -y clang libclang-dev\nflutter pub run ffigen:setup\n```\n\nGenerate `lib/bindings.dart`:\n```sh\nflutter pub run ffigen\n```\n\nFinally, use the generated `GreetingBindings` class. An example wrapper [is available here](./lib/mylib.dart).\n\n#### Manual bindings\n\nLoad the library: \n```dart\nfinal DynamicLibrary nativeExampleLib = Platform.isAndroid\n    ? DynamicLibrary.open(\"libexample.so\")   // Load the dynamic library on Android\n    : DynamicLibrary.process();              // Load the static library on iOS\n```\n\nFind the symbols we want to use, with the appropriate Dart signatures:\n```dart\nfinal Pointer\u003cUtf8\u003e Function(Pointer\u003cUtf8\u003e) rustGreeting = nativeExampleLib\n    .lookup\u003cNativeFunction\u003cPointer\u003cUtf8\u003e Function(Pointer\u003cUtf8\u003e)\u003e\u003e(\"rust_greeting\")\n    .asFunction();\n\nfinal void Function(Pointer\u003cUtf8\u003e) freeGreeting = nativeExampleLib\n    .lookup\u003cNativeFunction\u003cVoid Function(Pointer\u003cUtf8\u003e)\u003e\u003e(\"rust_cstr_free\")\n    .asFunction();\n```\n\nCall them:\n```dart\n// Prepare the parameters\nfinal name = \"John Smith\";\nfinal Pointer\u003cUtf8\u003e namePtr = Utf8.toUtf8(name);\nprint(\"- Calling rust_greeting with argument:  $namePtr\");\n\n// Call rust_greeting\nfinal Pointer\u003cUtf8\u003e resultPtr = rustGreeting(namePtr);\nprint(\"- Result pointer:  $resultPtr\");\n\nfinal String greetingStr = Utf8.fromUtf8(resultPtr);\nprint(\"- Response string:  $greetingStr\");\n```\n\nWhen we are done using `greetingStr`, tell Rust to free it, since the Rust implementation kept it alive for us to use it.\n```dart\nfreeGreeting(resultPtr);\n```\n\n## More information\n- https://dart.dev/guides/libraries/c-interop\n- https://flutter.dev/docs/development/platform-integration/c-interop\n- https://github.com/dart-lang/samples/blob/master/ffi/structs/structs.dart\n- https://mozilla.github.io/firefox-browser-architecture/experiments/2017-09-06-rust-on-ios.html\n- https://mozilla.github.io/firefox-browser-architecture/experiments/2017-09-21-rust-on-android.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrickpop%2Fflutter-rust-ffi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrickpop%2Fflutter-rust-ffi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrickpop%2Fflutter-rust-ffi/lists"}