npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dolami-inc/react-native-expo-unity

v0.5.3

Published

Unity as a Library (UaaL) bridge for React Native / Expo

Readme

@dolami-inc/react-native-expo-unity

Unity as a Library (UaaL) bridge for React Native / Expo.

Install

npm install @dolami-inc/react-native-expo-unity
# or
yarn add @dolami-inc/react-native-expo-unity
# or
bun add @dolami-inc/react-native-expo-unity

Quick Start

import { UnityView, type UnityViewRef } from "@dolami-inc/react-native-expo-unity";

const unityRef = useRef<UnityViewRef>(null);

<UnityView
  ref={unityRef}
  style={{ flex: 1 }}
  onUnityMessage={(e) => console.log(e.message)}
/>

// Send message to Unity
unityRef.current?.postMessage("GameObject", "Method", "payload");

API

<UnityView />

| Prop | Type | Default | Description | |---|---|---|---| | onUnityMessage | (e: { message: string }) => void | — | Message from Unity | | autoUnloadOnUnmount | boolean | true | Unload Unity when view unmounts. Set false to pause only (keeps state). | | style | ViewStyle | — | Must have dimensions (e.g. flex: 1) | | ref | UnityViewRef | — | Imperative methods |

Ref Methods

unityRef.current?.postMessage(gameObject, methodName, message)
unityRef.current?.pauseUnity()
unityRef.current?.resumeUnity()
unityRef.current?.unloadUnity()

Standalone Functions

Same as ref methods, callable anywhere (operates on the singleton):

import { postMessage, pauseUnity, resumeUnity, unloadUnity, isInitialized } from "@dolami-inc/react-native-expo-unity";

Setup

1. Unity project — add plugins

Copy the platform bridge files into your Unity project:

iOS:

# From node_modules after install
cp node_modules/@dolami-inc/react-native-expo-unity/plugin/NativeCallProxy.h  <UnityProject>/Assets/Plugins/iOS/
cp node_modules/@dolami-inc/react-native-expo-unity/plugin/NativeCallProxy.mm <UnityProject>/Assets/Plugins/iOS/

Android:

No plugin files need to be copied — the NativeCallProxy Java class ships with the module and is available at runtime automatically. Your Unity C# code calls it via AndroidJavaClass (see Messaging Guide).

2. Unity project — build for your target platform

iOS

  1. Unity → File → Build Settings → iOS → Build
  2. Open generated Xcode project
  3. Select NativeCallProxy.h in Libraries/Plugins/iOS/
  4. Set Target Membership → UnityFrameworkPublic
  5. Select the Data folder in the Project Navigator
  6. In the right panel under Target Membership, check UnityFramework

    This is critical. Without this, the Data folder (which contains global-metadata.dat and all Unity assets) will NOT be included inside UnityFramework.framework. The app will crash at launch with: Could not open .../global-metadata.dat — IL2CPP initialization failed

  7. Build UnityFramework scheme

Android

  1. Unity → File → Build Settings → Android
  2. Check Export Project (do not "Build" directly — you need the Gradle project)
  3. Set Scripting Backend to IL2CPP
  4. Set Target Architectures: ARMv7 and ARM64
  5. Click Export and save to a directory (e.g. unity/builds/android)

3. Copy build artifacts to your RN project

iOS

Create unity/builds/ios/ in your project root and copy the built framework and static libraries:

mkdir -p unity/builds/ios

# Copy the compiled framework (should already contain Data/ inside after step 2.6)
cp -R <xcode-build-output>/UnityFramework.framework unity/builds/ios/

