Skip to content

Basic React Native app with Tabs navigation and Integration of Unity View

Notifications You must be signed in to change notification settings

johnsonpeixoto/basic-react-native-unity

 
 

Repository files navigation

basic-react-native-unity

Basic React Native app with Tabs navigation and Integration of Unity View.

Works on both Android and iOS.

Kudos to @asmadsen/react-native-unity-view.

Demo

Getting Started

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.

Prerequisites

  • node / npm / yarn.
  • React Native 0.6+.
  • Unity 2019.3+.
  • Xcode (mine is 11).
  • Real test devices (for both platforms, especially for iOS, since the simulator won't work, you'll also need to have an Apple ID to be able to sign the app). Mine are Samsung S8 & iPhone starting from 7.
  • React Native Debugger (optional, if you want to test bridge messages that's it).

Installing

  • Clone this repo && cd.

  • Install dependencies & packages:

$ npm i

// OR

$ yarn

  • Link:
$ react-native link
$ react-native link @asmadsen/react-native-unity-view

Running the tests

  • Plug your device and make sure your system recognize it.

  • Start the packager (skip for Android if you want):

$ react-native start

For Android:

Gradle files are already configured. You just need to run:

$ react-native run-android

For iOS

  • Install pods:
$ cd ios

# For MACs with Intel Family
$ pod install
# For MACs with M1 Family 
$ sudo arch -x86_64 pod install --allow-root

$ cd ..
  • (Optional) Relink (just in case, just to make sure):
$ react-native link
$ react-native link @asmadsen/react-native-unity-view 
  • Open the .xcworkspace in Xcode.

Open .xcworkspace

  • Check and fix signing conflicts for both the Main Project and the Unity-iPhone Project (for Tests Target too).

  • Clean and Build the Main project for a real device, while the packager is running.

Open .xcworkspace

  • If the build succeeded but the app is not installed and launched on the device, just restart the packager, maybe delete the app on the iPhone, then clean and rebuild project. And make sure that your Apple ID works.
$ react-native start

How to use your own Unity Project

  • Want your own Unity Scene ?

Create a new Unity Project

  • Inside the unity/ folder, create your own Unity Project. So it will look like this:

(The folder's name doesn't matter.)

$ cd unity
$ git clone https://github.com/sdsmnc221/basic-unity.git UnityProject
$ cd ..
  • Open the project in Unity 2019.3+.

Import react-native-unity-view into the Unity Project

  • You will now have a ReactNative Menu!

(From this...)

(...to this.)

Configure the Unity Project

  • Open the Player Settings (Shift Cmd B > Player Settings).

  • Change Product Name to the name of the React Native Xcode project (ios/${XcodeProjectName}.xcodeproj):

  • Android configs:

(Auto Graphics API unchecked.)

(Android SDK version.)

(Other configs: IL2CPP, .NET 4.x, ARM64 checked.)

  • iOS configs:

(Auto Graphics API checked.)

(Identification configs (correctly config your signing team ID and Automatically Sign checked.)

Export the Unity Project

  • You can now export your project via the menu (not the Build Settings):

(Export Android (Unity...) or Export iOS (Unity...) .)

  • The exported builds will be placed in a folder called UnityExport inside either the android/ or ios/ folder.

  • Wait until Build Successful.

  • ATTENTION: Every time changes are made inside the Unity Project, no matter which change is it, please re-export the project.

  • Loading more than one instance of the Unity runtime is not supported. This is a crucial limitation, as mentioned in here, from the Unity Blog, and also with the react-native-unity-view package, there are only one UnityExport. I still don’t know whether we can run multiple Unity scenes or views inside a single React Native App. For scenes, perhaps, I speculate creating a SceneManager inside the Unity Project (will test it later). But for views (as in multiple instances of Unity), maybe it is not yet possible.

Config and Run on Android

  • Export the Unity Project.

  • Normally all of the Gradle files in this repo are preconfigured.

  • (Optional) Make sure that the minSdkVersion for everywhere inside this whole React Native project is at least 19. (You can run a search of 'minSdkVersion' inside VS Code to check. Sometimes it isn't always 19 everywhere, sometimes. But not in this repo...)

  • Plug in your Android device and run:

$ react-native run-android

Config and Run on iOS

  • Export the Unity Project.

  • Open the .xcworkspace in Xcode.

Open .xcworkspace

  • Check and fix signing conflicts for both the Main Project and the Unity-iPhone Project (for Tests Target too), if needed.

  • Clean and Build the Main project for a real device, while the packager is running.

Open .xcworkspace

  • If the build succeeded but the app is not installed and launched on the device, just restart the packager, clean and rebuild project. And make sure that your Apple ID works.
$ react-native start
  • The Xcode project is also preconfigured so you don't need to to anything.

    • If you're interested in the configs, please refer to asmadsen's docs.

    • OR here, in case build failed, errors, or you need a detailed illustrated guide: README-ios.md.

  • IF Build succeeded, but the app isn't installed nor launched on the device:

    • (Optional) Unplug and replug the iPhone.

    • (Optional) Close and reopen Xcode workspace.

    • Delete the app on the device.

    • Clean the build.

    • Restart the packager.

    • Rebuild.

Really this can happen frequently if you re-export your Project... And I promise this has got to be something with the Xcode build and packager. If this isn't working just repeat. The 3 last steps can be executed in any orders, until it works haha.

Example usage of the API and the React Native <-> Unity Bridge

  • Want a Bridge on any scene ?

  • For the full API, please refer to asmadsen's docs.

  • In my case, I based on his docs to create an example of bridge, with:

    • On Unity side, a C# script: RNUBridge Component.

      • In your Unity scene, tag the Main Camera as MainCamera.
      • Add the RNUBridge Component to any GameObject.

    • On React Native side, a Javascript script: UnityScreen.

Bridge's keypoints:

  • UnityMessageManager in Unity:

  • UnityModule in React Native:
// src/screens/UnityScreen/index.js
// UnityView is the React Native Component to display the Unity scene

import UnityView, { UnityModule } from '@asmadsen/react-native-unity-view';

Boot up the UnityMessageManager in Unity:

// RNUBridge.cs

void Awake()
{
    UnityMessageManager.Instance.OnRNMessage += onMessage;
}

void OnDestroy()
{
    UnityMessageManager.Instance.OnRNMessage -= onMessage;
}

void onMessage(MessageHandler message)
{
    var data = message.getData<string>();

    // do what you want here.
}

Unity: Implement commands listener, and then execute received commands with onMessage

  • I implemented 3 simple commands:

    • to toggle the GameObject's rotation;

    • to change the Main Camera's background color;

    • and to say Hi from Unity whenever you want (but in my case, whenever the UnityScreen is mounted, hence the command's name is 'OnStart'):

// RNUBridge.cs

void onMessage(MessageHandler message)
{
    var data = message.getData<string>();
    Debug.Log("onMessage:" + data);

    switch (data)
    {
        case "ToggleRotate":
            doRotate = !doRotate;
            UnityMessageManager.Instance.SendMessageToRN("Now it is " + (doRotate ? "" : "not ") + "rotating.");
            message.send(new { CallbackMsg = "JSON" +
                ": Rotate " + (doRotate ? "ON" : "OFF") });
            break;
        case "OnStart":
            UnityMessageManager.Instance.SendMessageToRN("Hello from Unity!");
            break;
        case "ChangeBGColor":
            doChangeBGColor = true;
            break;
        default:
            break;
    }
}

// And some other code in FixedUpdate() to make rotation and color changing work.
  • Unity, after receiving commands from React Native, can execute it and send a message string to React Native:
UnityMessageManager.Instance.SendMessageToRN("some string");
  • Or a callback message (message sent after executing the command) in JSON format:
message.send(new { CallbackMsg = "JSON" });

React Native: Implement commands sender and callback receiver from Unity

  • First we have the bridge function, to send message and to receive callback message:
// src/screens/UnityScreen/index.js

const bridge = (data, cb = null) => {

    // to receive callback message  

    if (!cb) cb = (data) => {
        console.log(data);
    }

    // to send/post command (the name is not important, but the data property must match the command name implemented in the C# script)

    UnityModule.postMessageToUnityManager({
        name: data,
        data: data,
        callBack: cb
    });
}
  • Also the onUnityMessage, to receive the message string:
// src/screens/UnityScreen/index.js

const onUnityMessage = (message) => {
    console.log(message);
};

// attach it to the <UnityView />

UnityView
    onMessage={onUnityMessage}
    onUnityMessage={onUnityMessage}
/>

  • Using the bridge function:

    • When the screen is mounted or focused:
    useEffect(() => {
        bridge('OnStart');
        
        if (isFocused) bridge('OnStart');
    }, [])
    
    • 2 simple buttons to send commands to the Unity Scene (either toggle rotation or changing the scene’s background color):
    <TouchableOpacity onPress={() => bridge('ToggleRotate')}>
        <Text>Toggle Rotation</Text>
    </TouchableOpacity>
    
    <TouchableOpacity onPress={() => bridge('ChangeBGColor')}>
        <Text>Change Background Color</Text>
    </TouchableOpacity>
    
    • I used the state to display Unity's messages (for instance I only display the message for the Toggle Rotation command).

Others:

  • To persist the Unity screen:
const UnityScreen = ({navigation}) => {
  navigation.setOptions({
    unmountOnBlur: true
  });

  return (<View> </View>)
}
  • You can see the debug log on your terminal or your React Native Debugger's console:

  • Well that's it, hope you can do more!

Multiple Unity Scenes

Full Video Demo, since I can't convert it into a full GIF

.
  • Tested on both iOS and Android.

  • Import this custom package into your Unity Project: multiple-scenes.unitypackage. It comes with:

    • a SceneLoader prefab, to change scene with a simple crossfade animation;

    • a SceneLoader Component, with methods to change scenes;

    • a SceneButton prefab, to change scenes within Unity;

    • and an update version of the RNUBridge Component (new command ChangeScene added).

  • I also updated the UnityScreen javascript code with a new bridge (to have a new button to call the ChangeScene command from React Native).

  • How to use it:

    • You need to have at least 2 scenes (well 2 scenes are good, since here in my test I have exactly 2 scenes, so my code is only adapted for switching between 2 scenes sorry haha.)

    • For each and every scenes, add the SceneLoader prefab into the Scene / Hierarchy.

    • Drag that SceneLoader gameobject into the SceneLoader slot in RNUBridge.

    • Open your Build Settings (Shift Cmd B), add all of your scenes in your order of choice.

    • Re-export your project for Android or iOS and then re-run the React Native App.
  • How to use the SceneButton prefab, to change scenes from within Unity (not using bridge):

    • Already having the SceneLoader in the scene.

    • Add the SceneBtn prefab into the Scene / Hierarchy. You may need to tweak its position so it is visible (it will be visible on 16:9 Portrait / 9:16 screen though).

    • Select (Hierarchy) / SceneBtn / Button > Button Componenent, config the OnClick() setting like so:

    (Make sure to choose the SceneLoader gameobject from THE SCENE, not from the Assets.)

    • That's it. Now you can crossfade between scene from within Unity.

  • Results:

    • Works like a charm on Android.

    • For iOS, beware of iOS build failed error undefined symbol _onUnityMessage or undefined symbol _UnityMessageManager_onUnityMessage, please refer to: README-ios.md.

Built With

Authors

Acknowledgments

TODO

  • Upload a nice demo gif.
  • Upload then include downdload links for UnityExports.
  • Working docs for Android.
  • Workings docs for iOS.
  • Upload a fresh UnityProject.
  • Docs for UnityProject & how to export and build the project on your own in:
    • Android.
    • iOS.
  • Docs for Bridge.
  • Support for multiple Unity scenes. Multiple Unity Views / Instances are impossible, until further updates from Unity and asmadsen (if he decides not to drop his project haha).
  • Docs for multiple Unity scenes.

About

Basic React Native app with Tabs navigation and Integration of Unity View

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 35.6%
  • Java 26.7%
  • Objective-C 18.4%
  • C# 8.5%
  • Starlark 7.6%
  • Ruby 3.2%