This Unity package provides the C# scripts and native plugins needed to integrate Unity with the GameFramework.
plugin/
├── Scripts/
│ ├── NativeAPI.cs # Low-level platform bridge (NEW)
│ ├── UnityMessageManager.cs # Message router with callbacks (NEW)
│ ├── MessageHandler.cs # Type-safe message handling (NEW)
│ ├── FlutterBridge.cs # Core bridge (backward compatible)
│ ├── FlutterSceneManager.cs # Scene management integration
│ ├── FlutterGameManager.cs # Example game manager
│ ├── FlutterUtilities.cs # Helper utilities
│ ├── FlutterPerformanceMonitor.cs # Performance monitoring
│ └── Examples/
│ └── NativeAPIExample.cs # Complete communication example
├── Plugins/
│ └── iOS/
│ └── FlutterBridge.mm # iOS native bridge (enhanced)
├── NATIVE_API_GUIDE.md # Complete communication guide
└── README.md # This file
The plugin now includes three levels of Unity-Flutter communication based on the flutter-unity-view-widget pattern:
- NativeAPI.cs - Low-level platform bridge (iOS/Android)
- UnityMessageManager.cs - High-level message routing with callbacks
- MessageHandler.cs - Type-safe message handling with generics
See NATIVE_API_GUIDE.md for comprehensive documentation.
- Copy the entire
pluginfolder to your Unity project'sAssets/directory - The scripts will be automatically compiled by Unity
- Import the
.unitypackagefile via Unity menu:Assets > Import Package > Custom Package...
- Create an empty GameObject in your startup scene
- Name it
FlutterBridge - Add the
FlutterBridgecomponent to it - The component will persist across scenes automatically
- Create an empty GameObject in your startup scene
- Name it
FlutterSceneManager - Add the
FlutterSceneManagercomponent to it - Configure the settings in the Inspector:
- ✓ Notify On Scene Load
- ✓ Notify On Scene Unload
- Create an empty GameObject in your scene
- Name it
GameManager - Add the
FlutterGameManagercomponent to it - Configure the settings:
- ✓ Send Game State Updates
- Update Interval: 1.0 (seconds)
using Xraph.GameFramework.Unity;
public class GameBootstrap : MonoBehaviour
{
private MessageHandler messageHandler;
void Start()
{
// 1. Initialize NativeAPI
NativeAPI.Initialize();
// 2. Setup message handler
messageHandler = gameObject.AddComponent<MessageHandler>();
messageHandler.RegisterHandler<PlayerAction>("PlayerAction", HandleAction);
// 3. Notify Flutter when ready
NativeAPI.NotifyUnityReady();
}
void HandleAction(PlayerAction action)
{
Debug.Log($"Action: {action.type}");
// Send response
var response = new ActionResponse { success = true };
messageHandler.SendMessage("Flutter", "onActionResponse", response);
}
}
[System.Serializable]
public class PlayerAction { public string type; public float x, y, z; }
[System.Serializable]
public class ActionResponse { public bool success; public string result; }See NATIVE_API_GUIDE.md for complete documentation.
The classic FlutterBridge API is still fully supported for backward compatibility.
using Xraph.GameFramework.Unity;
public class MyGameScript : MonoBehaviour
{
void OnEnable()
{
// Subscribe to all Flutter messages
FlutterBridge.OnFlutterMessage += HandleFlutterMessage;
}
void OnDisable()
{
FlutterBridge.OnFlutterMessage -= HandleFlutterMessage;
}
private void HandleFlutterMessage(string target, string method, string data)
{
if (target == "MyGameObject")
{
switch (method)
{
case "StartLevel":
StartLevel(data);
break;
case "UpdateSettings":
UpdateSettings(data);
break;
}
}
}
private void StartLevel(string levelData)
{
Debug.Log($"Starting level: {levelData}");
// Your level start logic
}
}using UnityEngine;
public class PlayerController : MonoBehaviour
{
// This method will be called when Flutter sends a message
// to GameObject named "Player" with method "Jump"
public void Jump(string data)
{
Debug.Log($"Jump triggered from Flutter: {data}");
// Your jump logic
}
// Flutter sends to "Player" -> "SetSpeed" -> this method is called
public void SetSpeed(string speedData)
{
float speed = float.Parse(speedData);
// Update player speed
}
}From Flutter:
controller.sendMessage('Player', 'Jump', '10.5');
controller.sendMessage('Player', 'SetSpeed', '5.0');using Xraph.GameFramework.Unity;
public class MyGameScript : MonoBehaviour
{
void Start()
{
// Send a simple message
FlutterBridge.Instance.SendToFlutter(
"GameManager",
"onGameReady",
"true"
);
}
void OnPlayerScored(int score)
{
// Send score to Flutter
FlutterBridge.Instance.SendToFlutter(
"GameManager",
"onScore",
score.ToString()
);
}
}using Xraph.GameFramework.Unity;
[System.Serializable]
public class PlayerData
{
public string playerName;
public int level;
public float health;
public int[] inventory;
}
public class MyGameScript : MonoBehaviour
{
void SendPlayerData()
{
var playerData = new PlayerData
{
playerName = "Hero",
level = 5,
health = 85.5f,
inventory = new int[] { 1, 2, 3 }
};
// Automatically serializes to JSON
FlutterBridge.Instance.SendToFlutter(
"GameManager",
"onPlayerUpdate",
playerData
);
}
}void OnError(string errorMessage)
{
FlutterBridge.Instance.SendError(errorMessage);
}using Xraph.GameFramework.Unity;
public class LevelManager : MonoBehaviour
{
void LoadNextLevel()
{
// Scene load will automatically notify Flutter
// via FlutterSceneManager
SceneManager.LoadScene("Level2");
}
// Or manually notify
void OnLevelComplete()
{
FlutterBridge.Instance.NotifySceneLoaded("Level2", 2);
}
}The main bridge component for Unity-Flutter communication.
Instance- Singleton instance of FlutterBridgeOnFlutterMessage- Event triggered when receiving messages from Flutter
SendToFlutter(string target, string method, string data)- Send string message to FlutterSendToFlutter<T>(string target, string method, T data)- Send JSON message to FlutterSendError(string errorMessage)- Send error message to FlutterNotifySceneLoaded(string sceneName, int buildIndex)- Notify Flutter of scene load
The ReceiveMessage(string message) method is called automatically via Unity's UnitySendMessage.
You don't need to call this method directly.
Manages scene events and notifications.
notifyOnSceneLoad- Automatically notify Flutter on scene loadnotifyOnSceneUnload- Automatically notify Flutter on scene unload
LoadScene(string sceneName)- Load scene by nameLoadSceneByIndex(string indexStr)- Load scene by indexLoadSceneAsync(string sceneName)- Load scene asynchronously with progress updates
Example game manager showing Flutter integration patterns.
sendGameStateUpdates- Send periodic game state updates to FlutterupdateInterval- Update interval in seconds
StartGame(string levelData)- Start the gamePauseGame()- Pause the gameResumeGame()- Resume the gameStopGame()- Stop the gameUpdateScore(string scoreData)- Update scoreSetLevel(string levelData)- Set current levelGameOver(int finalScore)- Trigger game overSendCustomEvent(string eventName, string eventData)- Send custom events
Flutter (Dart)
↓ controller.sendMessage('Player', 'Jump', '10')
Platform Channel
↓ engine#sendMessage
Native Bridge (Kotlin/Swift)
↓ UnityPlayer.UnitySendMessage('FlutterBridge', 'ReceiveMessage', ...)
Unity C#
↓ FlutterBridge.ReceiveMessage()
↓ OnFlutterMessage event OR GameObject.SendMessage()
Your Game Scripts
Your Game Scripts
↓ FlutterBridge.Instance.SendToFlutter(...)
Unity C#
↓ Platform-specific native call
Native Bridge (Kotlin/Swift)
↓ onUnityMessage() → sendEventToFlutter()
Platform Channel
↓ Event stream
Flutter (Dart)
↓ controller.messageStream
Your Flutter App
- Messages are sent via
AndroidJavaObjectcalls to the Activity - The
UnityEngineController.ktmust have a publiconUnityMessagemethod - All Unity operations must run on the main thread
- Messages are sent via native Objective-C bridge (
FlutterBridge.mm) - The
UnityEngineController.swiftmust have a publiconUnityMessagemethod - The Unity framework is loaded dynamically
Unity:
public class SimpleGame : MonoBehaviour
{
void OnEnable()
{
FlutterBridge.OnFlutterMessage += HandleMessage;
}
void OnDisable()
{
FlutterBridge.OnFlutterMessage -= HandleMessage;
}
private void HandleMessage(string target, string method, string data)
{
if (target != "Game") return;
if (method == "Start")
{
StartGame();
}
else if (method == "Stop")
{
StopGame();
}
}
private void StartGame()
{
Debug.Log("Game started!");
FlutterBridge.Instance.SendToFlutter("Game", "onStarted", "success");
}
private void StopGame()
{
Debug.Log("Game stopped!");
FlutterBridge.Instance.SendToFlutter("Game", "onStopped", "success");
}
}Flutter:
// Start the game
await controller.sendMessage('Game', 'Start', '');
// Listen for response
controller.messageStream.listen((message) {
if (message.method == 'onStarted') {
print('Game started successfully!');
}
});Unity:
public class ScoreManager : MonoBehaviour
{
private int currentScore = 0;
public void AddScore(int points)
{
currentScore += points;
// Send update to Flutter
FlutterBridge.Instance.SendToFlutter(
"Score",
"onScoreUpdate",
currentScore.ToString()
);
}
}Flutter:
int gameScore = 0;
controller.messageStream.listen((message) {
if (message.method == 'onScoreUpdate') {
setState(() {
gameScore = int.parse(message.data);
});
}
});Unity:
[System.Serializable]
public class GameStats
{
public int level;
public int score;
public float playTime;
public string[] achievements;
}
public void SendStats()
{
var stats = new GameStats
{
level = 5,
score = 1000,
playTime = 120.5f,
achievements = new string[] { "first_win", "speed_run" }
};
FlutterBridge.Instance.SendToFlutter("Stats", "onUpdate", stats);
}Flutter:
class GameStats {
final int level;
final int score;
final double playTime;
final List<String> achievements;
GameStats.fromJson(Map<String, dynamic> json)
: level = json['level'],
score = json['score'],
playTime = json['playTime'],
achievements = List<String>.from(json['achievements']);
}
controller.messageStream.listen((message) {
if (message.method == 'onUpdate') {
final stats = GameStats.fromJson(message.asJson());
print('Level: ${stats.level}, Score: ${stats.score}');
}
});- Ensure
FlutterBridgeGameObject exists in your scene - Check that the GameObject name matches the target in your Flutter code
- Verify the method name matches a public method in your script
- Check Unity console for error messages
- Verify you're building for Android or iOS (not Editor)
- Check native logs for bridge initialization
- Ensure
UnityEngineControlleris properly instantiated - Verify the platform channel is connected
- Ensure
FlutterSceneManageris in your scene - Check that notifications are enabled in the Inspector
- Verify scene names are correct
- Singleton Pattern: Always use
FlutterBridge.Instance- don't create multiple instances - Error Handling: Always wrap Flutter communication in try-catch blocks
- JSON Serialization: Use
[System.Serializable]for classes you want to send to Flutter - Message Routing: Use consistent target and method names across Unity and Flutter
- Lifecycle: Subscribe to
OnFlutterMessageinOnEnable, unsubscribe inOnDisable - Threading: All Unity API calls must be on the main thread
- Performance: Avoid sending large messages or too frequent updates
Override HandleMessage in FlutterBridge for custom routing:
public class CustomFlutterBridge : FlutterBridge
{
protected override void HandleMessage(string target, string method, string data)
{
// Your custom routing logic
if (target.StartsWith("Custom"))
{
// Handle custom targets
}
else
{
// Fall back to default handling
base.HandleMessage(target, method, data);
}
}
}public class AsyncExample : MonoBehaviour
{
private async void LoadDataFromFlutter()
{
// Request data
FlutterBridge.Instance.SendToFlutter("Data", "requestPlayerData", "");
// Wait for response (you'll need to implement the waiting logic)
// This is just a conceptual example
}
}See LICENSE file in the repository root.
For issues and questions:
- GitHub: https://github.com/xraph/gameframework/issues
- Documentation: See
engines/unity/dart/README.mdfor Flutter-side usage