Using FFIGen in Dart 2.18
Tags: flutter, productivity, dart, programming
Published: 2022-12-22 14:49:40

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

<!-- wp:paragraph -->
<p>We will cover briefly:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><!-- wp:list-item -->
<li>What’s FFIGen</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>What’s new in FFIGen</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Dart CLI App and integrate obj-c-based libraries</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Testing FFIGen&nbsp;</li>
<!-- /wp:list-item --></ol>
<!-- /wp:list -->

{% youtube VIbBuPl5oxA %}

<!-- wp:heading {"level":3} -->
<h3>Wait, what’s&nbsp;FFIGen?</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Before explaining the answer to this question, the reader needs to know about <code>FFI</code> (Foreign Function Interface)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>What’s FFI</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>FFI enables programs written in one language to call libraries written in other languages. The term <code>FFI</code> comes from <a href="http://wiki.c2.com/?CommonLisp" rel="noreferrer noopener" target="_blank">CommonLisp</a>, however, it’s applicable to any language. Some languages such as Java, use FFI in their ecosystem and call it <a href="http://wiki.c2.com/?JavaNativeInterface" rel="noreferrer noopener" target="_blank">JavaNativeInterface</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If we refer to the low-level language as the “<strong>host</strong>” language and the high-level language as the “<strong>guest</strong>” language, below are the ways to communicate between them.</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li><em>The host is expected to bridge the gap with the guest. We write host-language functions specifically to be called by the guest. An API is offered for the host language to communicate with guests.</em></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><em>The gap is bridged by some kind of tool that does not belong strictly to either the host or guest languages.</em></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><em>The guest is also expected to bridge the gap with the host. Guest language can call any host-language function, but it needs to support many low-level features, in order to communicate with the host language effectively.</em></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>According to Wikipedia, these are the things to consider for FFI:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li>If one language supports garbage collection (GC) and the other does not; care must be taken that the non-GC language code does nothing to cause GC in the other to fail.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Complicated or non-trivial objects or datatypes may be difficult to map from one environment to another.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>One or both languages may be running on a <a href="https://en.wikipedia.org/wiki/Virtual_machine" rel="noreferrer noopener" target="_blank">virtual machine</a> (VM); moreover, if both are, these will probably be different VMs.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Fortunately, we are able to use <strong>FFI </strong>in Dart through the <code>dart:ffi</code>library. With Dart v2.12 onwards, <a href="https://medium.com/dartlang/announcing-dart-2-12-499a6e689c87" rel="noreferrer noopener" target="_blank"><strong>Dart FFI</strong></a> is available on the stable channel. Dart FFI allows you to use the existing code in C libraries. By using FFI we can avail the benefits of both portability and integration of highly tuned C code for performance-intensive tasks. We are not limited to <code>C</code>&nbsp;, in fact, we can write the code in any language that is compiled to the C library, for instance <code>Go, Rust</code>&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Another use case for using Dart FFI can be there are times when the Flutter app needs to have greater control over memory management and garbage collection, for instance, an app using tensor flow.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Dart FFI can be used to read, write, allocate and deallocate the native memory. There are some packages that already used this feature:</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p><code><a href="https://pub.dev/packages/file_picker" rel="noreferrer noopener" target="_blank">file_picker</a></code>, <code><a href="https://pub.dev/packages/printing" rel="noreferrer noopener" target="_blank">printing</a></code>, <code><a href="https://pub.dev/packages/win32" rel="noreferrer noopener" target="_blank">win32</a></code>, <code><a href="https://pub.dev/packages/objectbox" rel="noreferrer noopener" target="_blank">objectbox</a></code>, <code><a href="https://pub.dev/packages/realm" rel="noreferrer noopener" target="_blank">realm</a></code>, <code><a href="https://pub.dev/packages/isar" rel="noreferrer noopener" target="_blank">isar</a></code>, <code><a href="https://pub.dev/packages/tflite_flutter" rel="noreferrer noopener" target="_blank">tflite_flutter</a></code>, and <code><a href="https://pub.dev/packages/dbus" rel="noreferrer noopener" target="_blank">dbus</a></code>.</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":4} -->
<h4>Ways of using Dart&nbsp;FFI</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>There are times when you want to create your own fresh library, but the maximum number of times, the library would already exist (created by some other team) and you simply want to use it. In either of the cases, we have the following choices</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li>Manually creating the FFI bindings</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Automatically generating the FFI bindings</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>If you like automation, you probably chose the second option, and as a result, we have <code><a href="https://pub.dev/packages/ffigen" rel="noreferrer noopener" target="_blank">package:ffigen</a></code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The idea behind the package <code>ffigen</code> is: For large APIs, it can be very time-consuming to write the Dart bindings which allow the integration with the C code. Hence, the Dart team came up with a binding generator (<strong>ffigen</strong>) that automatically creates the FFI wrappers out of the C header files.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Under the hood, this package uses <a href="https://medium.datadriveninvestor.com/whats-llvm-4c0c3ed43a72" target="_blank" rel="noreferrer noopener">LLVM</a> and <code>LibClang</code> to parse C header files. For installing LLVM inside <code>macOS</code></p>
<!-- /wp:paragraph -->

