Swift Native Unity Plugins

How to create a plugin for Unity that can be written in pure swift, no objective-c necessary

Project Setup

To ensure Swift files link correctly in Xcode, enable Swift support in one of the following ways:

  • If Google Dependency Resolver is already installed (or you’re comfortable adding it), enable the Enable Swift Framework Support Workaround option.

  • Alternatively, after the Xcode project is generated, manually create a new swift file in the project. Xcode will prompt to configure Swift support; accept to enable it.

Script Setup

To call Swift directly from C#, pay attention to how functions are defined and exposed for interop.

The following examples show a simple structure that supports calling both static and instance methods. Apply your own judgement and best practices for production code.

Swift

import Foundation
//import any other frameworks here

public class ClassName: NSObject {

    public static let shared = ClassName()

    public func internalFunctionWithParameters(paramater: String) {
        //any swift code can be called here as we are fully within the swift ecosystem
    }

    public func internalFunctionWithCallback(callback: @escaping @convention(c) (Bool) -> Swift.Void) {
        //any swift code can be called here as we are fully within the swift ecosystem
        callback(true)
    }
}


// Functions that are called from c# need to have an `@_cdecl("NameOfFunction") on them to be exposed
// As long as the name matches the name of the c# declaration, they can be named as needed
@_cdecl("FunctionWithParameters") // The name here is the one used on the csharp side in order to reference the function
public func functionName(_ charArrayFromCSharp : UnsafePointer<CChar>) {
    //string from c# are incompatible with swift as is, so we need to convert them to swift strings before use
    let swiftString = String(cString: charArrayFromCSharp)
    ClassName.shared.internalFunctionWithParameters(paramter: swiftString)
}

// Callbacks are completely available to be used from swift, either with or without parameters
@_cdecl("FunctionWithACallback")
public func functionNameWithCallback(callback: @escaping @convention(c) (Bool) -> Swift.Void) {
    ClassName.shared.internalFunctionWithCallback(callback)
}

C#

using System;
using UnityEngine;
using System.Runtime.InteropServices;
using AOT;

public class ClassName : MonoBehaviour
{
   [DllImport("__Internal")]
   private static extern void FunctionWithParameters(string charArray);

   [DllImport("__Internal")]
   private static extern void FunctionWithACallback(Action<bool> callback);

   public void CallSwiftCode()
   {
       //Call function with parameters
       FunctionWithParameters("String To Swift");
       //Call function with a callback
       FunctionWithACallback(ResultHandler);
   }

   [MonoPInvokeCallback(typeof(Action<bool>))]
   private static void ResultHandler(bool result)
   {
       //Called from the swift callback
   }
}

Additional Notes

  • Ensure the Swift source is placed under a folder within Plugins and is marked as an iOS plugin.

  • Keep function signatures stable and avoid name changes that could break bindings.

  • Prefer small, focused bridging surfaces to keep interop simple and maintainable.

Unity plugin import settings panel showing platform checkboxes with only iOS selected (Editor, Standalone, and Android unchecked).

Troubleshooting

  • If Xcode reports missing Swift symbols, verify that Swift support was actually enabled in the generated project.
  • If you see duplicate symbol or linkage errors, ensure exported function names are unique across files.
  • Confirm the plugin import settings target iOS only, and that the files are included in the build.