Things to keep in mind

What you'll learn

Prerequises

  1. A bit of Flutter knowledge. The Flutter team codelabs and the cookbook should help you get started.
  2. Install Unity Hub for Ubuntu and download the latest Unity Editor(LTS). While installing, you'll have to check out "Android Build Support"/"OpenJDK"/"Android SDK & NDK Tools" or you won't be able to export the project to Flutter. If you're building for ios, you have to check out "iOS Build Support". I won't be covering ios at this time.
  3. You'll also need to install the .NET SDK package repository for Ubuntu along with the C# extension in VSCode for syntax hightlighting and code completion. You can find a complete guide in VSCode website.
  4. A bit of Unity knowledge. Unity has good tutorials to help you get started.

To begin, create a new Flutter project and add a "unity" folder. Once done, create a new Unity project and set the path to the "unity" folder you just created. Your Flutter and Unity project should look like this:

📦flutter_unity_sample -> Flutter Project
 ┣ 📂android
 ┣ 📂ios
 ┣ 📂lib
 ┃ ┗ 📜main.dart
 ┣ 📂test
 ┣ 📂unity
 ┃ ┗ 📂sample_game -> Unity Project
 ┣ 📜README.md
 ┣ 📜analysis_options.yaml
 ┣ 📜flutter_unity_sample.iml
 ┣ 📜pubspec.lock
 ┗ 📜pubspec.yaml

In order to Flutter to work with Unity you'll need two components: the flutter_unity_widget package for Flutter and the fuw-(version).unitypackage for Unity.

Now that we have all the packages installed, we will make a small test and export/build the project to Flutter to know if everything work properly. You will rotate a cube as a test.

Adding The Code

To test, we need to add some components to Unity. Add a cube game object in your editor then in the cube inspector you will add a "Unity Message Manager" script along with your own "RotateCube" script.

This is the code in Unity for the cube:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FlutterUnityIntegration; //import library code

public class RotateCube : MonoBehaviour
{
    // this will help us send message to Flutter
    private UnityMessageManager unityMessageManganer;
    private float rotateSpeed = 0;

    // Start is called before the first frame update
    void Start()
    {
     unityMessageManganer = GetComponent<UnityMessageManager>();  
    }

    // Update is called once per frame
    void Update()
    {
     transform.Rotate(Vector3.up * Time.deltaTime * rotateSpeed); 

     //send to flutter deltaTime
     unityMessageManganer.SendMessageToFlutter($"DeltaTime: {Time.deltaTime}");  
    }

    // this is a method we created that we will call from Flutter to invoke
    public void MoveCubeFromFlutter(string value){ 

        rotateSpeed = float.Parse(value);

    }
}

This is code in the Flutter side:

import 'package:flutter/material.dart';
import 'package:flutter_unity_widget/flutter_unity_widget.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Unity Demo',
      theme: ThemeData(
        sliderTheme: const SliderThemeData(
            showValueIndicator: ShowValueIndicator.always),
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Unity Sample'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late UnityWidgetController _unityWidgetController;
  double sliderValue = 0;
  void _updateSliderValue(double value) {
    setState(() {
      sliderValue = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Stack(
          children: [
            UnityWidget(
              onUnityCreated: onUnityCreated,
              onUnityMessage: onUnityMessage,
            ),
            Positioned(
              bottom: 64,
              left: 16,
              right: 16,
              child: SizedBox(
                height: 64,
                width: MediaQuery.of(context).size.width,
                child: Card(
                  margin: const EdgeInsets.all(8.0),
                  child: Slider(
                    label: sliderValue.round().toString(),
                    min: 0,
                    max: 200,
                    onChanged: (value) => moveCubeFromFlutter('$value'),
                    value: sliderValue,
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }

  // Communcation from Flutter to Unity
  void moveCubeFromFlutter(String speed) {
    _unityWidgetController.postMessage(
      'Cube', //gameObjectName
      'MoveCubeFromFlutter', // methodName
      speed,
    );

    // update slider ui
    _updateSliderValue(double.parse(speed));
  }

  // Communication from Unity to Flutter
  // you should see the message of the deltaTime in the debug logs
  void onUnityMessage(message) {
    debugPrint('Received message from unity: ${message.toString()}');
  }

  // Callback that connects the created controller to the unity controller
  void onUnityCreated(controller) {
    _unityWidgetController = controller;
  }
}

Exporting The Build

Now that your code is ready, you can export the build. Save your Unity Scene, then go to the Flutter menu item and select "Export Android (Release)". When the build is done loading, go to the Flutter counterpart in VSCode. Look for your gradle file in android/app/build.gradle and change the line minSdkVersion flutter.minSdkVersion to minSdkVersion 22.

Run the code in your smartphone. You should be able to change the rotation of the cube with the slider widget. You should also see in the logs the Time.detlaTime value that Unity is sending to Flutter.

You completed the codelab, you can now use your newly acquired knowledge to build astounding game to Flutter.

If you have trouble running the app, you can compare your code from the github repository.

View Codelab Code

Feedback

This codelab may have some issues and to me this is only a draft, they are improvements that can be done. If you found a problem or have suggestions, you can click the report a mistake on the bottom left of the codelab. It will open a github issue.