Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Leveraging Go's Power in your Flutter App - Jhi...

GDG Montreal
July 15, 2024
29

Leveraging Go's Power in your Flutter App - Jhin Lee

GDG Montreal

July 15, 2024
Tweet

Transcript

  1. Jhin Lee Full Stack Developer @Unity • GDE Flutter •

    GDG / Flutter Montreal Organizer • Scrum Master (PSM2) https://www.linkedin.com/in/leehack/
  2. Agenda 1 2 3 4 5 6 Introduction Motivation What

    is FFI? Compile Golang library Use Golang library in Flutter Conclusion and Q&A
  3. GoLang is a very powerful language that is easy to

    use. Golang is very useful in writing high-performance and low-latency cross-platform applications, but it needs improvement in GUI. Flutter is a compelling cross-platform UI framework. It allows you to write a beautiful application effortlessly. Mixing GoLang and Flutter is an excellent idea to write a high-performance and beautiful application. (A colleague was developing a Golang app and opted for a web-based GUI. I wanted show him the power of Flutter…) Why are we doing this? Motivation
  4. Why Golang? Cross-platform development Golang shines in cross-compilation. Code compiles

    seamlessly for different operating systems (Windows, Linux, macOS) and architectures (x86, ARM) without needing modifications. This saves development time and simplifies deployment across diverse environments. Fast compilation and execution Golang compiles directly to machine code, resulting in efficient, high-performance applications. But the real superpower is the speed of compilation itself. Changes are reflected in running applications almost instantly, making development cycles incredibly fast. Lightweight and highly scalable Golang's built-in concurrency features (goroutines and channels) allow you to manage many tasks simultaneously without sacrificing performance. This makes it ideal for building highly scalable applications that can handle heavy workloads efficiently.
  5. Why Flutter? Cross-platform development Write code once and deploy it

    on multiple platforms (Android, iOS, web, desktop) with a single codebase. This saves time and resources compared to building separate native apps for each platform. Fast development and hot reload Flutter offers features like hot reload that lets you see changes in your code reflected in the app almost instantly. This speeds up development significantly. Beautiful and performant apps Flutter uses its own rendering engine, resulting in smooth animations and a high-quality user experience. The compiled code ensures the app runs efficiently.
  6. It is a way to call functions written in other

    languages from Dart. FFI helps use libraries written in other languages in a Flutter application. Flutter supports FFI for Android, iOS, Linux, macOS, and Windows. We use dart:ffi package to call functions written in C language from Dart. It means it allows us to call code written in languages like C++, Rust, or Go as long as it provides a foreign function interface (FFI) using C conventions. Foreign Function Interface What is FFI?
  7. We can create an FFI plugin example using this command:

    flutter create --platforms=android,ios,macos,windows,linux --template=plugin_ffi native_add The native_add project will support Android, iOS, Linux, macOS, and Windows. It will have a lib folder containing the Dart code, a src folder containing C codes, and an example folder containing a Flutter application to test the plugin. Create FFI plugin How to use the FFI in Flutter?
  8. 1. Create go.mod file: It defines the module name and

    golang version. $go mod init go_code 2. Write go codes in the sum.go file. // sum.go file package main import "C" //export sum func sum(a C.int, b C.int) C.int { return a + b } func main() {} How to use CGO Write the Golang codes • We use cgo shere to make the go package communicate with C. • // export <function_name> comment is for exposing the function to C. • To expose it to C, we have to use the types of C, so we use C.int instead of Int.
  9. We need to cross-compile it to make it run on

    Android devices. Modern Android devices mostly use arm64 or x86_64 architecture. We'll cross-compile for both architectures. Build for Android Compile the GoLang library export ANDROID_OUT=../android/src/main/jniLibs export ANDROID_SDK=$HOME/Library/Android/sdk export NDK_BIN=$ANDROID_SDK/ndk/23.1.7779620/toolchains/llvm/prebuilt/darwin-x86_64/bin # Compile for x86_64 architecture and place the binary file in the android/src/main/jniLibs/x86_64 folder CGO_ENABLED=1 \ GOOS=android \ GOARCH=amd64 \ CC=$NDK_BIN/x86_64-linux-android21-clang \ go build -buildmode=c-shared -o $ANDROID_OUT/x86_64/libsum.so . # Compile for arm64 architecture and place the binary file in the android/src/main/jniLibs/arm64-v8a folder CGO_ENABLED=1 \ GOOS=android \ GOARCH=arm64 \ CC=$NDK_BIN/aarch64-linux-android21-clang \ go build -buildmode=c-shared -o $ANDROID_OUT/arm64-v8a/libsum.so . Now we can use the libsum library in the Dart code using FFI. DynamicLibrary.open('libsum.so');
  10. The basic concept is the same as the Android build,

    but we need some extra steps. • We must compile it as a static library since iOS only supports it. • We need to cross-compile three libraries. (arm64 and amd64 for simulator, and arm64 for iPhone) • We need to combine the simulator libraries using lipo. • We need to package it as a xframework. Build for iOS Compile the GoLang library For the details: https://dev.to/leehack/how-to-use-golang-in-flutter-application-golang-ffi-1950
  11. The ffigen is the tool to generate the Dart code

    binding to the C library. We will create a ffigen.yaml file to configure the ffigen. Create a binding in Dart using ffigen How to use it in the Flutter App # Run with `flutter pub run ffigen --config ffigen.yaml`. name: NativeLibrary description: Bindings to `src/sum.h`. output: 'lib/generated_bindings.dart' headers: entry-points: - 'src/libsum.h' preamble: | // ignore_for_file: always_specify_types // ignore_for_file: camel_case_types // ignore_for_file: non_constant_identifier_names // ignore_for_file: unused_field // ignore_for_file: unused_element comments: style: any length: full After we run "flutter pub run ffigen --config ffigen.yaml", We can see the generated_bindings.dart generated under the lib folder.
  12. Now, we can load the library from the Dart and

    call the dart functions bound to the C functions in the generated_bindings.dart. Use the library in Dart How to use it in the Flutter App // lib/native_add.dart import 'dart:ffi'; import 'dart:io'; import 'generated_bindings.dart'; int sum(int a, int b) => _bindings.sum(a, b); const String _libName = 'native_add'; /// The dynamic library in which the symbols for [NativeAddBindings] can be found. final DynamicLibrary _dylib = () { if (Platform.isAndroid || Platform.isLinux) { return DynamicLibrary.open('libsum.so'); } throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}'); }(); /// The bindings to the native functions in [_dylib]. final NativeLibrary _bindings = NativeLibrary(_dylib); • We can call this function anywhere in your Dart or Flutter application.
  13. What we've learned: • We can load any native library

    that has the C interface. • ffigen automatically generates the binding based on the header file (.h) • With GoLang's cross-compiling capability, we can easily create native cross-platform libraries. Next Steps: • Make the plugin work for iPhone / MacOS / Windows / Linux. ◦ https://dev.to/leehack/how-to-use-golang-in-flutter-application-golang-ffi-1950 covers iPhone / Android build. ◦ https://github.com/leehack/flutter_golang_ffi_example covers iPhone / Android / MacOS. • Make the plugin work for Web (hint: WebAssembly) • More advanced use-cases like passing reference(pointers). Conclusion
  14. • The article I wrote: https://dev.to/leehack/how-to-use-golang-in-flutter-application-golang-ffi-1950 • The example I

    wrote: https://github.com/leehack/flutter_golang_ffi_example • Isar database (written in rust): https://github.com/isar/isar • Official document for Dart FFI: https://dart.dev/interop/c-interop • Official document for Flutter FFI: https://docs.flutter.dev/platform-integration/android/c-interop References