```yaml
brew install llvm
```

<!-- wp:paragraph -->
<p>There are multiple types provided by <code>dart:ffi</code> for representing the types in C. However, they broadly are classified in</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li>Instantiable Native Types</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Purely marker Native Types</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Instantiable Native Types: They or their subtypes can be instantiated in the Dart Code. For instance, <code>Array</code> <code>Pointer</code> <code>Struct</code> <code>Union</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Purely marker Native Types: They are platform agnostic and cannot be instantiated in the Dart Code. For instance, <code>Bool</code> <code>Double</code> <code>Int64</code> <code>Int32</code> etc</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>There are also <a href="https://api.dart.dev/stable/dart-ffi/Abi-class.html" rel="noreferrer noopener" target="_blank">ABI</a> marker types that extend <code>AbiSpecificInteger</code> For instance <code>Size</code> <code>Short</code> etc</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>Until now, we have covered what’s <strong>FFI</strong> and what’s <strong>ffigen</strong>, let’s explore what’s new inside <em>ffigen from Dart 2.18</em></p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":3} -->
<h3>What’s new in&nbsp;FFIGen</h3>
<!-- /wp:heading -->

<!-- wp:image {"align":"center"} -->
<figure class="wp-block-image aligncenter"><img src="https://cdn-images-1.medium.com/max/800/0*__o2z4PlwKCYgCNo" alt="Dart 2.18"/><figcaption class="wp-element-caption">Dart 2.18</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>The Dart team wants Dart to support interoperability with all the primary languages on the platforms where Dart runs.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>As of <a href="https://dart.dev/guides/language/evolution#dart-218" rel="noreferrer noopener" target="_blank"><em>Dart 2.18</em></a><em> </em>the <code>Dart</code> code can now call the Objective-C and Swift code since these are used for writing APIs for macOS and iOS. This interop mechanism is supported across all types of apps (for instance, CLI app to backend app to Flutter code)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This feature is not limited to command-line apps. Even the Dart mobile, and server apps running on the <a href="https://dart.dev/overview#platform" rel="noreferrer noopener" target="_blank">Dart Native platform</a>, on macOS or iOS, can use <code>dart:ffi</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This unlocks the possibilities since before 2.18 it was only possible to call the <code>C/C++</code>based libraries.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>According to the official blog,</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>This new mechanism utilizes the fact that Objective-C and Swift code can be exposed as C code based on API bindings. The Dart API wrapper generation tool, <code><a href="https://pub.dev/packages/ffigen" rel="noreferrer noopener" target="_blank">ffigen</a></code>, can create these bindings from API headers</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>This support for Objective-C and Swift is <strong>marked as experimental starting from </strong><code><strong>Dart 2.18</strong></code> In case someone experiences any problems, they can comment on the <a href="https://github.com/dart-lang/sdk/issues/49673" rel="noreferrer noopener" target="_blank">feedback issue</a> on GitHub.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Dart CLI App with Objective-C-based libraries</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In this section, we create a Dart-based command line application that demonstrates how to call an Objective-C-based library using the new functionalities from <code>ffigen</code>&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will choose any Objective-C library present inside the macOS, and integrate it inside the Dart CLI App.</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>One such library is <code><a href="https://developer.apple.com/documentation/foundation/nsurlcache" rel="noreferrer noopener" target="_blank">NSURLCache</a></code></p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>macOS has an API for querying URL cache information exposed by the <code><a href="https://developer.apple.com/documentation/foundation/nsurlcache" rel="noreferrer noopener" target="_blank">NSURLCache</a></code> class.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The <code>NSURLCache</code> implements the caching of responses to URL load requests, by mapping <code><a href="https://developer.apple.com/documentation/foundation/nsurlrequest" rel="noreferrer noopener" target="_blank">NSURLRequest</a></code> objects to <code><a href="https://developer.apple.com/documentation/foundation/nscachedurlresponse" rel="noreferrer noopener" target="_blank">NSCachedURLResponse</a></code> objects. It provides a composite in-memory and on-disk cache, and lets you manipulate the sizes of both the in-memory and on-disk portions.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will be integrating the <code>NSURLCache</code> inside <code>Dart</code> and call some of its functions:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li><code>currentDiskUsage</code>&nbsp;: The current size of the on-disk cache, in bytes.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>diskCapacity</code>&nbsp;: The capacity of the on-disk cache, in bytes.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>memoryCapacity</code>&nbsp;: The capacity of the in-memory cache, in bytes.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p><strong>Create Dart CLI App</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We start by creating the Dart CLI App using the below command. Also, upgrade to the latest Dart version <code>2.18</code></p>
<!-- /wp:paragraph -->

