How to create a Swift framework that is compatible with Xamarin iOS

Hi amigos… 🙂 Welcome back with a new blog post. With this post, what I’m trying to achieve is, reducing the gap between native application development and hybrid application development. Xamarin, is doing a pretty good job by creating an interface to use the native Swift frameworks. But how about a third party framework that you or your company has build for your own. How can we use that same Swift framework in Xamarin environment? That’s what you are going to learn today.


Without going around the bush let’s start the development. So, the very first thing that you need to understand is, languages, syntax and the way of doing things will change time to time. Therefore first I will provide my working environment details

  • Xcode version – 10.2
  • Swift version – 4.2.1
  • Deployment target – 10.0

First, you need to create a new Xcode project.

Creating a new Xcode project
Creating a new Xcode project

This time you are going to create a Cocoa Touch Framework under iOS category.

Selecting Cocoa Touch Framework option
Selecting Cocoa Touch Framework option

Then fill the basic details in the next pop up window and make sure to select Swift language, instead of Objective C.

Fill the project details
Fill the project details

Once the project loaded, next thing we need to do is, creating a new file inside that project like below.

Creating a new file
Creating a new file

That file content should be a Cocoa Touch Class.

Selecting the Cocoa Touch Class
Selecting the Cocoa Touch Class

In the next pop up window, you can give a name to that class, but you must make sure the class should be a subclass of NSObject. That’s one of the important thing you have to remember if you need your class to be visible inside a Xamarin project.

Providing a class name and selecting a parent class
Providing a class name and selecting a parent class

For the simplicity, I will make sure that our Swift framework does only one functionality, which is adding two numbers that passes to the function in the framework. That makes our class simple as below

import UIKit

@objc(AroshaFramework)
open class AroshaFramework: NSObject {

    @objc open func addTwoNumbers(numberOne: Int, numberTwo: Int) -> Int {
        return numberOne + numberTwo
    }
}

Make sure you have added @objc annotation and open keyword for both class and the function in order to make visible those inside the Xamarin project. When I declare the @objc annotation to the class, I have added class name inside the parenthesis. The reason for that is, if you have not done that the build tools will create a random name when it creates ApiDefinitions file, which you will be learn later in this post

That’s all about coding and our next mission is to create a new target.

Creating a new Target
Creating a new Target

That Target should be an Aggregate target which comes under Cross-platform.

Selecting an Aggregate target
Selecting an Aggregate target

What I am going to do is creating a universal framework by including most commonly used iOS architectures without exiting the Xcode. In the next pop up window, provide a Product Name as below.

Providing a product name
Providing a product name

Under the newly created target, we need to run some commands, which we normally do inside a Run Script.

Adding a Run Script Phase
Adding a Run Script Phase

What goes inside the Run Script is shown below with the description as a comment of each line.

#!/bin/sh

UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"

# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"

# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi

# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"

# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"

# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"

Don’t just copy and paste as it is. Just try to understand what has been written and why. In that script there are some build settings parameters have included. And we have used xcodebuild command. Location of the xcodebuild path is below.

/Applications/Xcode-beta.app/Contents/Developer/usr/bin/xcodebuild

You might wonder, how can I know those, where can I find those, what the exact parameter I should use etc… Do not worry. Those are not magically appeared. Those are the Xcode project build settings, which you can see by running the following command.

/Applications/Xcode-beta.app/Contents/Developer/usr/bin/xcodebuild -project AroshaFramework.xcodeproj -showBuildSettings

Next thing you have to do before build project is set build configurations as Release. You can open that pop up window like below.

Easy way to open Run Configuration window
Easy way to open Run Configuration window

Next, set build configuration as Release and also remove the tick from the Shared box.

Set Build Configuration as Release
Set Build Configuration as Release

The last thing is related to your universal target that you have created. What I’m going to achieve here is include latest as well as old architectures to our framework, then we can use this framework even in somewhat old iPhones as well. I’ve added missing architectures as below.

Add missing architectures
Add missing architectures

If I explain little bit about this architectures, iOS is going to stop supporting for 32 bit and moving on with 64 bits. I wanted this framework to support both 32 bit and 64 bit. That’s why I added x86 architecture which is 32 bit supports. Further more, like I mentioned in very early stage of this post, the Deployment Target is set to 10.0.

Now you are good to build your framework target and universal target. First you build your framework target and then universal target. Make sure you have selected Generic iOS Device option like below.

Building the universal target
Building the universal target