# Copy static libraries from the Unity Xcode project root
cp <unity-xcode-project>/*.a unity/builds/ios/

Verify that Data/ exists inside the framework:

ls unity/builds/ios/UnityFramework.framework/Data
# Should show: Managed/  Resources/  etc.

The podspec references these files directly by path — nothing is copied or embedded into the npm package. Updating your Unity build is as simple as replacing the contents of unity/builds/ios/ and re-running pod install.

Custom path? Set EXPO_UNITY_PATH environment variable pointing to your Unity build directory, or pass unityPath to the config plugin (see step 4).

Android

The Unity export directory (containing the unityLibrary folder) should be at unity/builds/android/ in your project root. The config plugin will automatically include the :unityLibrary Gradle module.

# Verify the structure
ls unity/builds/android/unityLibrary
# Should show: libs/  src/  build.gradle  etc.

Custom path? Set EXPO_UNITY_ANDROID_PATH environment variable, or pass androidUnityPath to the config plugin.

4. Add the config plugin to app.json

{
  "expo": {
    "plugins": [
      "@dolami-inc/react-native-expo-unity"
    ]
  }
}

The plugin automatically configures:

iOS:

  • ENABLE_BITCODE = NO — Unity does not support bitcode
  • CLANG_CXX_LANGUAGE_STANDARD = c++17 — required for Unity headers
  • Embeds UnityFramework.framework via a build script phase

Android:

  • Includes :unityLibrary module in settings.gradle
  • Adds flatDir repository for Unity's native libs
  • Adds ndk.abiFilters for armeabi-v7a and arm64-v8a

If your Unity artifacts are in custom paths:

["@dolami-inc/react-native-expo-unity", {
  "unityPath": "/absolute/path/to/unity/builds/ios",
  "androidUnityPath": "/absolute/path/to/unity/builds/android"
}]

5. Build

# iOS
expo prebuild --platform ios --clean
expo run:ios --device

# Android
expo prebuild --platform android --clean
expo run:android

Lifecycle

Unity is a singleton — one instance for the entire app.

| State | Memory | Re-entry | |---|---|---| | Running | ~200-500MB+ (depends on scene/assets) | Already running | | Paused | Same (frozen in memory, no CPU/GPU usage) | resumeUnity() — instant, state preserved | | Unloaded | ~80-180MB retained (Unity limitation) | Remount <UnityView /> — ~1-2s reinit, state reset |

Auto behavior

| Event | What happens | |---|---| | <UnityView /> mounts | Unity initializes and starts rendering | | <UnityView /> unmounts | Unity unloads (or pauses if autoUnloadOnUnmount={false}) | | App → background | Unity pauses | | App → foreground | Unity resumes |

Manual control

Screen focus/blur is not automatic — handle with useFocusEffect:

useFocusEffect(
  useCallback(() => {
    unityRef.current?.resumeUnity();
    return () => unityRef.current?.pauseUnity();
  }, [])
);

Messaging

RN → Unity

unityRef.current?.postMessage("GameManager", "LoadAvatar", '{"id":"avatar_01"}');
// Unity C# — on "GameManager" GameObject
public void LoadAvatar(string json) { /* ... */ }

Unity → RN

// iOS — uses extern "C" DllImport
#if UNITY_IOS && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern void sendMessageToMobileApp(string message);
#endif

// Android — uses AndroidJavaClass
private static void SendToMobile(string message) {
#if UNITY_IOS && !UNITY_EDITOR
    sendMessageToMobileApp(message);
#elif UNITY_ANDROID && !UNITY_EDITOR
    using (var proxy = new AndroidJavaClass("com.expounity.bridge.NativeCallProxy")) {
        proxy.CallStatic("sendMessageToMobileApp", message);
    }
#endif
}

// Usage:
SendToMobile("{\"event\":\"image_taken\",\"data\":{\"path\":\"/tmp/photo.jpg\"}}");
<UnityView onUnityMessage={(e) => {
  const msg = JSON.parse(e.message);
  // msg.event, msg.data
}} />

See Messaging Guide for recommended patterns.

Docs

Requirements

  • Expo SDK 54+
  • React Native New Architecture (Fabric) — old architecture not supported
  • Physical device — iOS: Unity renders only on device, Simulator shows a placeholder. Android: physical device or emulator with ARM support.
  • Unity build artifacts — must be exported/copied manually into your project (not bundled via npm)

Platform Support

| Platform | Status | |---|---| | iOS Device | Supported | | iOS Simulator | Not supported — renders a placeholder view | | Android Device | Supported | | Android Emulator | Supported (ARM-based emulators only) |

Limitations

  • Single instance — only one Unity view at a time, cannot run multiple
  • Full-screen rendering only — Unity renders full-screen within its view (Unity limitation)
  • Memory retention — after unloadUnity(), Unity retains 80-180MB in memory (Unity limitation)
  • No reload after quit — if Unity calls Application.Quit() on iOS, it cannot be restarted without restarting the app
  • No hot reload — native code changes require a full rebuild

License

MIT