```dart
dart create ffi_2_18
## ffi_2_18 is the name of the project which will be created
```

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>Note: There are various templates available for Dart, see below. By default, it selects console application.</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:image {"align":"center"} -->
<figure class="wp-block-image aligncenter"><img src="https://cdn-images-1.medium.com/max/800/1*-pkYl31cp_Sb8xHzLUN5wA.png" alt="Dart Templates"/><figcaption class="wp-element-caption">Dart Templates</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>This gives us a basic template with all the necessary files, for instance, <code>pubspec</code> or <code>linter</code> Open the <code>pubspec</code> file to check the dependencies which come bundled with this template.</p>
<!-- /wp:paragraph -->

```yaml
dev_dependencies:
  lints: ^2.0.0
  test: ^1.16.0
```

<!-- wp:paragraph -->
<p>Edit your <code>pubspec</code> file to add the <code><a href="https://pub.dev/packages/ffigen" target="_blank" rel="noreferrer noopener">ffigen</a></code> dev dependency. Next, specify the configuration under this dependency. <a href="https://pub.dev/packages/ffigen#configurations" target="_blank" rel="noreferrer noopener">Configurations</a> can be provided in 2 ways-</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><!-- wp:list-item -->
<li>In the project’s <code>pubspec.yaml</code> file under the key <code>ffigen</code>.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Via a custom YAML file, then specify this file while running — <code>dart run ffigen --config config.yaml</code></li>
<!-- /wp:list-item --></ol>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>We will see the <strong>option 2 first.</strong> Separate config files for the libraries</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>Create a file called <code>url_cache_config.yaml</code> and put the below contents inside it.&nbsp;</p>
<!-- /wp:paragraph -->

```yaml
name: URLCacheLibrary
language: objc
output: "url_cache_bindings.dart"
exclude-all-by-default: true
objc-interfaces:
  include:
    - "NSURLCache"
headers:
  entry-points:
    - "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURLCache.h"
```

<!-- wp:paragraph -->
<p>Let’s see the above configuration options-</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li><code>name</code> The name for the class which will be generated, after we run the <code>ffigen</code>, this class will be called <code>URLCacheLibrary</code>&nbsp;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>language</code> Must be one of `c`, or ‘objc’. Defaults to ‘c’. Since the library we select is written in Objective-C, we specify <code>objc</code>&nbsp;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>output</code> Output path of the generated bindings. This file will have all the FFI bindings which take care of the functions inside <code>Obj-C</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>headers</code> This includes the path to the <code>header files</code> It includes everything from the location as specified under the <code>entry-points</code>In our case, the header files are present inside the <code>Foundation.framework</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>exclude-all-by-default</code> When a declaration filter (eg functions or structs:) is empty, it defaults to including everything. If this flag is enabled, the default behavior is to exclude everything instead.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p><strong>Objective-C config options</strong></p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li><code>objc-interfaces</code> This filters for the interface declarations. In our case, we specify the <code>NSURLCache</code> interface</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