Because of the last line of the Run Script, a finder window will open where you can see your build framework. At this point you have successfully created a Swift framework that can be integrate with a Xamarin iOS project.

Before going to that integration part, I will tell you, how to verify that your fat file is supported for all the architectures that you have enabled in Xcode settings. What you have to do is, open your terminal application and go inside to your newly created framework directory and run below command.

lipo -info AroshaFramework 

If you get an out put like below, which means that your framework will run on both 32 and 64 bit OS.

Architectures in the fat file: AroshaFramework are: i386 x86_64 armv7 arm64

Source for this project can be access in my GitLab repository

Let’s move to the next part of the post, that is integrating the Swift framework to a Xamarin iOS project. I’m not going to go through in details description of creating a sample Xamarin solution. If you are so naive, just follow this post, which has more than enough details of creating a Xamarin solution. Once you have created a basic solution, you need to add one more project to that.

Adding a new project
Adding a new project

The project that you are going to add, is a Binding Library project.

Adding Bindings Library project
Adding Bindings Library project

In the next pop up window, you can give a name to that project.

Naming the project
Naming the project

Next thing is refer the fat file inside your Swift framework with the Xamarin Binding Library.

Refer the fat file inside the Swift framework
Refer the fat file inside the Swift framework

After finish that, then you have to modify the ApiDefinition.cs file. Here, I recommend you to use Objective Sharpie tool. As for the my knowledge, Xamarin still does not support direct binding with Swift. That’s why we needed Objective C interface as a helper. Once you install that tool, you have to run following command by going inside the Headers directory of the Swift framework

sharpie bind -sdk iphoneos12.1 AroshaFramework-Swift.h

If you are having curiosity mind, you may questioning yourself, how on earth this iphoneos12.1 parameter came from. Again, what I have to say is, there is no magic with these commands, everything has a purpose and a meaning. That is the current iPhone OS which installed inside my Mac. How you find is? Just run below command.

sharpie xcode -sdks

Back to the topic. We were in the middle of editing ApiDefinition.cs file. After you ran the bind command it will create ApiDefinitions.cs (with extra s) file where your Swift header files are. Open that ApiDefinitions.cs file and just copy what you need and paste inside your project’s ApiDefinition.cs. The appropriate code will be like below.

    // @interface AroshaFramework : NSObject
    [BaseType(typeof(NSObject))]
    interface AroshaFramework
    {
        // -(NSInteger)addTwoNumbersWithNumberOne:(NSInteger)numberOne numberTwo:(NSInteger)numberTwo __attribute__((warn_unused_result));
        [Export("addTwoNumbersWithNumberOne:numberTwo:")]
        nint AddTwoNumbersWithNumberOne(nint numberOne, nint numberTwo);
    }

Next step is to figure out each Swift package that is related to your Swift framework which you will be adding as NuGet packages inside your Xamarin iOS project. To do that, again go inside your Swift framework directory and run following command.

otool -l -arch armv7 AroshaFramework | grep libswift

By looking at the above out put, you can add necessary Swift NuGet packages. As for the worst case, if you have followed the steps accurately, you will ended up with an error by saying that there are some conflicts between Swift packages that you have added. In such a case just try to add the lower version of that conflicting occurring Swift Nuget package.

Last, but not least, what you want to do is accessing your precious framework inside your Xamarin iOS code. To do that, you have to add the binding project to your main project. Here is how you do it.

  • Expand the main project (Ex. UsageOfSwiftFramework.iOS)
  • Right click on the References and select Edit References
  • Then tap on the Projects tab
  • Then tick the project that you need to refer (Ex. BindingSwift)

Now you are good to call the Swift framework functions inside your ViewController.

using System;
using UIKit;
using BindingSwift;

namespace UsageOfSwiftFramework.iOS
{
    public partial class ViewController : UIViewController
    {
        public ViewController(IntPtr handle) : base(handle)
        {
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            var myClass = new AroshaFramework();
            var result = myClass.AddTwoNumbersWithNumberOne(1, 2);
            Console.WriteLine("# Result = " + result);
        }
    }
}

I believe this is the end of this descriptive lengthy post. You can access this Xamarin code source as well from my GitLab repository. If you encounter any issues, just reach me out from the comments. Wish you all a happy coding…!!! 🙂

About AnujAroshA

Working as an Associate Technical Lead. Specialized in iOS application development. A simple person :)
This entry was posted in iOS, Swift, Xamarin and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s