iOS plugins: configuration and C# access
.gdip files, binary selection, dependencies, singletons and diagnosis.
An iOS plugin supplies a native library linked into an exported application. It can expose platform functionality without recompiling the engine when the integration fits the existing plugin interface. You still need a compatible binary, headers, dependencies and a working Xcode export; the config file does not implement the plugin.
Install a plugin
Place its config and binaries under asset://ios/plugins, for example asset://ios/plugins/my_plugin/MyPlugin.gdip next to MyPlugin.xcframework. The current exporter recursively scans that directory for .gdip files. Keep that exact extension: renaming it prevents detection.
The loader requires nonempty name, binary, initialization and deinitialization values and an existing supported binary path. Valid plugins receive an export option named plugins/<name>, initially false. Enable the required plugin in the iOS export preset. Plugin discovery is not the same as loading its code into the desktop editor.
Use a unique config name per plugin. Inspect the generated Xcode project, build it for the actual target, then verify initialization and one real operation on a device. An enabled checkbox alone establishes none of those results.
Minimal configuration
Save this as MyPlugin.gdip. It describes an example package: supply a real compatible library and matching native entry points before export.
[config]
name="MyPlugin"
binary="MyPlugin.xcframework"
initialization="init_my_plugin"
deinitialization="deinit_my_plugin"
[dependencies]
linked=[]
embedded=[]
system=["Foundation.framework"]
capabilities=[]
files=[]
linker_flags=[]
spm_packages=[]
[plist]
PluginLabel:string="MyPlugin"binary and relative local dependency paths are resolved from the config directory. asset:// paths can also identify project files. For the main binary, .a must be an existing file and .xcframework an existing directory. This discovery check does not validate object-code architecture, exported symbols or the contents of an XCFramework.
If the configured common binary exists, it is used for both targets. Otherwise, the loader accepts both MyPlugin.debug.xcframework and MyPlugin.release.xcframework, selected by debug/release export; the same naming rule applies to .a. Remove an obsolete common binary when switching to target-specific variants, or it will take precedence. Supplying only one variant does not pass the paired-file check.
Native implementation and dependencies
The exporter generates declarations and calls of the form extern void init_my_plugin(); and extern void deinit_my_plugin();. The native implementation must provide matching functions and manage its own initialization, cleanup and API registration. The config does not create a singleton or define its methods. Use headers and generated inputs matching the engine/template build; do not stop a build arbitrarily and assume every generated header is ready.
Build device and simulator variants for their respective SDKs and package the required variants into an XCFramework. Do not combine iOS-device and iOS-Simulator code into one binary just because both use arm64. Follow Apple's XCFramework instructions and Building iOS templates. There is no universal compiler-flag list that makes every vendor library compatible.
| Section/key | Purpose |
|---|---|
dependencies/linked | Local dependencies to link. |
dependencies/embedded | Dependencies to link and include in the application; choose according to the actual library packaging. |
dependencies/system | System frameworks; relative names resolve under /System/Library/Frameworks. |
dependencies/files | Additional files to copy; local relative paths use the config directory. |
dependencies/capabilities | Required-device capabilities for the exported plist; not a substitute for entitlements or user permission requests. |
dependencies/linker_flags | Flags required by the specific library; do not add -ObjC without an integration requirement. |
dependencies/spm_packages | Package dictionaries with url, exact version and products array. |
plist | Additional plist keys: string, integer, boolean, raw or string_input; no suffix defaults to string. |
SPM export groups packages by URL and merges product names; the current implementation does not report conflicting versions for the same URL. Keep versions consistent across enabled plugins and inspect the generated project. raw plist content is copied as supplied, and string content is inserted into XML without general escaping in this loader: check the final plist, especially values containing XML-special characters. string_input creates an editable export value; it is not a secret store.
Calling a registered singleton from C#
If the native implementation exposes an Engine singleton, use its registered singleton name, which may differ from config name. This helper checks existence and method availability before making a zero-argument call:
using Reckfell;
public static class NativePluginBridge
{
public static bool TryCall(StringName singletonName, StringName method, out Variant result)
{
result = default;
if (!Engine.HasSingleton(singletonName))
return false;
var plugin = Engine.GetSingleton(singletonName);
if (plugin is null || !plugin.HasMethod(method))
return false;
result = plugin.Call(method);
return true;
}
}The returned bool means the name/method checks passed and the call was issued; it does not validate an operation's success or returned data. Validate the result against the plugin's documented contract and dispose an owned returned Variant after use. The singleton wrapper is borrowed: do not Free or Dispose it. Methods requiring parameters need a matching argument list; this helper intentionally handles zero arguments only.
If the singleton is absent in the desktop editor, show an unavailable state instead of invoking it. This helper does not make native iOS code or C# publishing available on an unsupported target.
Diagnose the failing stage
| Symptom | Check |
|---|---|
| Plugin absent from export options | ios/plugins location, exact .gdip extension, required fields and existing binary or complete target pair. |
| Undefined initialization symbol | Config spelling, generated C++ declaration and actual linked symbols. |
| Wrong-platform or architecture linker error | Device/simulator SDK and the selected XCFramework slice; arm64 alone does not identify the platform. |
| Build succeeds, singleton absent | Plugin enabled, initialization executed and native code actually registering the expected name. |
| Method missing | Registered method name, API version and parameters; config name defines no methods. |
| Invalid plist or dependency resolution failure | Final plist XML, dependency paths and consistent SPM versions, not just config syntax. |
The config snippet and C# helper were executed with the installed Windows Runtime: generic ConfigFile parsing, built-in Engine calls and absent singleton/method cases. This does not exercise the Apple plugin loader, native linking, Xcode, C# iOS export, signing, simulator/device execution or a vendor service. Those conditions remain unverified.