```yaml
objc-interfaces:
  include:
    # Includes a specific interface.
    - 'NSURLCache'
    # Includes all interfaces starting with "NS".
    - 'NS.*'
  exclude:
    # Override the above NS.* inclusion, to exclude NSURL.
    - 'NSURL'
  rename:
    # Removes '_' prefix from interface names.
    '_(.*)': '$1'
```

<!-- wp:paragraph -->
<p><strong>Generate Bindings</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To generate the bindings, run the following:</p>
<!-- /wp:paragraph -->

```yaml
dart run ffigen --config url_cache_config.yaml
## url_cache_config is the file which we created above
```

<!-- wp:paragraph -->
<p>This command creates a new file (<strong>url_cache_bindings.dart</strong>) as specified inside the <code>output</code> parameter of the <code>url_cache_config.yaml</code>which contains a bunch of generated API bindings. Using this binding file, we can write our Dart <code>main</code> method.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Integrate into Dart</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We generated the bindings using the <code>ffigen</code> in the above step. Let’s see how to integrate it inside the <code>Dart</code> We create a new dart file called <code>url_cache.dart</code>&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Inside this file, we would be loading and interacting with the generated library.</p>
<!-- /wp:paragraph -->

```dart
void main() {
  const dylibPath = '/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation';
final lib = URLCacheLibrary(DynamicLibrary.open(dylibPath));
final urlCache = NSURLCache.getSharedURLCache(lib);
  if (urlCache != null) {
    print('currentDiskUsage: ${urlCache.currentDiskUsage}');
    print('currentMemoryUsage: ${urlCache.currentMemoryUsage}');
    print('diskCapacity: ${urlCache.diskCapacity}');
    print('memoryCapacity: ${urlCache.memoryCapacity}');
  }
}
```

<!-- wp:paragraph -->
<p>We mention the path of the library in the first step. Since, the library we are using is an internal library, the <code>dylib</code> points to the macOS’s framework <code>dylib</code> We can consider this library to be dynamically linked.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<figure class="wp-block-image aligncenter"><img src="https://cdn-images-1.medium.com/max/800/0*rr0NgVo2Gjmx5AC2.png" alt="Library linking"/><figcaption class="wp-element-caption">Library linking</figcaption></figure>
<!-- /wp:image -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>Note: We can also use our own library or a static library (linked inside our app)</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p><strong>Dynamic Linking</strong>: In this type, the external libraries are placed inside the final executable, however, the actual linking happens at the run time. In dynamic linking, only one copy of the shared library is kept inside the memory which <strong>reduces the program size, memory, and disk space</strong>. Since the libraries are shared, <strong>dynamic linking programs are slower</strong> in comparison to static linking programs.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>A dynamically linked library is distributed in a separate file or folder within the app and loaded on demand. A dynamically linked library can be loaded into Dart via <code>DynamicLibrary.open</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Static Linking</strong>: In this type, the modules are copied inside the program before creating the final executable. Since these programs include libraries, they are <strong>large in size</strong>. However, because of the libraries already compiled, these programs are <strong>faster than dynamically linked programs</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>A statically linked library is embedded into the app’s executable image and is loaded when the app starts. Symbols from a statically linked library can be loaded using <code>DynamicLibrary.executable</code> or <code>DynamicLibrary.process</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Next</strong>, we construct the <code>URLCacheLibrary</code> by using the constructor which needs the <code>dylib</code> path. For this, we call the <code>DynamicLibrary.open</code> This loads the library file and provides the access to its symbols.</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>Note: This process loads the library into the DartVM only once, regardless of the function calls.</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>Once the library gets initialized, we can call the different methods present inside it (which were generated).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We are looking for a <code>NSURLCache</code> class. This class implements the caching of responses to URL load requests, by mapping <code><a href="https://developer.apple.com/documentation/foundation/nsurlrequest" rel="noreferrer noopener" target="_blank">NSURLRequest</a></code> objects to <code><a href="https://developer.apple.com/documentation/foundation/nscachedurlresponse" rel="noreferrer noopener" target="_blank">NSCachedURLResponse</a></code> objects. For getting an instance of this class, we call <code>sharedURLCache</code>&nbsp;</p>
<!-- /wp:paragraph -->

