FFIGen: An Easy Way to Access iOS Libraries
Learn a new approach to system interoperability for easy access to swift classes.
FFIGen is a new approach to system interoperability introduced in Flutter 3.7.0 at the Flutter Forward event. FFIGen works on the principle of generating Dart binding that calls C modules which are complied from another language.
In the previous article, we saw the binding generation concept in Android using JNIGen and how to implement it. Follow the link below to access that article.
Today we will see how to implement FFIGen to generate Dart bindings for accessing Swift classes.
- Let’s say I want to implement a small demo of an audio player, and we have its implementation in a Swift class.
In the above code, we have one play function that will take the path for the audio file and initialize the AVAudioPlayer object. It does so with the URL we have passed, and then it starts playing the audio. We have another method for stopping the player.
We will use both of these methods in our Dart code. So, let’s get started!
1. Installation of tools
Use the below steps to install LLVM:
- Install Xcode.
- Install LLVM.
brew install llvm
Windows:
- Install Visual Studio with C++ development support.
- Install LLVM through this link https://releases.llvm.org/download.html
or
Run the following command:
winget install -e --id LLVM.LLVM
2. Add FFIGen to your pubspec.yaml file
- Before converting our Swift class to Dart, we need to create an Objective-C header file and Dynamic Library from our Swift file.
Run the below command in your path containing the sWift file:
- Place your generated .dylib file in the lib folder and the Objective-C header file in the appropriate folder, i.e., ‘ios_headers/’. We will use this header to generate Dart bindings.
Create a “ffigen.yaml” file in your source directory.
- As we saw in the case of JNIGen, we can specify a property in the .yaml binding file for the output directory and for the classes to be converted from an Android library. We have a similar property in FFIGen too. So let’s explore those properties and implement FFIGen in our project.
Now, there are a few configuration properties required for this file:
*
denotes requires:
- output*: Path for writing generate bindings
- headers*: Contains subsection which specifies the list of paths for objective-C header files and directives to include in code generation
The header contains the following subsection:
- entry-points*: List of paths to Objective-C header file, which will be scanned to look for classes to be converted.
- include-directives: Contains path for header file to be included in a generation. If not given, FFIGen will generate everything directly/transitively under the entry points.
2. objc-interface: List of classes for which bindings will be generated
It contains the following sub-sections
- include: Classes which are needed to be converted
- exclude: Classes to exclude from conversion
- module: Used to add module name prefix to the class name. This is useful when multiple module classes are going to be generated in a single file.
Now run the following command in the terminal to generate bindings:
dart run ffigen --config ffigen.yaml
iOS bindings will be generated in the “audio_player.dart” file as we have specified in our “ffigen.yaml” file.
Now we can use these bindings in our Dart code.
To use our generated classes, we first need to load Dynamic Library .dylib that we generated previously while converting the .swift file in the Objective-C header file.
To create the class object, we will use the new1() function and pass the dynamic library object in the argument.
There you go! Now you can access methods of Swift class easily and directly in your Dart code.
Note: Currently we are not running example as a flutter app because for iOS apps, we need to bundle .dylib within the app archive. You can use the ‘Embedded binaries’ property in Xcode for this purpose.
Also, the .dylib file you generate using the above process will be for macOS. To generate a Dynamic library for iOS, use the below commands.
For iOS devices:
xcrun --sdk iphoneos swiftc -c audioplayer.swift
-module-name audioplayer
-emit-objc-header-path audioplayer.h
-emit-library -o libaudioplayer.dylib
-target arm64-apple-ios14.0
For iOS simulator:
xcrun --sdk iphonesimulator swiftc -c audioplayer.swift
-module-name audioplayer
-emit-objc-header-path audioplayer.h
-emit-library -o libaudioplayer.dylib
-target arm64-apple-ios14.0-simulator
Wrapping up
I hope this clarifies your understanding of how FFIGen works and how to implement it in your project for accessing swift classes easily without hassle.
NOTE: Currently many features in this package are in the experimental phase and are prone to changes so stay tuned for the updates
Here’s the repo for the AudioPlayer example of FFIGen.
Stay tuned and follow Simform Engineering for important and exciting updates on Flutter tools and technologies.
Happy Coding :)