Extending the UnityPlayerActivity on Android
Note: This process is specific to the Android platform and not applicable to other platforms.
You can find the resulting project of this guide here on my Github collection Unity Good Practices.
This project allows you to extend UnityPlayerActivity
in an isolated source-control friendly Android Studio project, without a need to work on the exported Android Studio project of your game. It also removes the need to copy, maintain (and even worse, include) the file classes.jar
from the Unity installation.
Table of contents
Background
On Android, it is possible to extend UnityPlayerActivity
to override existing interactions between Unity and Android OS or introduce new behaviors.
From the Unity documentation:
When you develop a Unity Android application, you can use plug-ins to extend the standard UnityPlayerActivity class (the primary Java class for the Unity Player on Android, similar to AppController.mm on Unity iOS). An application can override all basic interactions between the Android OS and the Unity Android application.
The common methods to extend UnityPlayerActivity are:
-
The suggested method in Unity documentation is to extend UnityPlayerActivity is to open the exported Android project in Android Studio, and do modifications from there. However, this method may introduce friction and difficulties in workflow, such as difficulty in source control of the extension plugin, and maintaining other modules/plugins that you may want to introduce.
-
Another method suggested around the web is to manually copy
classes.jar
from the Unity directory to your working directory. However, this requires including theclasses.jar
file within the plugin, or needs extra effort to exclude it from builds.
On the other hand, with this method, you can have an isolated Android Studio project for your Unity plugin, by referencing the Unity classes without a need to copy and maintain classes.jar
, and keeping the reference import com.unity3d.player.UnityPlayerActivity;
intact.
The whole idea is to mock com.unity3d.player.UnityPlayerActivity;
by including a compile-only module for UnityPlayerActivity
. This way you can work on a fresh isolated Android Studio project as if you are working on an exported Android Studio project.
Guide
You can use the project created with this method as a starting point, or follow this guide to start fresh.
It is suggested create the project from scratch if you are using a significantly newer version of Android Studio, or you would like to keep the references of the tests removed.
This project was created using Android Studio Arctic Fox 2020.3.1.
Android Studio
Create your activity
- In Android Studio create a new project with “No activity”.
- Use package name that matches your Unity project
com.mycompany.myunityproject.player
(e.g.com.awesomegamestudio.veryfungame.player
).
- Use package name that matches your Unity project
- In
AndroidManifest.xml
:- Delete all lines referencing themes and icons:
android:icon=...
android:roundIcon=...
android:theme=...
- Delete all lines referencing themes and icons:
- (Optional) Delete folders
app/src/androidTest
andapp/src/test
. - Delete everything under the folder
res
exceptres/values/strings.xml
. - In
build.gradle
of the module:- Replace
id 'com.android.application'
withid 'com.android.library'
. - Delete line
applicationId "com.mycompany.myunityproject"
. - Delete all lines related to tests.
- Delete all dependencies.
-
Add local Unity installation as a compile-only dependency (so that it is not included in the builds).
dependencies { compileOnly files('C:/Program Files/Unity/Hub/Editor/YOUR_UNITY_VERSION/Editor/Data/PlaybackEngines/AndroidPlayer/Variations/mono/Release/Classes/classes.jar) }
NOTE: Unity version in URLs should match yours. You only need to update this if you need to modify the plugin with a newer Unity installation.
- Replace
Mock Unity activity
- From
File/New/New Module
, create a new module with package namecom.unity3d.player
. - Perform the same steps above (Create your activity) for this module as well (clean-up and adding local Unity dependency).
3.
- Create file
UnityPlayerActivity.java
in/player/java/com/unity3d/player/
. Use simple mock content or copy it from Unity directory.-
Paste the simplified mock content into
UnityPlayerActivity.java
you created:// This is a stripped-off version of the Unity file `UnityPlayerActivity.java`. // Original file is not included to prevent licensing issues. // // If you ever need a specific usage, you can copy the original file from // `C:\Program Files\Unity\Hub\Editor\YOUR_UNITY_VERSION\Editor\Data\PlaybackEngines\AndroidPlayer\src\com\unity3d\player`. package com.unity3d.player; import android.app.Activity; public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents { protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code // When Unity player unloaded move task to background @Override public void onUnityPlayerUnloaded() { } // When Unity player quited kill process @Override public void onUnityPlayerQuitted() { } }
-
Or, in order to access original functionality, or use a more recent version of the file, copy
UnityPlayerActivity.java
fromC:\Program Files\Unity\Hub\Editor\2019..4.33f1\Editor\Data\PlaybackEngines\AndroidPlayer\src\com\unity3d\player\
to/player/java/com/unity3d/player/
.
-
- Create file
-
In
build.gradle
of moduleMyUnityPlayerActivity
add a compile-only dependency to the moduleplayer
we just created.dependencies { compileOnly files('C:/Program Files/Unity/Hub/Editor/YOUR_UNITY_VERSION/Editor/Data/PlaybackEngines/AndroidPlayer/Variations/mono/Release/Classes/classes.jar) compileOnly project(':player') }
NOTE: Unity version in URLs should match yours. You only need to update this if you need to modify the plugin with a newer Unity installation.
Extend Unity activity
-
Create new class
MyUnityPlayerActivity
inapp/java/com.mycompany.myunityproject.player
with this content:package com.mycompany.myunityproject.player; import android.os.Bundle; import android.util.Log; import com.unity3d.player.UnityPlayerActivity; public class MyUnityPlayerActivity extends UnityPlayerActivity { private static final String TAG = "Unity"; // This override is not required for extending the UnityPlayerActivity. // It is included to test configuration on a device. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "Running MyUnityPlayerActivity."); } }
NOTE: Overriding
onCreate()
is only for demo purposes, and not required for extending the Unity activity.
Export plugin from Android Studio
- Select build variant
debug
orrelease
fromBuild/Select Build Variant...
. (Use build variantdebug
to see the logs in logcat.) - In Android Studio
Build/Make
will build.aar
to/app/build/outputs/aar/app-release.aar
.
Unity
Open your Unity project.
Import plugin to Unity
- Copy the
.aar
file built in previous step to Unity project into the folderAssets/Plugins/Android/libs/MyUnityPlayerActivity/
. - Customize Unity AndroidManifest (need to be done only once):
- Enable
Custom Main Manifest
atProject Settings/Player/Publishing Settings/Build
. - Open
Assets/Plugins/Android/AndroidManifest.xml
for editing. Edit activty attribute from<activity android:name="com.unity3d.player.UnityPlayerActivity" ...
to<activity android:name="com.mycompany.myunityproject.player.MyUnityPlayerActivity" ... >
.
- Enable
- If you introduced any non-compile-only dependencies in
build.gradle (app)
of MyUnityPlayerActivity:- Create a file
/Assets/MyUnityPlayerActivity/Editor/MyUnityPlayerActivityDependencies.xml
. -
Declare those dependencies in this file using the format below.
For example, if your
build.gradle (app)
looks like this:dependencies { implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.gms:play-services-auth:19.2.0' //noinspection GradlePath compileOnly files('C:/Program Files/Unity/Hub/Editor/2019.4.33f1/Editor/Data/PlaybackEngines/AndroidPlayer/Variations/mono/Release/Classes/classes.jar') compileOnly project(':player') }
Then your
MyUnityPlayerActivityDependencies.xml
should look like this:<dependencies> <androidPackages> <androidPackage spec="androidx.appcompat:appcompat:1.3.1"/> <androidPackage spec="com.google.android.gms:play-services-auth:19.2.0"/> </androidPackages> </dependencies>
- Use External Dependency Manager for Unity to resolve dependencies.
- Create a file
Run on device
- In Unity, make sure the Android platform is selected in
Build Settings
. - Use
Build Settings/Build And Run
to run the application on a connected Android device. - If you used build variant
debug
while building the plugin in Android Studio, you should see the demo logRunning MyUnityPlayerActivity.
from overriddenonCreate()
inadb logcat
(e.g. by runningadb logcat -s Unity
in command prompt, or by using Android Logcat package in Unity).
Further improvements
- Exporting Android Studio build and copying the built plugin into the Unity project can be automated for even a smoother workflow.