```dart
final urlCache = NSURLCache.getSharedURLCache(lib)
```

<!-- wp:paragraph -->
<p>Since we have the instance of <code>URLCache</code> we can access the different methods <code>currentDiskUsage</code> <code>currentMemoryUsage</code> <code>diskCapacity</code> <code>memoryCapacity</code>. Let’s run the dart code using</p>
<!-- /wp:paragraph -->

```dart
dart run bin/url_cache.dart
```

<!-- wp:paragraph -->
<p>The result is as</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<figure class="wp-block-image aligncenter"><img src="https://cdn-images-1.medium.com/max/800/1*0IRU5Jp6JwNt967IxvOD5w.png" alt="NSURLCache data"/><figcaption class="wp-element-caption">NSURLCache data</figcaption></figure>
<!-- /wp:image -->

<!-- wp:heading {"level":4} -->
<h4><strong>Using configuration inside&nbsp;pubspec</strong></h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In the above section, we saw how to use the configuration specified inside a separate config file, let’s see how to use the configuration inside the <code>pubspec</code>&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will choose another Objective-C library present inside the macOS.</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>One such library is <code><a href="https://developer.apple.com/documentation/foundation/nstimezone?language=objc]" rel="noreferrer noopener" target="_blank"><em>NSTimeZone</em></a></code><em>&nbsp;</em></p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>This API is used for querying the time zones along with the standard time policies of a region. These time zones can have identifiers such as <code>America/Los_Angeles</code> and can also be identified by abbreviations such as <code>PST</code> for Pacific Standard Time.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The header for this library is present inside the <code>NSTimeZone.h</code>which can be found inside the Apple Foundation library. Let’s include the configuration inside the pubspec:</p>
<!-- /wp:paragraph -->

```yaml
dev_dependencies:
ffigen:
  name: TimeZoneLibrary
  language: objc
  output: "timezone_bindings.dart"
  exclude-all-by-default: true
  objc-interfaces:
    include:
      - "NSTimeZone"
  headers:
    entry-points:
      - "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSTimeZone.h"
```

<!-- wp:paragraph -->
<p>In the above configuration, we specify the&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li><code>name</code> This class will be called <code>TimeZoneLibrary</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>language</code> The library we select is written in Objective-C, we specify <code>objc</code></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>headers</code> The path to the <code>header files</code> which is present inside the <code>Foundation.framework</code></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>For generating the bindings we run the following</p>
<!-- /wp:paragraph -->

```dart
dart run ffigen
```

<!-- wp:paragraph -->
<p>This command creates a new file (<strong>timezone_bindings.dart</strong>) as specified inside the <strong>output </strong>parameter that contains a bunch of generated API bindings. Using this binding file, we can write our Dart <code>main</code> method.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We create a new dart file called <code>timezones.dart</code> Inside this file, we load and interact with the generated library.</p>
<!-- /wp:paragraph -->

```dart
const dylibPath='/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation';
final lib = TimeZoneLibrary(DynamicLibrary.open(dylibPath));
final timeZone = NSTimeZone.getLocalTimeZone(lib);
if (timeZone != null) {
  print('Timezone name: ${timeZone.name}');
  print('Offset: ${timeZone.secondsFromGMT / 60 / 60} hours');
}
```

<!-- wp:paragraph -->
<p><strong>W</strong>e construct the <code>TimeZoneLibrary</code> by using the constructor which needs the <code>dylib</code> path. Once the library gets initialized, we call the different methods present inside it.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will be integrating the <code>NSTimeZone</code> inside <code>Dart</code> and call some of its functions:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li><code>name</code>&nbsp;: The geopolitical region ID that identifies the receiver.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><code>secondsFromGMT</code>&nbsp;: The current difference in seconds between the receiver and Greenwich Mean Time.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>For getting an instance of this class, we call <code>localTimeZone</code></p>
<!-- /wp:paragraph -->

```dart
final timeZone = NSTimeZone.getLocalTimeZone(lib)
```

<!-- wp:paragraph -->
<p>Since we have the instance of <code>NSTimeZone</code> we can access the different methods <code>name</code> <code>secondsFromGMT</code>. Let’s run the dart code using</p>
<!-- /wp:paragraph -->

```dart
dart run bin/timezones.dart
```

