-
Notifications
You must be signed in to change notification settings - Fork 6
Home
This plugin was designed as a federated plugin to make it easier to support multiple versions of Unity. Instead of having confusing branching code for different versions of Unity, and cases where fixing a problem with one version of Unity will break another, the idea is to create separate sub-packages which can be maintained and updated separately.
This plugin is organised as follows:
-
flutter_embed_unity
: this is the main app-facing package, which you should depend on in your Flutter app'spubspec.yaml
-
flutter_embed_unity_2022_3_android
: the Android platform package for this plugin, supporting Unity 2022.3 LTS -
flutter_embed_unity_2022_3_ios
: the iOS platform package for this plugin, supporting Unity 2022.3 LTS -
flutter_embed_unity_platform_interface
: The package that glues the app-facing package to the platform package(s). This package declares an interface that any platform package must implement to support the app-facing package. Having a single package that defines this interface ensures that all platform packages implement the same functionality in a uniform way. -
example_unity_2022_3_project
: a Unity project for building into the example project, for demo and development purposes
For example, if you wanted to support Unity 2019.4 on Android, you would create a separate package called flutter_embed_unity_2019_4_android
by copying the flutter_embed_unity_2022_3_android
and making changes as required (it would be best to keep the structure as similar as possible to help maintainability by other contributors).
A separate example Unity project for that version of Unity should also be created at the root of the repository to be used in the example app.
The pubspec.yaml for the public facing package defines which packages are currently the default 'endorsed' package, for example:
flutter:
plugin:
platforms:
android:
default_package: flutter_embed_unity_2022_3_android
ios:
default_package: flutter_embed_unity_2022_3_ios
The user can choose to use flutter_embed_unity_2019_4_android
instead by depending on it directly it in their app's pubspec.yaml. Alternatively, for newer LTS versions of Unity, the default endorsed package could be updated as a breaking change.
The best way to get started with development is to run the example first.
There are 3 example projects: one for the app-facing package, which will run on both iOS and Android (flutter_embed_unity/flutter_embed_unity/example
), one for the Android platform implementation package (flutter_embed_unity/flutter_embed_unity_2022_3_android/example
) and one for the iOS platform implementation package (flutter_embed_unity/flutter_embed_unity_2022_3_ios/example
).
If you just want to test the example, use the public facing package example.
If you want to do development on the plugin, you should use the platform implementation examples, because this will allow you to more easily edit the source code in Android Studio / xcode etc. with code completion, compiler warnings etc.
- Checkout the repository
- Create a folder called
unityLibrary
at:-
flutter_embed_unity/flutter_embed_unity_2022_3_android/example/android/unityLibrary
for Android or -
flutter_embed_unity/flutter_embed_unity_2022_3_ios/example/ios/unityLibrary
for iOS
-
- Install Unity 2022.3 LTS
- Open the example Unity project
- In Unity, go to
Flutter Embed -> Export project to Flutter app
(iOS or Android), and choose the export folder you created earlier - For iOS: In project navigator, expand the Unity-iPhone project, and select the Data folder. In the Inspector, under Target Membership, change the target membership to UnityFramework. Then select the Unity-iPhone project, then in the editor select the Unity-iPhone project under PROJECTS, then select the Build Settings tab. In the Build Settings tab, find the 'Other linker Flags' setting (you can use the search box to help you find it). Add the following : '-Wl,-U,_FlutterEmbedUnityIos_sendToFlutter'
Unity 2022.3 is now relatively old, and the Android library project which is produced by the Unity 'export as a library' function relies on versions of Gradle, AGP and JDK which are gradually becoming obsolete. Therefore the example project may not build with your version of Android Studio out of the box due to some of the following issues:
- Android Studio 2024 / Ladybug now bundles Java 21 as the built-in JDK
- Flutter by default uses the JDK which is bundled with Android Studio.
- Java 21 requires gradle 8.4 or later
- Later versions of Gradle are more picky about the version of NDK which is used, and Unity 2022.3 by default uses NDK 23.1.7779620 which comes bundled in Unity (see
flutter_embed_unity/example/android/unityLibrary/build.gradle
) - Different versions of Flutter have different expectations on what versions of Gradle and AGP are used (you may notice warnings when compiling)
The solution to what combination of versions you use will depend on what constraints and dependencies you have in your own development environment. The following are some pieces of advice to help you resolve these problems.
The version of com.android.application
in flutter_embed_unity/example/android/settings.gradle
is the version of AGP (Android Gradle Plugin) used by the example project. The version of the distributionUrl
in flutter_embed_unity/example/android/gradle/wrapper/gradle-wrapper.properties
is the version of Gradle used. You can amend these as required. Use the compatibility matrix to figure out which versions of Gradle and AGP are compatible with each other.
The following are the versions of Gradle and AGP which the flutter create
command uses in new projects, for different versions of Flutter. These should be considered the recommended versions to use:
Flutter 3.29.0
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
plugins {
id("com.android.application") version "8.7.0" apply false
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
}
Flutter 3.24.5 & 3.27.4
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
plugins {
id "com.android.application" version "8.1.0" apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}
Flutter 3.22.3 & 3.19.6
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
plugins {
id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}
Flutter 3.16.9
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
ext.kotlin_version = '1.7.10'
plugins {
id "com.android.application" version "7.3.0" apply false
}
You can downgrade later versions of Android Studio to use earlier versions of JDK, which support earlier versions of Gradle and may resolve build errors. For example, Android Studio Ladybug by default uses JDK 21, which will not build the example projects because it requires Gradle 8.4. You can change this to use JDK 17 instead, which still supports the versions of Gradle used in the example project.
- download the latest version of OpenJDK 17.x (on a Mac, it's recommended to download to
/Library/Java/JavaVirtualMachines/
, which is where Android Studio will look for external JDKs) - tell Flutter to use the JDK using
flutter config --jdk-dir
- for example if you have downloaded to/Library/Java/JavaVirtualMachines/
, useflutter config --jdk-dir /Library/Java/JavaVirtualMachines/jdk-17.0.2.jdk/Contents/Home
- set JAVA_HOME to the same location
- open the Android sub-project, go to All Settings -> Build, Execution & Deployment -> Build Tools -> Gradle, change the android Gradle project to use the new Gradle JDK)
Alternatively if you prefer to use JDK 21 with the latest Android Studio, you need to take some steps to get it to work:
- Use versions of flutter which support later versions of Gradle, for example Flutter 3.29, and update
example/android/settings.gradle
andexample/android/gradle/wrapper/gradle-wrapper.properties
to use suitable versions of Gradle and AGP:
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
plugins {
id("com.android.application") version "8.7.0" apply false
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
}
- Set
ndkVersion = "27.0.12077973"
inexample/android/app/build.gradle
- Remove
ndkPath
fromexample/android/app/unityLibrary/build.gradle
which points to the older NDK embedded with Unity and instead setndkVersion = "27.0.12077973"
- Install NDK 27.0.12077973 using Android Studio SDK manager
- Update source compatibility targets in
example/app/android/build.gradle
:
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17
}
- Add
namespace 'com.UnityTechnologies.XR.Manifest'
toexample/app/android/unityLibrary/xrmanifest.androidlib/build.gradle
The examples can now be run. However, any local changes you make to plugin source code will not be picked up by the examples, because they depend on published versions. Therefore if you want to work on the plugin and use the examples to test changes, you need to change the dependencies to local paths.
For Android, change flutter_embed_unity/flutter_embed_unity_2022_3_android/example/pubspec.yaml
:
dependencies:
...
flutter_embed_unity_2022_3_android:
path: ../
flutter_embed_unity:
path: ../../flutter_embed_unity
For iOS, change flutter_embed_unity/flutter_embed_unity_2022_3_ios/example/pubspec.yaml
:
dependencies:
...
flutter_embed_unity_2022_3_ios:
path: ../
flutter_embed_unity:
path: ../../flutter_embed_unity
Now to resolve a dependency conflict with local paths and published versions you also need to change flutter_embed_unity/flutter_embed_unity/pubspec.yaml
:
dependencies:
...
flutter_embed_unity_2022_3_android:
path: ../flutter_embed_unity_2022_3_android
flutter_embed_unity_2022_3_ios:
path: ../flutter_embed_unity_2022_3_ios
Now you should be able to develop the plugin platform source code, and use the platform example projects to test your changes.
On Android Studio, open flutter_embed_unity/flutter_embed_unity_2022_3_android
Flutter project, then open one of the Kotlin files under the android
subfolder, then click on "Open for editing in Android Studio" at the top right (or go to Tools -> Flutter -> Open for editing in Android Studio
). This should open the Android subproject, with the example project also in the source navigator so it can compile correctly.
In Xcode, open flutter_embed_unity/flutter_embed_unity_2022_3_ios/example/ios/Runner.xcworkspace
, then in the project navigator go to Pods/Development Pods/hello/../../example/ios/.symlinks/plugins/flutter_embed_unity
to find the plugin Swift files.
The Android package contains a JAR file in flutter_embed_unity\flutter_embed_unity_2022_3_android\android\libs
containing bits of Unity code for Android such as the UnityPlayer
which basically runs Unity. This was copied from the Unity editor install folder, for example at Unity Editors\2022.3.7f1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Release\Classes
, and renamed to make it clear which version of Unity it is from.
It is included in the Android plugin project via a dependency in flutter_embed_unity\flutter_embed_unity_2022_3_android\android\build.gradle
:
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
To develop for a different version of Unity, make sure to replace this file!
The iOS package contains a framework file at flutter_embed_unity\flutter_embed_unity_2022_3_ios\ios\UnityFramework.framework
, which is required for the plugin to build and for import UnityFramework
to work. Without this you will get No such module UnityFramework
. It was extracted from the
DerivedData
folder after building the launcher Xcode project which Unity exports.
It is included into the iOS plugin build by adding this to flutter_embed_unity_2022_3_ios/ios/flutter_embed_unity_ios.podspec
:
# Add UnityFramework
s.vendored_frameworks = 'UnityFramework.framework'
Then run pod install
from flutter_embed_unity_2022_3_ios/example/iOS
To develop for a different version of Unity, make sure to rebuild UnityFramework!
This is a slight hack borrowed from https://pub.dev/packages/flutter_unity which allows us to easily send messages from Unity to Flutter without having to mess around with manually editing Unity files.
-Wl
allows us to pass additional options to the linker (ld
) when it is invoked-U
tells the linker to force the symbol_FlutterEmbedUnityIos_sendToFlutter
to be entered in the output file as an undefined symbol. It will be linked instead to a C function defined influtter_embed_unity_2022_3_ios/ios/Classes/SendToFlutter.swift
See the linker documentation for more
The following may be useful for plugin developers
- Unity manual: Structure of a Unity Xcode Project
- Unity manual: Structure of an Android project
- https://docs.unity3d.com/2022.3/Documentation/Manual/UnityasaLibrary.html
- Official documentation of integrating Unity into an app
- Old and very out of date but still useful background: https://forum.unity.com/threads/using-unity-as-a-library-in-native-ios-android-apps.685195/
-
UnityPlayerActivity.java
source can be found in the unity install folder, for example:<Unity hub editors install folder>\2022.3.7f1\Editor\Data\PlaybackEngines\AndroidPlayer\Source\com\unity3d\player\UnityPlayerActivity.java