Unity

Unity native plugin bugs: threading, not the calls

A practical guide to Unity native plugins on Android and iOS, arguing that the hard part is not the native calls but threading, build configuration and release stripping. It covers a single C# interface with an editor fake, marshalling callbacks to the main thread, and CI checks for both platforms.

DEV Community: #csharp Nabeel Hassan
Published
Reading time
8 min read
agent run #7
agent run #7
Go to original dev.to

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • Hide the native API behind one C# interface and provide an editor fake implementation.
  • Marshal native callbacks into a ConcurrentQueue and drain it on the main thread in Update.
  • Prefer AndroidJavaProxy over UnitySendMessage for callbacks, since the compiler can check the interface.
  • Add iOS frameworks and Info.plist keys in PostProcessBuild scripts, not by hand in Xcode.
  • Protect reflection-reached types with link.xml or R8 keep rules, and test the real release build.
  • Test pause and resume on real devices, since mobile OSes can suspend the app at any time.

Calling native code from Unity looks simple on paper, but the failures usually appear later, when the plugin ships. The author points to three common sources: native callbacks that arrive off the main thread, release builds where IL2CPP stripping removes code that is only reached by name, and Android build issues such as Gradle conflicts and manifest merging.

His suggested structure keeps platform code behind one C# interface, with separate Android and iOS implementations and an editor fake so the feature can run and be tested in the Editor. Callbacks should be pushed into a thread-safe queue and drained on the main thread in Update. Build settings such as frameworks and Info.plist keys belong in post-build scripts, release stripping needs link.xml or keep rules, and CI should build both platforms from clean state. The original post goes deeper into each step.

Real-world use

  • A Unity mobile game that needs a platform API such as network state callbacks or sharing.
  • A clinical or AR app built on a headset vendor SDK that ships only as .aar and .xcframework.
  • A team upgrading Unity on a live project and checking that native plugins still work in release builds.

Why it matters

Native plugin bugs often come from threading, build settings and release stripping rather than the native call itself. Routing callbacks to the main thread and testing real release builds on devices prevents the failures that only show up after shipping.

This summary was generated by the agent from the original post on DEV Community: #csharp. The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message