<!-- wp:paragraph -->
<p>The result is as</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<figure class="wp-block-image aligncenter"><img src="https://cdn-images-1.medium.com/max/800/1*N5OZQ5ULW7wt3ThZb3vpiw.png" alt="NSTimeZone data"/><figcaption class="wp-element-caption">NSTimeZone data</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p><strong>Garbage Collection</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Objective-C uses reference counting for memory management, but on the Dart side, memory management is handled automatically. The Dart wrapper object retains a reference to the Objective-C object, and when the Dart object is garbage collected, the generated code automatically releases that reference using a <code><a href="https://api.dart.dev/dart-ffi/NativeFinalizer-class.html" rel="noreferrer noopener" target="_blank">NativeFinalizer</a></code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Limitations of Objective-C Interop</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The issues with the multithreading currently are a limitation to Dart’s experimental support for <code>Objective-C</code> interop. However, these limitations are not intentional, but due to the relationship between the Dart isolates and OS threads, and also how Apple handles the multithreading.</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li>While <code>ffigen</code> supports converting Dart functions to Objective-C blocks, but most Apple APIs don’t guarantee on which thread a callback will run.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Dart isolates are not the same as threads. Isolates run on threads but aren’t guaranteed to run on any particular thread. The VM can change which thread an isolate is running on without warning.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Apple APIs are not <a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html" rel="noreferrer noopener" target="_blank">thread-safe</a>.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Since the VM can change the thread in which an isolate can run, this means a callback created in one isolate might be invoked on a different or no isolate. However, there are some tweaks around this, as implemented in the <code><a href="https://github.com/dart-lang/http/blob/master/pkgs/cupertino_http/src/CUPHTTPClientDelegate.m" rel="noreferrer noopener" target="_blank">cupertino:http</a></code>&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Testing FFIGen</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Till now, we saw how to generate the bindings, and consume them from Dart CLI. In this section, we will see how to test the generated bindings.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We install the dependencies <code><a href="https://pub.dev/packages/yaml" rel="noreferrer noopener" target="_blank">yaml</a></code> and <code><a href="https://pub.dev/packages/logging" rel="noreferrer noopener" target="_blank">logging</a></code> and create a file called <code>ffi_2_18_test</code>&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p><em>Note: The tests should follow </em><code><em>&lt;name&gt;_test.dart</em></code><em> pattern</em></p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>The <code>yaml</code> dependency helps in the parsing of a <code>YAML</code> file. Whereas <code>logging</code> provides us with the APIs useful for logging (based on the configuration as specified).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Setup Logging</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We configure the logging level and add a handler for the log messages. The level is set to <code>Level.SEVERE</code> and next, we listen on the <code>onRecord</code> stream for <code>LogRecord</code> events.</p>
<!-- /wp:paragraph -->

```dart
void logWarnings([Level level = Level.WARNING]) {
  Logger.root.level = level;
  Logger.root.onRecord.listen((record) {
    print('${record.level.name.padRight(8)}: ${record.message}');
  });
}
```

<!-- wp:paragraph -->
<p>This function <code>logWarnings</code> is called inside the <code>setUpAll</code> The function registered under <code>setUpAll</code> will be run once before all the tests.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Test for NSURLCache</strong></p>
<!-- /wp:paragraph -->

```dart
test('url_cache', () {
  final pubspecFile = File('url_cache_config.yaml');
  final pubspecYaml = loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
  final config = Config.fromYaml(pubspecYaml);
  final output = parse(config).generate();
  expect(output, contains('class URLCacheLibrary{'));
  expect(output, contains('static NSURLCache?getSharedURLCache('));
 });
}
```

