Integrating with Xcode

It is possible to generate Swift bindings at compile time for Xcode projects and incorporate them alongside hand-written Swift code to form a larger module. Broadly, you will need to:

  1. Add a build phase to compile the Rust crate into a static lib and link it into your framework.
  2. Add a build phase to run uniffi-bindgen and generate the Swift bindings.
  3. Include the generated bridging header into your overall bridging header.

There is also an example app in the UniFFI project repo that may be helpful.

Compiling the Rust crate.

Sorry, configuring Xcode to compile the Rust crate into a staticlib is beyond the scope of this document. However you do so, make sure you include the resulting libexample.a file in the "Link Binary with Libraries" build phase for your framework.

This repository contains an example iOS app (at ./examples/app/ios) which may be useful for reference. It contains an xc-universal-binary.sh shell script which can invoke cargo with the necessary settings to produce a static library of Rust code.

Generating the bindings

In the "Build Rules" section of your config, add a rule to process .udl files using uniffi-bindgen. We recommend having it generate the output files somewhere in your source tree, rather than in Xcode's default $DERIVED_FILE_DIR; this both helps with debugging the build output, and makes it easier to configure how the generated files are used.

  • Add a build rule processing files with names matching *.udl.
    • Use something like the following as the custom script:
      • $HOME/.cargo/bin/uniffi-bindgen generate $INPUT_FILE_PATH --language swift --out-dir $INPUT_FILE_DIR/Generated
    • Add both the .swift file and the generated bridging header as output files:
      • $(INPUT_FILE_DIR)/Generated/$(INPUT_FILE_BASE).swift
      • $(INPUT_FILE_DIR)/Generated/$(INPUT_FILE_BASE)FFI.h
  • Add your .udl file to the "Compile Sources" build phase for your framework, so that Xcode will process it using the new build rule and will include the resulting outputs in the build.

You do not need to add the generated Swift code to the list of "Compile Sources" and should not attempt to compile it explicitly; Xcode will figure out what it needs to do with this code based on it being generated from the Build Rule for your .udl file.

Including the bridging header

In the overall bridging header for your module, include the header file generated by UniFFI in the previous step:

#include "exampleFFI.h"

For this to work without complaint from Xcode, you also need to add the generated header file as a Public header in the "Headers" build phase of your project (which is why it's useful to generate this file somewhere in your source tree, rather than in a temporary build directory).