<!-- wp:paragraph -->
<p>We begin writing a test using the <code>test</code> method. The first thing we do is create the <code>url_cache_config.yaml</code> using a <a href="https://api.flutter.dev/flutter/package-file_file/File-class.html" rel="noreferrer noopener" target="_blank">file</a> object.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Next, we use the <code><a href="https://pub.dev/documentation/yaml/latest/yaml/loadYaml.html" rel="noreferrer noopener" target="_blank">loadYaml</a></code> the function which loads a single document from the YAML string. Since this method expects the parameter to be a string, we use the <code>readAsStringSync</code> to convert the file contents into string synchronously.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The return value is mostly normal Dart objects. Since we are using the <code>YAML</code>file, we specify the result as <code><a href="https://pub.dev/documentation/yaml/latest/yaml/YamlMap-class.html" rel="noreferrer noopener" target="_blank">YamlMap</a></code>YAML mappings support some key types that the default Dart map implementation doesn’t have.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Next, we use the <code><a href="https://pub.dev/documentation/ffigen/latest/ffigen/Config-class.html" rel="noreferrer noopener" target="_blank">Config</a></code> from the <code>ffigen</code> to create the configuration required for testing from the above <code>yaml</code> map. Finally, we use the <code><a href="https://pub.dev/documentation/ffigen/latest/ffigen/parse.html" rel="noreferrer noopener" target="_blank">parse</a></code> to generate the bindings.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The output from the above step is compared against the strings, for instance</p>
<!-- /wp:paragraph -->

```dart
expect(output, contains('class URLCacheLibrary{'));
expect(output, contains('static NSURLCache? getSharedURLCache('));
```

<!-- wp:paragraph -->
<p>This is because once we run the test using</p>
<!-- /wp:paragraph -->

```dart
dart test test/ffi_2_18_test.dart
```

<!-- wp:paragraph -->
<p>It generates the config file during the runtime and this gets compared with the strings above.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<figure class="wp-block-image aligncenter"><img src="https://cdn-images-1.medium.com/max/800/1*jE85taC0nAduR40g7SAcRg.png" alt="Test passed using FFIGen"/><figcaption class="wp-element-caption">Test passed using&nbsp;FFIGen</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p><strong>Test for NSTimeZone&nbsp;</strong></p>
<!-- /wp:paragraph -->

```dart
test('timezones', () {
  final pubspecFile = File('pubspec.yaml');
  final pubspecYaml = loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
  final config = Config.fromYaml(pubspecYaml['ffigen'] as YamlMap);
  final output = parse(config).generate();
expect(output, contains('class TimeZoneLibrary{'));
  expect(output, contains('class NSString extends _ObjCWrapper {'));
  expect(output, contains('static NSTimeZone? getLocalTimeZone('));
 );
}
```

<!-- wp:paragraph -->
<p>We create a <a href="https://api.flutter.dev/flutter/package-file_file/File-class.html" rel="noreferrer noopener" target="_blank">file</a> object using the <code>pubspec.yaml</code> file. Next, we use the <code><a href="https://pub.dev/documentation/yaml/latest/yaml/loadYaml.html" rel="noreferrer noopener" target="_blank">loadYaml</a></code> which loads the file from the YAML string.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Next, we use the <code><a href="https://pub.dev/documentation/ffigen/latest/ffigen/Config-class.html" rel="noreferrer noopener" target="_blank">Config</a></code> from the <code>ffigen</code> to create the configuration required for testing from the above <code>yaml</code> map. Since the pubspec file has the property <code>ffigen</code> defined inside it, we straight away refer to that and specify the output type to be <code>YamlMap</code></p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>Note: For the NSTimeZone, we specified the ffigen configuration inside the pubspec.yaml</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>Finally, we use the <code><a href="https://pub.dev/documentation/ffigen/latest/ffigen/parse.html" rel="noreferrer noopener" target="_blank">parse</a></code> to generate the bindings. The output from this step is compared against the strings, for instance</p>
<!-- /wp:paragraph -->

```dart
expect(output, contains('class TimeZoneLibrary{'));
expect(output, contains('static NSTimeZone? getLocalTimeZone('));
```

<!-- wp:paragraph -->
<p>This is because once we run the test using</p>
<!-- /wp:paragraph -->

```dart
dart test test/ffi_2_18_test.dart
```
{% youtube VIbBuPl5oxA %}

<!-- wp:paragraph -->
<p>It generates the config file during the runtime and this gets compared with the strings inside the test.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<figure class="wp-block-image aligncenter"><img src="https://cdn-images-1.medium.com/max/800/1*BhhVE230XuwSS9jKtS381w.png" alt="Test passed using FFIGen"/><figcaption class="wp-element-caption">Test passed using&nbsp;FFIGen</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p><a rel="noreferrer noopener" href="https://github.com/AseemWangoo/flutter_programs/tree/master/ffi_2_18" target="_blank"><em>Source code</em></a>

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>